diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..1f5493729 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +src/processor/testdata/*.out text eol=lf diff --git a/.github/mistaken-pull-closer.yml b/.github/mistaken-pull-closer.yml deleted file mode 100644 index 13c8d1b3d..000000000 --- a/.github/mistaken-pull-closer.yml +++ /dev/null @@ -1,17 +0,0 @@ -# The JSONPath filter expression used to identify which PRs to close. -# The data filtered is the pull request data along with other metadata passed in -# by probot. -# See http://goessner.net/articles/JsonPath/ -# `true` will close all PRs. -filters: - - true - -# The message to post to the closed PR. -commentBody: | - Thanks for your contribution! Unfortunately, we don't use GitHub pull - requests to manage code contributions to this repository. Instead, please - see [README.md](../blob/master/README.md) which provides full instructions - on how to get involved. - -# Whether to add a label to the closed PR. -addLabel: false diff --git a/.github/workflows/build-test-ci.yml b/.github/workflows/build-test-ci.yml new file mode 100644 index 000000000..2196d55f5 --- /dev/null +++ b/.github/workflows/build-test-ci.yml @@ -0,0 +1,73 @@ +# GitHub actions workflow. +# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions + +name: Build+Test CI + +on: + push: + branches: [main] + + schedule: + # The GH mirroring from Google GoB does not trigger push actions. + # Fire it every other day to provide some coverage. This will run ~8 AM PT. + - cron: '39 3 */2 * *' + + # Allow for manual triggers from the web. + workflow_dispatch: + +jobs: + autotools: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + cc: gcc + cxx: g++ + - os: ubuntu-latest + cc: clang + cxx: clang++ + - os: macos-latest + cc: clang + cxx: clang++ + runs-on: ${{ matrix.os }} + env: + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + steps: + - name: System settings + run: | + set -x + $CC --version + $CXX --version + getconf _NPROCESSORS_ONLN + getconf _NPROCESSORS_CONF + true + + - name: Checkout depot_tools + run: git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git ../depot_tools + + - name: Checkout breakpad + run: | + set -xe + PATH+=:$PWD/../depot_tools + gclient config --unmanaged --name=src https://github.com/${{ github.repository }} + gclient sync --no-history --nohooks + + # First build & test in-tree. + - run: ./configure --disable-silent-rules + working-directory: src + - run: make -j$(getconf _NPROCESSORS_CONF) + working-directory: src + - run: make -j$(getconf _NPROCESSORS_CONF) check VERBOSE=1 + working-directory: src + - run: make -j$(getconf _NPROCESSORS_CONF) distclean + working-directory: src + + # Then build & test out-of-tree. + - run: mkdir -p src/build/native + - run: ../../configure --disable-silent-rules + working-directory: src/build/native + - run: make -j$(getconf _NPROCESSORS_CONF) distcheck VERBOSE=1 + working-directory: src/build/native diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml new file mode 100644 index 000000000..06f8e2763 --- /dev/null +++ b/.github/workflows/coverity.yml @@ -0,0 +1,43 @@ +# GitHub actions workflow. +# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions + +# https://scan.coverity.com/projects/google-breakpad +name: Coverity Scan + +on: + push: + branches: [main] + + schedule: + # The GH mirroring from Google GoB does not trigger push actions. + # Fire it once a week to provide some coverage. + - cron: '39 2 * * WED' + + # Allow for manual triggers from the web. + workflow_dispatch: + +jobs: + coverity: + runs-on: ubuntu-latest + env: + CC: clang + CXX: clang++ + steps: + - name: Checkout depot_tools + run: git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git ../depot_tools + + - name: Checkout breakpad + run: | + set -xe + PATH+=:$PWD/../depot_tools + gclient config --unmanaged --name=src https://github.com/${{ github.repository }} + gclient sync --no-history --nohooks + + - run: ./configure --disable-silent-rules + working-directory: src + + - uses: vapier/coverity-scan-action@v1 + with: + command: make -C src -O -j$(getconf _NPROCESSORS_CONF) + email: ${{ secrets.COVERITY_SCAN_EMAIL }} + token: ${{ secrets.COVERITY_SCAN_TOKEN }} diff --git a/.gitignore b/.gitignore index d6140d8c1..737bda54b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +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 @@ -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. # @@ -69,7 +69,7 @@ config.h /Makefile stamp-h1 -# Ignore GYP generated Visual Studio artifacts. +# Ignore generated Visual Studio artifacts. *.filters *.sdf *.sln @@ -77,7 +77,7 @@ stamp-h1 *.vcproj *.vcxproj -# Ignore GYP generated Makefiles +# Ignore generated Makefiles src/Makefile *.Makefile *.target.mk @@ -89,4 +89,3 @@ src/Makefile src/testing src/third_party/lss src/third_party/protobuf -src/tools/gyp diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 628362d27..000000000 --- a/.travis.yml +++ /dev/null @@ -1,34 +0,0 @@ -# Travis build integration. -# https://docs.travis-ci.com/ -language: cpp - -sudo: required - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - clang - - gcc-4.8 - - g++-4.8 - -env: - global: - - secure: "FPczJ1u7FWGXOtUVf5AONeexfQDYnKRtuNs3phLwlPPAbgAlIc/WeTRSHC8DAb1T8IyPdN3Zi7cqLz0dvPol0iX1fWSfr8YdtW0ea8nUYH5ldmmp6H75FEUJUcISmYwL4WN7TldC6Hnzrlbw/0xmBH8gtAgddtBXKc9P9SwEZvM4OiFMHbMPwZEhRj+D95rfH12lgh3D16nbXGnx3rSNbHszvIxrU2VvlLo9Aa+hbmVj5CsBiNJjhDS64ie+VMTkuzcWNqLRYaGOCQ8ftKAlj/fjGfoKjPDN9dSJg9gW1FjOMPeQo93qhSc/hCmTq7sWxBJu48telinUgESdE5q/8gRf5J05ImWPntZAkC/wQkA20K7Kp/fH1CRaYXQMWKjts8c6dQZ5R4WxE4WXUo5rz573Ti9uyVTLys9whnzaib3YbqYv04irkhpgzo3rd8PF8SXpgK99ySQCcv/Dh7UQuXPpcaknOk2mBySXjQDgpQHHXDN2uUek1HEo5xit8fQuQw3TdPIZ9ZgzQ/c5/Dx6sLWAGEfVH9MN+hy6AiZnJ1JI+XF82kAf1pnf8WddHtlE7pAdWRFQt0iOj9T9esV1/o0VCJVzJLRdpKecF0sTpJxDuan6cFI0tNCkNjHFA5wJKYAvdOPAmYkqre7aIIqSOKy3Fjh9JP9CBJFy7eals9U=" - -# TODO: Add an OS X config. -matrix: - include: - - os: linux - compiler: gcc - env: USE_CC=gcc-4.8 USE_CXX=g++-4.8 COVERITY_SCAN=true - - os: linux - compiler: clang - -before_install: ./scripts/travis-checkout.sh -script: ./scripts/travis-build.sh - -notifications: - email: - - google-breakpad-dev@googlegroups.com diff --git a/DEPS b/DEPS index 064907ff5..f00f5d246 100644 --- a/DEPS +++ b/DEPS @@ -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. # @@ -36,49 +36,23 @@ deps = { # Testing libraries and utilities. "src/src/testing": "https://github.com/google/googletest.git" + - "@4fe018038f87675c083d0cfb6a6b57c274fb1753", + "@v1.16.0", # Protobuf. "src/src/third_party/protobuf/protobuf": "https://github.com/google/protobuf.git" + "@cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac", - # GYP project generator. - "src/src/tools/gyp": - "https://chromium.googlesource.com/external/gyp/" + - "@324dd166b7c0b39d513026fa52d6280ac6d56770", - # Linux syscall support. "src/src/third_party/lss": "https://chromium.googlesource.com/linux-syscall-support/" + - "@fd00dbbd0c06a309c657d89e9430143b179ff6db", + "@ed31caa60f20a4f6569883b2d752ef7522de51e0", } hooks = [ { # Keep the manifest up to date. - "action": ["python", "src/src/tools/python/deps-to-manifest.py", + "action": ["src/src/tools/python/deps-to-manifest.py", "src/DEPS", "src/default.xml"], }, ] - -hooks_os = { - 'win': [ - { - # TODO(chrisha): Fix the GYP files so that they work without - # --no-circular-check. - "pattern": ".", - "action": ["python", - "src/src/tools/gyp/gyp_main.py", - "--no-circular-check", - "src/src/client/windows/breakpad_client.gyp"], - }, - { - # XXX: this and above should all be wired into build/all.gyp ? - "action": ["python", - "src/src/tools/gyp/gyp_main.py", - "--no-circular-check", - "src/src/tools/windows/tools_windows.gyp"], - }, - ], -} diff --git a/DIR_METADATA b/DIR_METADATA new file mode 100644 index 000000000..bc37756ef --- /dev/null +++ b/DIR_METADATA @@ -0,0 +1,13 @@ +# Metadata information for this directory. +# +# For more information on DIR_METADATA files, see: +# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/README.md +# +# For the schema of this file, see Metadata message: +# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto + +monorail { + project: "google-breakpad" +} + +team_email: "google-breakpad-dev@googlegroups.com" diff --git a/LICENSE b/LICENSE index a840b2647..42af8c10c 100644 --- a/LICENSE +++ b/LICENSE @@ -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 @@ 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. @@ -28,32 +27,50 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------- +License for src/common/convert_UTF.cc, src/common/convert_UTF.h -Copyright 2001-2004 Unicode, Inc. - -Disclaimer +Copyright © 1991-2015 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in +http://www.unicode.org/copyright.html. -This source code is provided as is by Unicode, Inc. No claims are -made as to fitness for any particular purpose. No warranties of any -kind are expressed or implied. The recipient agrees to determine -applicability of information provided. If this file has been -purchased on magnetic or optical media from Unicode, Inc., the -sole remedy for any claim will be exchange of defective media -within 90 days of receipt. +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, +(b) this copyright and permission notice appear in associated +documentation, and +(c) there is clear notice in each modified Data File or in the Software +as well as in the documentation associated with the Data File(s) or +Software that the data or software has been modified. -Limitations on Rights to Redistribute This Code +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. -Unicode, Inc. hereby grants the right to freely use the information -supplied in this file in the creation of products supporting the -Unicode Standard, and to make copies of this file in any form -for internal or external distribution as long as this notice -remains attached. +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. -------------------------------------------------------------------- +License for src/common/linux/breakpad_getcontext.S libunwind - a platform-independent unwind library Copyright (C) 2008 Google, Inc - Contributed by Paul Pluzhnikov + Contributed by Paul Pluzhnikov Copyright (C) 2010 Konstantin Belousov Permission is hereby granted, free of charge, to any person obtaining @@ -76,29 +93,270 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -------------------------------------------------------------------- +License for +src/client/mac/handler/breakpad_nlist_64.cc +src/third_party/mac_headers/architecture/byte_order.h +src/third_party/mac_headers/mach-o/arch.h +src/third_party/mac_headers/mach-o/fat.h: +src/third_party/mac_headers/mach-o/loader.h +src/third_party/mac_headers/mach-o/nlist.h -Copyright (c) 1999 Apple Computer, Inc. All rights reserved. +APPLE PUBLIC SOURCE LICENSE -@APPLE_LICENSE_HEADER_START@ +Version 2.0 - August 6, 2003 -This file contains Original Code and/or Modifications of Original Code -as defined in and that are subject to the Apple Public Source License -Version 2.0 (the 'License'). You may not use this file except in -compliance with the License. Please obtain a copy of the License at -http://www.opensource.apple.com/apsl/ and read it before using this -file. +Please read this License carefully before downloading this software. By +downloading or using this software, you are agreeing to be bound by the terms +of this License. If you do not or cannot agree to the terms of this License, +please do not download or use the software. -The Original Code and all software distributed under the License are -distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER -EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. -Please see the License for the specific language governing rights and -limitations under the License. +Apple Note: In January 2007, Apple changed its corporate name from "Apple +Computer, Inc." to "Apple Inc." This change has been reflected below and +copyright years updated, but no other changes have been made to the APSL 2.0. + +1. General; Definitions. This License applies to any program or other work which Apple Inc. ("Apple") makes publicly available and which contains a notice placed by Apple identifying such program or work as "Original Code" and stating that it is subject to the terms of this Apple Public Source License version 2.0 ("License"). As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is the +grantor of rights, (i) claims of patents that are now or hereafter acquired, +owned by or assigned to Apple and (ii) that cover subject matter contained in +the Original Code, but only to the extent necessary to use, reproduce and/or +distribute the Original Code without infringement; and (b) in the case where +You are the grantor of rights, (i) claims of patents that are now or hereafter +acquired, owned by or assigned to You and (ii) that cover subject matter in +Your Modifications, taken alone or in combination with Original Code. + +1.2 "Contributor" means any person or entity that creates or contributes to +the creation of Modifications. + +1.3 "Covered Code" means the Original Code, Modifications, the combination of +Original Code and any Modifications, and/or any respective portions thereof. + +1.4 "Externally Deploy" means: (a) to sublicense, distribute or otherwise make +Covered Code available, directly or indirectly, to anyone other than You; +and/or (b) to use Covered Code, alone or as part of a Larger Work, in any way +to provide a service, including but not limited to delivery of content, +through electronic communication with a client other than You. + +1.5 "Larger Work" means a work which combines Covered Code or portions thereof +with code not governed by the terms of this License. + +1.6 "Modifications" mean any addition to, deletion from, and/or change to, the +substance and/or structure of the Original Code, any previous Modifications, +the combination of Original Code and any previous Modifications, and/or any +respective portions thereof. When code is released as a series of files, a +Modification is: (a) any addition to or deletion from the contents of a file +containing Covered Code; and/or (b) any new file or other representation of +computer program statements that contains any part of Covered Code. + +1.7 "Original Code" means (a) the Source Code of a program or other work as +originally made available by Apple under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Apple under this License, and that has been expressly identified by Apple as +such in the header file(s) of such work; and (b) the object code compiled from +such Source Code and originally made available by Apple under this License + +1.8 "Source Code" means the human readable form of a program or other work +that is suitable for making modifications to it, including all modules it +contains, plus any associated interface definition files, scripts used to +control compilation and installation of an executable (object code). + +1.9 "You" or "Your" means an individual or a legal entity exercising rights +under this License. For legal entities, "You" or "Your" includes any entity +which controls, is controlled by, or is under common control with, You, where +"control" means (a) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (b) ownership +of fifty percent (50%) or more of the outstanding shares or beneficial +ownership of such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and conditions of this License, Apple hereby grants You, effective on the date You accept this License and download the Original Code, a world-wide, royalty-free, non-exclusive license, to the extent of Apple's Applicable Patent Rights and copyrights covering the Original Code, to do the following: + +2.1 Unmodified Code. You may use, reproduce, display, perform, internally +distribute within Your organization, and Externally Deploy verbatim, +unmodified copies of the Original Code, for commercial or non-commercial +purposes, provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the copyright +and other proprietary notices and disclaimers of Apple as they appear in the +Original Code, and keep intact all notices in the Original Code that refer to +this License; and + +(b) You must include a copy of this License with every copy of Source Code of +Covered Code and documentation You distribute or Externally Deploy, and You +may not offer or impose any terms on such Source Code that alter or restrict +this License or the recipients' rights hereunder, except as permitted +under Section 6. + +2.2 Modified Code. You may modify Covered Code and use, reproduce, display, +perform, internally distribute within Your organization, and Externally Deploy +Your Modifications and Covered Code, for commercial or non-commercial +purposes, provided that in each instance You also meet all of these +conditions: + +(a) You must satisfy all the conditions of Section 2.1 with respect to the +Source Code of the Covered Code; + +(b) You must duplicate, to the extent it does not already exist, the notice in +Exhibit A in each file of the Source Code of all Your Modifications, and cause +the modified files to carry prominent notices stating that You changed the +files and the date of any change; and + +(c) If You Externally Deploy Your Modifications, You must make Source Code of +all Your Externally Deployed Modifications either available to those to whom +You have Externally Deployed Your Modifications, or publicly available. Source +Code of Your Externally Deployed Modifications must be released under the +terms set forth in this License, including the license grants set forth in +Section 3 below, for as long as you Externally Deploy the Covered Code or +twelve (12) months from the date of initial External Deployment, whichever is +longer. You should preferably distribute the Source Code of Your Externally +Deployed Modifications electronically (e.g. download from a web site). + +2.3 Distribution of Executable Versions. In addition, if You Externally Deploy +Covered Code (Original Code and/or Modifications) in object code, executable +form only, You must include a prominent notice, in the code itself as well as +in related documentation, stating that Source Code of the Covered Code is +available under the terms of this License with information on how and where to +obtain such Source Code. + +2.4 Third Party Rights. You expressly acknowledge and agree that although +Apple and each Contributor grants the licenses to their respective portions of +the Covered Code set forth herein, no assurances are provided by Apple or any +Contributor that the Covered Code does not infringe the patent or other +intellectual property rights of any other entity. Apple and each Contributor +disclaim any liability to You for claims brought by any other entity based on +infringement of intellectual property rights or otherwise. As a condition to +exercising the rights and licenses granted hereunder, You hereby assume sole +responsibility to secure any other intellectual property rights needed, if +any. For example, if a third party patent license is required to allow You to +distribute the Covered Code, it is Your responsibility to acquire that license +before distributing the Covered Code. + +3. Your Grants. In consideration of, and as a condition to, the licenses granted to You under this License, You hereby grant to any person or entity receiving or distributing Covered Code under this License a non-exclusive, royalty-free, perpetual, irrevocable license, under Your Applicable Patent Rights and other intellectual property rights (other than patent) owned or controlled by You, to use, reproduce, display, perform, modify, sublicense, distribute and Externally Deploy Your Modifications of the same scope and extent as Apple's licenses under Sections 2.1 and 2.2 above. + +4. Larger Works. You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In each such instance, You must make sure the requirements of this License are fulfilled for the Covered Code or any portion thereof. -@APPLE_LICENSE_HEADER_END@ +5. Limitations on Patent License. Except as expressly stated in Section 2, no other patent rights, express or implied, are granted by Apple herein. Modifications and/or Larger Works may require additional patent licenses from Apple which Apple may grant in its sole discretion. + +6. Additional Terms. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations and/or other rights consistent with the scope of the license granted herein ("Additional Terms") to one or more recipients of Covered Code. However, You may do so only on Your own behalf and as Your sole responsibility, and not on behalf of Apple or any Contributor. You must obtain the recipient's agreement that any such Additional Terms are offered by You alone, and You hereby agree to indemnify, defend and hold Apple and every Contributor harmless for any liability incurred by or claims asserted against Apple or such Contributor by reason of any such Additional Terms. + +7. Versions of the License. Apple may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Once Original Code has been published under a particular version of this License, You may continue to use it under the terms of that version. You may also choose to use such Original Code under the terms of any subsequent version of this License published by Apple. No one other than Apple has the right to modify the terms applicable to Covered Code created under this License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in part pre-release, untested, or not fully tested works. The Covered Code may contain errors that could cause failures or loss of data, and may be incomplete or contain inaccuracies. You expressly acknowledge and agree that use of the Covered Code, or any portion thereof, is at Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You acknowledge that the Covered Code is not intended for use in the operation of nuclear facilities, aircraft navigation, communication systems, or air traffic control machines in which case the failure of the Covered Code could lead to death, personal injury, or severe physical or environmental damage. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event shall Apple's total liability to You for all damages (other than as may be required by applicable law) under this License exceed the amount of fifty dollars ($50.00). + +10. Trademarks. This License does not grant any rights to use the trademarks or trade names "Apple", "Mac", "Mac OS", "QuickTime", "QuickTime Streaming Server" or any other trademarks, service marks, logos or trade names belonging to Apple (collectively "Apple Marks") or to any trademark, service mark, logo or trade name belonging to any Contributor. You agree not to use any Apple Marks in or as part of the name of products derived from the Original Code or to endorse or promote products derived from the Original Code other than as expressly permitted by and in strict compliance at all times with Apple's third party trademark usage guidelines which are posted at http://www.apple.com/legal/guidelinesfor3rdparties.html. + +11. Ownership. Subject to the licenses granted under this License, each Contributor retains all rights, title and interest in and to any Modifications made by such Contributor. Apple retains all rights, title and interest in and to the Original Code and any Modifications made by or on behalf of Apple ("Apple Modifications"), and such Apple Modifications will not be automatically subject to this License. Apple may, at its sole discretion, choose to license such Apple Modifications under this License, or on different terms from those contained in this License or may choose not to license them at all. + +12. Termination. + +12.1 Termination. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Apple if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of +becoming aware of such breach; + +(b) immediately in the event of the circumstances described in Section +13.5(b); or + +(c) automatically without notice from Apple if You, at any time during the +term of this License, commence an action for patent infringement against +Apple; provided that Apple did not first commence an action for patent +infringement against You in that instance. + +12.2 Effect of Termination. Upon termination, You agree to immediately stop +any further use, reproduction, modification, sublicensing and distribution of +the Covered Code. All sublicenses to the Covered Code which have been properly +granted prior to termination shall survive any termination of this License. +Provisions which, by their nature, should remain in effect beyond the +termination of this License shall survive, including but not limited to +Sections 3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other +for compensation, indemnity or damages of any sort solely as a result of +terminating this License in accordance with its terms, and termination of this +License will be without prejudice to any other right or remedy of any party. + +13. Miscellaneous. + +13.1 Government End Users. The Covered Code is a "commercial item" as defined +in FAR 2.101. Government software and technical data rights in the Covered +Code include only those rights customarily provided to the public as defined +in this License. This customary commercial license in technical data and +software is provided in accordance with FAR 12.211 (Technical Data) and 12.212 +(Computer Software) and, for Department of Defense purchases, DFAR +252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3 (Rights in +Commercial Computer Software or Computer Software Documentation). Accordingly, +all U.S. Government End Users acquire Covered Code with only those rights set +forth herein. + +13.2 Relationship of Parties. This License will not be construed as creating +an agency, partnership, joint venture or any other form of legal association +between or among You, Apple or any Contributor, and You will not represent to +the contrary, whether expressly, by implication, appearance or otherwise. + +13.3 Independent Development. Nothing in this License will impair Apple's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions +as, or otherwise compete with, Modifications, Larger Works, technology or +products that You may develop, produce, market or distribute. + +13.4 Waiver; Construction. Failure by Apple or any Contributor to enforce any +provision of this License will not be deemed a waiver of future enforcement of +that or any other provision. Any law or regulation which provides that the +language of a contract shall be construed against the drafter will not apply +to this License. + +13.5 Severability. (a) If for any reason a court of competent jurisdiction +finds any provision of this License, or portion thereof, to be unenforceable, +that provision of the License will be enforced to the maximum extent +permissible so as to effect the economic benefits and intent of the parties, +and the remainder of this License will continue in full force and effect. (b) +Notwithstanding the foregoing, if applicable law prohibits or restricts You +from fully and/or specifically complying with Sections 2 and/or 3 or prevents +the enforceability of either of those Sections, this License will immediately +terminate and You must immediately discontinue any use of the Covered Code and +destroy all copies of it that are in your possession or control. + +13.6 Dispute Resolution. Any litigation or other dispute resolution between +You and Apple relating to this License shall take place in the Northern +District of California, and You and Apple hereby consent to the personal +jurisdiction of, and venue in, the state and federal courts within that +District with respect to this License. The application of the United Nations +Convention on Contracts for the International Sale of Goods is expressly +excluded. + +13.7 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +California, except that body of California law concerning conflicts of law. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this License +and all related documents be drafted in English. Les parties ont exigé que le +présent contrat et tous les documents connexes soient rédigés en anglais. + +EXHIBIT A. + +"Portions Copyright (c) 1999-2007 Apple Inc. All Rights Reserved. + +This file contains Original Code and/or Modifications of Original Code as +defined in and that are subject to the Apple Public Source License Version 2.0 +(the 'License'). You may not use this file except in compliance with +the License. Please obtain a copy of the License at +http://www.opensource.apple.com/apsl/ and read it before using this file. + +The Original Code and all software distributed under the License are +distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the +License for the specific language governing rights and limitations under the +License." -------------------------------------------------------------------- +License for +src/client/mac/handler/breakpad_nlist_64.cc +src/third_party/mac_headers/mach-o/nlist.h Copyright (c) 1989, 1993 The Regents of the University of California. All rights reserved. @@ -130,3 +388,681 @@ 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. + +-------------------------------------------------------------------- +License for +src/third_party/curl/curl.h +src/third_party/curl/curlbuild.h +src/third_party/curl/curlrules.h +src/third_party/curl/curlver.h +src/third_party/curl/easy.h +src/third_party/curl/mprintf.h +src/third_party/curl/multi.h +src/third_party/curl/stdcheaders.h +src/third_party/curl/typecheck-gcc.h + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1996 - 2011, Daniel Stenberg, . + +All rights reserved. + +Permission to use, copy, modify, and distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright +notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall not +be used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization of the copyright holder. + +-------------------------------------------------------------------- +License for +src/common/mac/GTMDefines.h +src/common/mac/GTMLogger.h +src/common/mac/GTMLogger.m +src/common/mac/testing/GTMSenTestCase.h +src/common/mac/testing/GTMSenTestCase.m + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the +copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other +entities that control, are controlled by, or are under common control with +that entity. For the purposes of this definition, "control" means (i) the +power, direct or indirect, to cause the direction or management of such +entity, whether by contract or otherwise, or (ii) ownership of fifty percent +(50%) or more of the outstanding shares, or (iii) beneficial ownership of such +entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, and +configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object +code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that is +included in or attached to the work (an example is provided in the Appendix +below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative +Works shall not include works that remain separable from, or merely link (or +bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor for +inclusion in the Work by the copyright owner or by an individual or Legal +Entity authorized to submit on behalf of the copyright owner. For the purposes +of this definition, "submitted" means any form of electronic, verbal, or +written communication sent to the Licensor or its representatives, including +but not limited to communication on electronic mailing lists, source code +control systems, and issue tracking systems that are managed by, or on behalf +of, the Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise designated +in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +(a) You must give any other recipients of the Work or Derivative Works a copy +of this License; and + +(b) You must cause any modified files to carry prominent notices stating that +You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works that You +distribute, all copyright, patent, trademark, and attribution notices from the +Source form of the Work, excluding those notices that do not pertain to any +part of the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its distribution, +then any Derivative Works that You distribute must include a readable copy of +the attribution notices contained within such NOTICE file, excluding those +notices that do not pertain to any part of the Derivative Works, in at least +one of the following places: within a NOTICE text file distributed as part of +the Derivative Works; within the Source form or documentation, if provided +along with the Derivative Works; or, within a display generated by the +Derivative Works, if and wherever such third-party notices normally appear. +The contents of the NOTICE file are for informational purposes only and do not +modify the License. You may add Your own attribution notices within Derivative +Works that You distribute, alongside or as an addendum to the NOTICE text from +the Work, provided that such additional attribution notices cannot be +construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a +whole, provided Your use, reproduction, and distribution of the Work otherwise +complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +-------------------------------------------------------------------- +License for INSTALL + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. + +-------------------------------------------------------------------- +License for src/common/mac/testing/GTMSenTestCase.h + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. 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 + +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 HOLDER 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. + +-------------------------------------------------------------------- +License for src/third_party//libdisasm + + The "Clarified Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder as specified below. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Distribution fee" is a fee you charge for providing a copy of this + Package to another party. + + "Freely Available" means that no fee is charged for the right to use + the item, though there may be fees involved in handling the item. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain, or those made Freely Available, or from +the Copyright Holder. A Package modified in such a way shall still be +considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site allowing unrestricted access to them, or by allowing the Copyright + Holder to include your modifications in the Standard Version of the + Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + + e) permit and encourge anyone who receives a copy of the modified Package + permission to make your modifications Freely Available in some specific + way. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) give non-standard executables non-standard names, and clearly + document the differences in manual pages (or equivalent), together + with instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + + e) offer the machine-readable source of the Package, with your + modifications, by mail order. + +5. You may charge a distribution fee for any distribution of this Package. +If you offer support for this Package, you may charge any fee you choose +for that support. You may not charge a license fee for the right to use +this Package itself. You may distribute this Package in aggregate with +other (possibly commercial and possibly nonfree) programs as part of a +larger (possibly commercial and possibly nonfree) software distribution, +and charge license fees for other parts of that software distribution, +provided that you do not advertise this Package as a product of your own. +If the Package includes an interpreter, You may embed this Package's +interpreter within an executable of yours (by linking); this shall be +construed as a mere form of aggregation, provided that the complete +Standard Version of the interpreter is so embedded. + +6. The scripts and library files supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whoever generated +them, and may be sold commercially, and may be aggregated with this +Package. If such scripts or library files are aggregated with this +Package via the so-called "undump" or "unexec" methods of producing a +binary executable image, then distribution of such an image shall +neither be construed as a distribution of this Package nor shall it +fall under the restrictions of Paragraphs 3 and 4, provided that you do +not represent such an executable image as a Standard Version of this +Package. + +7. C subroutines (or comparably compiled subroutines in other +languages) supplied by you and linked into this Package in order to +emulate subroutines and variables of the language defined by this +Package shall not be considered part of this Package, but are the +equivalent of input as in Paragraph 6, provided these subroutines do +not change the language in any way that would cause it to fail the +regression tests for the language. + +8. Aggregation of the Standard Version of the Package with a commercial +distribution is always permitted provided that the use of this Package is +embedded; that is, when no overt attempt is made to make this Package's +interfaces visible to the end user of the commercial distribution. +Such use shall not be construed as a distribution of this Package. + +9. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End + +-------------------------------------------------------------------- +License for Autotools + +AUTOCONF CONFIGURE SCRIPT EXCEPTION + +Version 3.0, 18 August 2009 + +Copyright © 2009 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +This Exception is an additional permission under section 7 of the GNU General +Public License, version 3 ("GPLv3"). It applies to a given file that bears a +notice placed by the copyright holder of the file stating that the file is +governed by GPLv3 along with this Exception. + +The purpose of this Exception is to allow distribution of Autoconf's +typical output under terms of the recipient's choice (including +proprietary). + +0. Definitions. +"Covered Code" is the source or object code of a version of Autoconf that is a +covered work under this License. + +"Normally Copied Code" for a version of Autoconf means all parts of its +Covered Code which that version can copy from its code (i.e., not from its +input file) into its minimally verbose, non-debugging and non-tracing output. + +"Ineligible Code" is Covered Code that is not Normally Copied Code. + +1. Grant of Additional Permission. +You have permission to propagate output of Autoconf, even if such propagation +would otherwise violate the terms of GPLv3. However, if by modifying Autoconf +you cause any Ineligible Code of the version you received to become Normally +Copied Code of your modified version, then you void this Exception for the +resulting covered work. If you convey that resulting covered work, you must +remove this Exception in accordance with the second paragraph of Section 7 of +GPLv3. + +2. No Weakening of Autoconf Copyleft. +The availability of this Exception does not imply any general presumption that +third-party software is unaffected by the copyleft requirements of the license +of Autoconf. + +-------------------------------------------------------------------- +License for Autotools + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +Autoconf Exception + +As a special exception, the Free Software Foundation gives unlimited +permission to copy, distribute and modify the configure scripts that are the +output of Autoconf. You need not follow the terms of the GNU General Public +License when using or distributing such scripts, even though portions of the +text of Autoconf appear in them. The GNU General Public License (GPL) does +govern all other use of the material that constitutes the Autoconf program. + +Certain portions of the Autoconf source text are designed to be copied (in +certain cases, depending on the input) into the output of Autoconf. We call +these the "data" portions. The rest of the Autoconf source text consists of +comments plus executable code that decides which of the data portions to +output in any given case. We call these comments and executable code the "non- +data" portions. Autoconf never copies any of the non-data portions into its +output. + +This special exception to the GPL applies to versions of Autoconf released by +the Free Software Foundation. When you make and distribute a modified version +of Autoconf, you may extend this special exception to the GPL to apply to your +modified version as well, *unless* your modified version has the potential to +copy into its output some of the text that was the non-data portion of the +version that you started with. (In other words, unless your change moves or +copies text from the non-data portions to the data portions.) If your +modification has such potential, you must delete any notice of this special +exception to the GPL from your modified version. + + diff --git a/Makefile.am b/Makefile.am index ee7454e4e..06f34ce84 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,6 @@ ## Process this file with automake to produce Makefile.in -# 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. # @@ -119,6 +118,22 @@ TEST_LIBS = src/testing/libtesting.a TEST_DEPS = $(TEST_LIBS) endif + +## Setup test driver +if ANDROID_HOST +# Since Autotools 1.2, tests are run through a special "test driver" script. +# Unfortunately, it's not possible anymore to specify an alternative shell to +# run them on connected devices, so use a slightly modified version of the +# driver for Android. +LOG_DRIVER = $(top_srcdir)/android/test-driver +else +if TESTS_AS_ROOT +LOG_DRIVER = $(top_srcdir)/autotools/root-test-driver $(top_srcdir)/autotools/test-driver +else +LOG_DRIVER = $(top_srcdir)/autotools/test-driver +endif !TESTS_AS_ROOT +endif !ANDROID_HOST + ## Libraries check_LIBRARIES = noinst_LIBRARIES = @@ -126,12 +141,16 @@ lib_LIBRARIES = libexec_PROGRAMS = bin_PROGRAMS = check_PROGRAMS = +noinst_PROGRAMS = +noinst_SCRIPTS = EXTRA_PROGRAMS = CLEANFILES = -check_LIBRARIES += src/testing/libtesting.a - +# +# Tests helper library +# if !SYSTEM_TEST_LIBS +check_LIBRARIES += src/testing/libtesting.a src_testing_libtesting_a_SOURCES = \ src/breakpad_googletest_includes.h \ src/testing/googletest/src/gtest-all.cc \ @@ -141,59 +160,175 @@ src_testing_libtesting_a_CPPFLAGS = \ $(AM_CPPFLAGS) $(TEST_CFLAGS) endif +# +# General +# Not specific to processor, client or tools +# + +check_PROGRAMS += src/common/safe_math_unittest + + +# +# Breakpad minidump and microdump +# processor library, tools and tests +# if !DISABLE_PROCESSOR + lib_LIBRARIES += src/libbreakpad.a pkgconfig_DATA += breakpad.pc noinst_LIBRARIES += src/third_party/libdisasm/libdisasm.a -endif +## Programs +bin_PROGRAMS += \ + src/processor/microdump_stackwalk \ + src/processor/minidump_dump \ + src/processor/minidump_stackwalk + +## Tests (binaries) +check_PROGRAMS += \ + src/common/test_assembler_unittest \ + src/common/dwarf/dwarf2reader_lineinfo_unittest \ + src/common/dwarf/dwarf2reader_splitfunctions_unittest \ + src/processor/address_map_unittest \ + src/processor/basic_source_line_resolver_unittest \ + src/processor/cfi_frame_info_unittest \ + src/processor/contained_range_map_unittest \ + src/processor/disassembler_x86_unittest \ + src/processor/exploitability_unittest \ + src/processor/fast_source_line_resolver_unittest \ + src/processor/map_serializers_unittest \ + src/processor/microdump_processor_unittest \ + src/processor/minidump_processor_unittest \ + src/processor/minidump_unittest \ + src/processor/static_address_map_unittest \ + src/processor/static_contained_range_map_unittest \ + src/processor/static_map_unittest \ + src/processor/static_range_map_unittest \ + src/processor/pathname_stripper_unittest \ + src/processor/postfix_evaluator_unittest \ + src/processor/proc_maps_linux_unittest \ + src/processor/range_map_truncate_lower_unittest \ + src/processor/range_map_truncate_upper_unittest \ + src/processor/range_map_unittest \ + src/processor/stackwalker_amd64_unittest \ + src/processor/stackwalker_arm_unittest \ + src/processor/stackwalker_arm64_unittest \ + src/processor/stackwalker_address_list_unittest \ + src/processor/stackwalker_mips_unittest \ + src/processor/stackwalker_mips64_unittest \ + src/processor/stackwalker_riscv_unittest \ + src/processor/stackwalker_riscv64_unittest \ + src/processor/stackwalker_x86_unittest \ + src/processor/synth_minidump_unittest if LINUX_HOST +check_PROGRAMS += \ + src/processor/disassembler_objdump_unittest \ + src/common/linux/scoped_pipe_unittest \ + src/common/linux/scoped_tmpfile_unittest +endif LINUX_HOST +if SELFTEST +check_PROGRAMS += \ + src/processor/stackwalker_selftest +endif SELFTEST + +## Tests (scripts) +check_SCRIPTS = \ + src/processor/microdump_stackwalk_test \ + src/processor/microdump_stackwalk_machine_readable_test \ + src/processor/minidump_dump_test \ + src/processor/minidump_stackwalk_test \ + src/processor/minidump_stackwalk_machine_readable_test + +endif !DISABLE_PROCESSOR + + +# +# Breakpad client library and tests +# +# Currently Linux only, the macOS client +# is built using an Xcode project instead. +# +if LINUX_HOST + lib_LIBRARIES += src/client/linux/libbreakpad_client.a pkgconfig_DATA += breakpad-client.pc -src_client_linux_libbreakpad_client_a_SOURCES = \ - src/client/linux/crash_generation/crash_generation_client.cc \ - src/client/linux/crash_generation/crash_generation_server.cc \ - src/client/linux/dump_writer_common/thread_info.cc \ - src/client/linux/dump_writer_common/ucontext_reader.cc \ - src/client/linux/handler/exception_handler.cc \ - src/client/linux/handler/exception_handler.h \ - src/client/linux/handler/minidump_descriptor.cc \ - src/client/linux/handler/minidump_descriptor.h \ - src/client/linux/log/log.cc \ - src/client/linux/log/log.h \ - src/client/linux/microdump_writer/microdump_writer.cc \ - src/client/linux/microdump_writer/microdump_writer.h \ - src/client/linux/minidump_writer/linux_core_dumper.cc \ - src/client/linux/minidump_writer/linux_dumper.cc \ - src/client/linux/minidump_writer/linux_ptrace_dumper.cc \ - src/client/linux/minidump_writer/minidump_writer.cc \ - src/client/minidump_file_writer-inl.h \ - src/client/minidump_file_writer.cc \ - src/client/minidump_file_writer.h \ - src/common/convert_UTF.cc \ - src/common/convert_UTF.h \ - src/common/md5.cc \ - src/common/md5.h \ - src/common/string_conversion.cc \ - src/common/string_conversion.h \ - src/common/linux/elf_core_dump.cc \ - src/common/linux/elfutils.cc \ - src/common/linux/elfutils.h \ - src/common/linux/file_id.cc \ - src/common/linux/file_id.h \ - src/common/linux/guid_creator.cc \ - src/common/linux/guid_creator.h \ - src/common/linux/linux_libc_support.cc \ - src/common/linux/memory_mapped_file.cc \ - src/common/linux/safe_readlink.cc -if !HAVE_GETCONTEXT -src_client_linux_libbreakpad_client_a_SOURCES += \ - src/common/linux/breakpad_getcontext.S +check_PROGRAMS += \ + src/client/linux/linux_client_unittest \ + src/common/linux/google_crashdump_uploader_test + +EXTRA_PROGRAMS += \ + src/client/linux/linux_dumper_unittest_helper \ + src/client/linux/linux_client_unittest_shlib + +CLEANFILES += \ + src/client/linux/linux_dumper_unittest_helper \ + src/client/linux/linux_client_unittest_shlib + +endif LINUX_HOST + + +# +# Various Breakpad tools +# This includes symbol dumpers and uploaders +# +if !DISABLE_TOOLS + +if LINUX_HOST + +bin_PROGRAMS += \ + src/tools/linux/core2md/core2md \ + src/tools/linux/pid2md/pid2md \ + src/tools/linux/dump_syms/dump_syms \ + src/tools/linux/md2core/minidump-2-core \ + src/tools/linux/symupload/minidump_upload \ + src/tools/linux/symupload/sym_upload +if X86_HOST +bin_PROGRAMS += \ + src/tools/mac/dump_syms/dump_syms_mac +endif +if HAVE_MEMFD_CREATE +libexec_PROGRAMS += \ + src/tools/linux/core_handler/core_handler +endif + +check_PROGRAMS += \ + src/common/dumper_unittest \ + src/tools/linux/md2core/minidump_2_core_unittest +if X86_HOST +check_PROGRAMS += \ + src/common/mac/macho_reader_unittest endif + endif LINUX_HOST -if !DISABLE_PROCESSOR +endif !DISABLE_TOOLS + +TESTS = $(check_PROGRAMS) $(check_SCRIPTS) + +## Non-installables +noinst_SCRIPTS += $(check_SCRIPTS) + + +## Target definitions + +# All targets that were defined above should now be +# declared below. This should be done unconditionally +# so DO NOT wrap them in conditions! +# Execept for conditionally adding a specific file or +# flag that should only be added for a specific arch, +# system, etc. + +src_common_safe_math_unittest_SOURCES = \ + src/common/safe_math.h \ + src/common/safe_math_unittest.cc +src_common_safe_math_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_common_safe_math_unittest_LDADD = \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +# Breakpad processor library src_libbreakpad_a_SOURCES = \ src/google_breakpad/common/breakpad_types.h \ src/google_breakpad/common/minidump_format.h \ @@ -295,6 +430,10 @@ src_libbreakpad_a_SOURCES = \ src/processor/stackwalker_ppc.h \ src/processor/stackwalker_ppc64.cc \ src/processor/stackwalker_ppc64.h \ + src/processor/stackwalker_riscv.cc \ + src/processor/stackwalker_riscv.h \ + src/processor/stackwalker_riscv64.cc \ + src/processor/stackwalker_riscv64.h \ src/processor/stackwalker_sparc.cc \ src/processor/stackwalker_sparc.h \ src/processor/stackwalker_x86.cc \ @@ -313,7 +452,17 @@ src_libbreakpad_a_SOURCES = \ src/processor/symbolic_constants_win.h \ src/processor/tokenize.cc \ src/processor/tokenize.h +if LINUX_HOST +src_libbreakpad_a_SOURCES += \ + src/common/linux/scoped_pipe.h \ + src/common/linux/scoped_pipe.cc \ + src/common/linux/scoped_tmpfile.h \ + src/common/linux/scoped_tmpfile.cc \ + src/processor/disassembler_objdump.h \ + src/processor/disassembler_objdump.cc +endif +# libdisasm 3rd party library src_third_party_libdisasm_libdisasm_a_SOURCES = \ src/third_party/libdisasm/ia32_implicit.c \ src/third_party/libdisasm/ia32_implicit.h \ @@ -342,131 +491,50 @@ src_third_party_libdisasm_libdisasm_a_SOURCES = \ src/third_party/libdisasm/x86_operand_list.c \ src/third_party/libdisasm/x86_operand_list.h -## Programs -bin_PROGRAMS += \ - src/processor/microdump_stackwalk \ - src/processor/minidump_dump \ - src/processor/minidump_stackwalk -endif !DISABLE_PROCESSOR - -if LINUX_HOST -EXTRA_PROGRAMS += \ - src/client/linux/linux_dumper_unittest_helper -CLEANFILES += \ - src/client/linux/linux_dumper_unittest_helper - -if !DISABLE_TOOLS -bin_PROGRAMS += \ - src/tools/linux/core2md/core2md \ - src/tools/linux/pid2md/pid2md \ - src/tools/linux/dump_syms/dump_syms \ - src/tools/linux/md2core/minidump-2-core \ - src/tools/linux/symupload/minidump_upload \ - src/tools/linux/symupload/sym_upload -if X86_HOST -bin_PROGRAMS += \ - src/tools/mac/dump_syms/dump_syms_mac -endif -if HAVE_MEMFD_CREATE -libexec_PROGRAMS += \ - src/tools/linux/core_handler/core_handler -endif -endif -endif LINUX_HOST - - -## Tests -if !DISABLE_PROCESSOR -check_PROGRAMS += \ - src/common/test_assembler_unittest \ - src/common/dwarf/dwarf2reader_lineinfo_unittest \ - src/common/dwarf/dwarf2reader_splitfunctions_unittest \ - src/processor/address_map_unittest \ - src/processor/basic_source_line_resolver_unittest \ - src/processor/cfi_frame_info_unittest \ - src/processor/contained_range_map_unittest \ - src/processor/disassembler_x86_unittest \ - src/processor/exploitability_unittest \ - src/processor/fast_source_line_resolver_unittest \ - src/processor/map_serializers_unittest \ - src/processor/microdump_processor_unittest \ - src/processor/minidump_processor_unittest \ - src/processor/minidump_unittest \ - src/processor/static_address_map_unittest \ - src/processor/static_contained_range_map_unittest \ - src/processor/static_map_unittest \ - src/processor/static_range_map_unittest \ - src/processor/pathname_stripper_unittest \ - src/processor/postfix_evaluator_unittest \ - src/processor/proc_maps_linux_unittest \ - src/processor/range_map_truncate_lower_unittest \ - src/processor/range_map_truncate_upper_unittest \ - src/processor/range_map_unittest \ - src/processor/stackwalker_amd64_unittest \ - src/processor/stackwalker_arm_unittest \ - src/processor/stackwalker_arm64_unittest \ - src/processor/stackwalker_address_list_unittest \ - src/processor/stackwalker_mips_unittest \ - src/processor/stackwalker_mips64_unittest \ - src/processor/stackwalker_x86_unittest \ - src/processor/synth_minidump_unittest -endif - -if LINUX_HOST -EXTRA_PROGRAMS += \ - src/client/linux/linux_client_unittest_shlib -CLEANFILES += \ - src/client/linux/linux_client_unittest_shlib - -check_PROGRAMS += \ - src/client/linux/linux_client_unittest \ - src/common/linux/google_crashdump_uploader_test - -if !DISABLE_TOOLS -check_PROGRAMS += \ - src/common/dumper_unittest \ - src/tools/linux/md2core/minidump_2_core_unittest -if X86_HOST -check_PROGRAMS += \ - src/common/mac/macho_reader_unittest -endif -endif -endif LINUX_HOST - -if !DISABLE_PROCESSOR -if SELFTEST -check_PROGRAMS += \ - src/processor/stackwalker_selftest -endif SELFTEST -endif !DISABLE_PROCESSOR - -if !DISABLE_PROCESSOR -check_SCRIPTS = \ - src/processor/microdump_stackwalk_test \ - src/processor/microdump_stackwalk_machine_readable_test \ - src/processor/minidump_dump_test \ - src/processor/minidump_stackwalk_test \ - src/processor/minidump_stackwalk_machine_readable_test +# Breakpad client +src_client_linux_libbreakpad_client_a_SOURCES = \ + src/client/linux/crash_generation/crash_generation_client.cc \ + src/client/linux/crash_generation/crash_generation_server.cc \ + src/client/linux/dump_writer_common/thread_info.cc \ + src/client/linux/dump_writer_common/ucontext_reader.cc \ + src/client/linux/handler/exception_handler.cc \ + src/client/linux/handler/exception_handler.h \ + src/client/linux/handler/minidump_descriptor.cc \ + src/client/linux/handler/minidump_descriptor.h \ + src/client/linux/log/log.cc \ + src/client/linux/log/log.h \ + src/client/linux/microdump_writer/microdump_writer.cc \ + src/client/linux/microdump_writer/microdump_writer.h \ + src/client/linux/minidump_writer/linux_core_dumper.cc \ + src/client/linux/minidump_writer/linux_dumper.cc \ + src/client/linux/minidump_writer/linux_ptrace_dumper.cc \ + src/client/linux/minidump_writer/minidump_writer.cc \ + src/client/linux/minidump_writer/pe_file.cc \ + src/client/minidump_file_writer-inl.h \ + src/client/minidump_file_writer.cc \ + src/client/minidump_file_writer.h \ + src/common/convert_UTF.cc \ + src/common/convert_UTF.h \ + src/common/md5.cc \ + src/common/md5.h \ + src/common/string_conversion.cc \ + src/common/string_conversion.h \ + src/common/linux/elf_core_dump.cc \ + src/common/linux/elfutils.cc \ + src/common/linux/elfutils.h \ + src/common/linux/file_id.cc \ + src/common/linux/file_id.h \ + src/common/linux/guid_creator.cc \ + src/common/linux/guid_creator.h \ + src/common/linux/linux_libc_support.cc \ + src/common/linux/memory_mapped_file.cc \ + src/common/linux/safe_readlink.cc +if !HAVE_GETCONTEXT +src_client_linux_libbreakpad_client_a_SOURCES += \ + src/common/linux/breakpad_getcontext.S endif -TESTS = $(check_PROGRAMS) $(check_SCRIPTS) - -if ANDROID_HOST -# Since Autotools 1.2, tests are run through a special "test driver" script. -# Unfortunately, it's not possible anymore to specify an alternative shell to -# run them on connected devices, so use a slightly modified version of the -# driver for Android. -LOG_DRIVER = $(top_srcdir)/android/test-driver -else -# The default Autotools test driver script. -if TESTS_AS_ROOT -LOG_DRIVER = $(top_srcdir)/autotools/root-test-driver $(top_srcdir)/autotools/test-driver -else -LOG_DRIVER = $(top_srcdir)/autotools/test-driver -endif !TESTS_AS_ROOT -endif !ANDROID_HOST - -if LINUX_HOST +# Client tests src_client_linux_linux_dumper_unittest_helper_SOURCES = \ src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc src_client_linux_linux_dumper_unittest_helper_LDFLAGS=$(PTHREAD_CFLAGS) @@ -491,10 +559,14 @@ src_client_linux_linux_client_unittest_shlib_SOURCES = \ src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc \ src/client/linux/minidump_writer/minidump_writer_unittest.cc \ src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc \ + src/client/linux/minidump_writer/pe_file.cc \ src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc \ src/common/linux/elf_core_dump.cc \ src/common/linux/linux_libc_support_unittest.cc \ - src/common/linux/tests/auto_testfile.h \ + src/common/linux/scoped_pipe.h \ + src/common/linux/scoped_pipe.cc \ + src/common/linux/scoped_tmpfile.h \ + src/common/linux/scoped_tmpfile.cc \ src/common/linux/tests/crash_generator.cc \ src/common/memory_allocator_unittest.cc \ src/common/tests/auto_tempdir.h \ @@ -573,26 +645,28 @@ src_client_linux_linux_client_unittest_LDADD = \ src_client_linux_linux_client_unittest_DEPENDENCIES = \ src/client/linux/linux_client_unittest_shlib -if !DISABLE_TOOLS +# Tools + src_tools_linux_core2md_core2md_SOURCES = \ src/tools/linux/core2md/core2md.cc src_tools_linux_core2md_core2md_LDADD = \ - src/client/linux/libbreakpad_client.a + src/client/linux/libbreakpad_client.a \ + src/common/path_helper.o -if HAVE_MEMFD_CREATE src_tools_linux_core_handler_core_handler_SOURCES = \ src/tools/linux/core_handler/core_handler.cc src_tools_linux_core_handler_core_handler_LDADD = \ - src/client/linux/libbreakpad_client.a -endif + src/client/linux/libbreakpad_client.a \ + src/common/path_helper.o src_tools_linux_pid2md_pid2md_SOURCES = \ src/tools/linux/pid2md/pid2md.cc src_tools_linux_pid2md_pid2md_LDADD = \ - src/client/linux/libbreakpad_client.a + src/client/linux/libbreakpad_client.a \ + src/common/path_helper.o src_tools_linux_dump_syms_dump_syms_SOURCES = \ src/common/dwarf_cfi_to_module.cc \ @@ -620,9 +694,12 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \ src/common/linux/safe_readlink.cc \ src/tools/linux/dump_syms/dump_syms.cc src_tools_linux_dump_syms_dump_syms_CXXFLAGS = \ - $(RUST_DEMANGLE_CFLAGS) + $(RUSTC_DEMANGLE_CFLAGS) \ + $(ZSTD_CFLAGS) src_tools_linux_dump_syms_dump_syms_LDADD = \ - $(RUST_DEMANGLE_LIBS) + $(RUSTC_DEMANGLE_LIBS) \ + $(ZSTD_CFLAGS) \ + -lz src_tools_linux_md2core_minidump_2_core_SOURCES = \ src/common/linux/memory_mapped_file.cc \ @@ -632,6 +709,7 @@ src_tools_linux_md2core_minidump_2_core_SOURCES = \ src_tools_linux_symupload_minidump_upload_SOURCES = \ src/common/linux/http_upload.cc \ + src/common/path_helper.cc \ src/tools/linux/symupload/minidump_upload.cc src_tools_linux_symupload_minidump_upload_LDADD = -ldl @@ -644,6 +722,7 @@ src_tools_linux_symupload_sym_upload_SOURCES = \ src/common/linux/symbol_collector_client.h \ src/common/linux/symbol_upload.cc \ src/common/linux/symbol_upload.h \ + src/common/path_helper.cc \ src/tools/linux/symupload/sym_upload.cc src_tools_linux_symupload_sym_upload_LDADD = -ldl @@ -678,10 +757,10 @@ src_tools_mac_dump_syms_dump_syms_mac_SOURCES = \ src/tools/mac/dump_syms/dump_syms_tool.cc src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS= \ -I$(top_srcdir)/src/third_party/mac_headers \ - $(RUST_DEMANGLE_CFLAGS) \ + $(RUSTC_DEMANGLE_CFLAGS) \ -DHAVE_MACH_O_NLIST_H src_tools_mac_dump_syms_dump_syms_mac_LDADD= \ - $(RUST_DEMANGLE_LIBS) + $(RUSTC_DEMANGLE_LIBS) src_common_dumper_unittest_SOURCES = \ src/common/byte_cursor_unittest.cc \ @@ -743,12 +822,15 @@ src_common_dumper_unittest_SOURCES = \ src/common/tests/file_utils.cc src_common_dumper_unittest_CPPFLAGS = \ $(AM_CPPFLAGS) $(TEST_CFLAGS) \ - $(RUST_DEMANGLE_CFLAGS) \ - $(PTHREAD_CFLAGS) + $(RUSTC_DEMANGLE_CFLAGS) \ + $(PTHREAD_CFLAGS) \ + $(ZSTD_CFLAGS) src_common_dumper_unittest_LDADD = \ $(TEST_LIBS) \ - $(RUST_DEMANGLE_LIBS) \ - $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + $(RUSTC_DEMANGLE_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \ + $(ZSTD_LIBS) \ + -lz src_common_mac_macho_reader_unittest_SOURCES = \ src/common/dwarf_cfi_to_module.cc \ @@ -782,7 +864,6 @@ src_common_mac_macho_reader_unittest_CPPFLAGS = \ src_common_mac_macho_reader_unittest_LDADD = \ $(TEST_LIBS) \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) -endif src_common_linux_google_crashdump_uploader_test_SOURCES = \ src/common/linux/google_crashdump_uploader.cc \ @@ -803,9 +884,6 @@ src_tools_linux_md2core_minidump_2_core_unittest_LDADD = \ $(TEST_LIBS) \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) -endif LINUX_HOST - -if !DISABLE_PROCESSOR src_processor_address_map_unittest_SOURCES = \ src/processor/address_map_unittest.cc src_processor_address_map_unittest_LDADD = \ @@ -877,6 +955,8 @@ src_processor_exploitability_unittest_LDADD = \ src/processor/stackwalker_mips.o \ src/processor/stackwalker_ppc.o \ src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ src/processor/stackwalker_sparc.o \ src/processor/stackwalker_x86.o \ src/processor/symbolic_constants_win.o \ @@ -884,6 +964,45 @@ src_processor_exploitability_unittest_LDADD = \ src/third_party/libdisasm/libdisasm.a \ $(TEST_LIBS) \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +if LINUX_HOST +src_processor_exploitability_unittest_LDADD += \ + src/common/linux/scoped_pipe.o \ + src/common/linux/scoped_tmpfile.o \ + src/processor/disassembler_objdump.o +endif + +src_common_linux_scoped_pipe_unittest_SOURCES = \ + src/common/linux/scoped_pipe_unittest.cc +src_common_linux_scoped_pipe_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_common_linux_scoped_pipe_unittest_LDADD = \ + src/common/linux/scoped_pipe.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_common_linux_scoped_tmpfile_unittest_SOURCES = \ + src/common/linux/scoped_tmpfile_unittest.cc +src_common_linux_scoped_tmpfile_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_common_linux_scoped_tmpfile_unittest_LDADD = \ + src/common/linux/scoped_tmpfile.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_disassembler_objdump_unittest_SOURCES = \ + src/processor/disassembler_objdump_unittest.cc +src_processor_disassembler_objdump_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_disassembler_objdump_unittest_LDADD = \ + src/common/linux/scoped_pipe.o \ + src/common/linux/scoped_tmpfile.o \ + src/processor/disassembler_objdump.o \ + src/processor/dump_context.o \ + src/processor/dump_object.o \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) src_processor_disassembler_x86_unittest_SOURCES = \ src/processor/disassembler_x86_unittest.cc @@ -950,11 +1069,19 @@ src_processor_microdump_processor_unittest_LDADD = \ src/processor/stackwalker_mips.o \ src/processor/stackwalker_ppc.o \ src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ src/processor/stackwalker_sparc.o \ src/processor/stackwalker_x86.o \ src/processor/tokenize.o \ $(TEST_LIBS) \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +if LINUX_HOST +src_processor_microdump_processor_unittest_LDADD += \ + src/common/linux/scoped_pipe.o \ + src/common/linux/scoped_tmpfile.o \ + src/processor/disassembler_objdump.o +endif src_processor_minidump_processor_unittest_SOURCES = \ src/processor/minidump_processor_unittest.cc @@ -989,6 +1116,8 @@ src_processor_minidump_processor_unittest_LDADD = \ src/processor/stackwalker_mips.o \ src/processor/stackwalker_ppc.o \ src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ src/processor/stackwalker_sparc.o \ src/processor/stackwalker_x86.o \ src/processor/symbolic_constants_win.o \ @@ -996,6 +1125,12 @@ src_processor_minidump_processor_unittest_LDADD = \ src/third_party/libdisasm/libdisasm.a \ $(TEST_LIBS) \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +if LINUX_HOST +src_processor_minidump_processor_unittest_LDADD += \ + src/common/linux/scoped_pipe.o \ + src/common/linux/scoped_tmpfile.o \ + src/processor/disassembler_objdump.o +endif src_processor_minidump_unittest_SOURCES = \ src/common/test_assembler.cc \ @@ -1132,10 +1267,18 @@ src_processor_stackwalker_selftest_LDADD = \ src/processor/stackwalker_mips.o \ src/processor/stackwalker_ppc.o \ src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ src/processor/stackwalker_sparc.o \ src/processor/stackwalker_x86.o \ src/processor/tokenize.o \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +if LINUX_HOST +src_processor_stackwalker_selftest_LDADD += \ + src/common/linux/scoped_pipe.o \ + src/common/linux/scoped_tmpfile.o \ + src/processor/disassembler_objdump.o +endif src_processor_stackwalker_amd64_unittest_SOURCES = \ src/common/test_assembler.cc \ @@ -1197,6 +1340,26 @@ src_processor_stackwalker_mips64_unittest_LDADD = \ src_processor_stackwalker_mips64_unittest_CPPFLAGS = \ $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_stackwalker_riscv_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_riscv_unittest.cc +src_processor_stackwalker_riscv_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +src_processor_stackwalker_riscv_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_riscv64_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_riscv64_unittest.cc +src_processor_stackwalker_riscv64_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +src_processor_stackwalker_riscv64_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + src_processor_stackwalker_x86_unittest_SOURCES = \ src/common/test_assembler.cc \ src/processor/stackwalker_x86_unittest.cc @@ -1253,13 +1416,10 @@ src_common_dwarf_dwarf2reader_splitfunctions_unittest_LDADD = \ $(TEST_LIBS) \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) -## Non-installables -noinst_PROGRAMS = -noinst_SCRIPTS = $(check_SCRIPTS) - src_processor_minidump_dump_SOURCES = \ src/processor/minidump_dump.cc src_processor_minidump_dump_LDADD = \ + src/common/path_helper.o \ src/processor/basic_code_modules.o \ src/processor/convert_old_arm64_context.o \ src/processor/dump_context.o \ @@ -1299,10 +1459,18 @@ src_processor_microdump_stackwalk_LDADD = \ src/processor/stackwalker_mips.o \ src/processor/stackwalker_ppc.o \ src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ src/processor/stackwalker_sparc.o \ src/processor/stackwalker_x86.o \ src/processor/tokenize.o \ src/third_party/libdisasm/libdisasm.a +if LINUX_HOST +src_processor_microdump_stackwalk_LDADD += \ + src/common/linux/scoped_pipe.o \ + src/common/linux/scoped_tmpfile.o \ + src/processor/disassembler_objdump.o +endif src_processor_minidump_stackwalk_SOURCES = \ src/processor/minidump_stackwalk.cc @@ -1338,13 +1506,19 @@ src_processor_minidump_stackwalk_LDADD = \ src/processor/stackwalker_mips.o \ src/processor/stackwalker_ppc.o \ src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ src/processor/stackwalker_sparc.o \ src/processor/stackwalker_x86.o \ src/processor/symbolic_constants_win.o \ src/processor/tokenize.o \ src/third_party/libdisasm/libdisasm.a - -endif !DISABLE_PROCESSOR +if LINUX_HOST +src_processor_minidump_stackwalk_LDADD += \ + src/common/linux/scoped_pipe.o \ + src/common/linux/scoped_tmpfile.o \ + src/processor/disassembler_objdump.o +endif LINUX_HOST ## Additional files to be included in a source distribution ## @@ -1389,13 +1563,10 @@ EXTRA_DIST = \ src/client/solaris/handler/minidump_test.cc \ src/client/solaris/handler/solaris_lwp.cc \ src/client/solaris/handler/solaris_lwp.h \ - src/client/windows/breakpad_client.gyp \ src/client/windows/handler/exception_handler.cc \ src/client/windows/handler/exception_handler.h \ - src/client/windows/handler/exception_handler.gyp \ src/client/windows/sender/crash_report_sender.cc \ src/client/windows/sender/crash_report_sender.h \ - src/client/windows/sender/crash_report_sender.gyp \ src/common/dwarf/dwarf2diehandler.h \ src/common/dwarf/dwarf2enums.h \ src/common/dwarf/line_state_machine.h \ @@ -1565,10 +1736,12 @@ EXTRA_DIST = \ src/third_party/curl/typecheck-gcc.h \ src/third_party/curl/types.h \ src/third_party/mac_headers/architecture/byte_order.h \ + src/third_party/mac_headers/arm/_types.h \ src/third_party/mac_headers/i386/_types.h \ src/third_party/mac_headers/mach/boolean.h \ + src/third_party/mac_headers/mach/arm/boolean.h \ + src/third_party/mac_headers/mach/arm/vm_types.h \ src/third_party/mac_headers/mach/i386/boolean.h \ - src/third_party/mac_headers/mach/i386/vm_param.h \ src/third_party/mac_headers/mach/i386/vm_types.h \ src/third_party/mac_headers/mach/machine/boolean.h \ src/third_party/mac_headers/mach/machine.h \ @@ -1605,9 +1778,7 @@ EXTRA_DIST = \ src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym \ src/tools/windows/converter/ms_symbol_server_converter.cc \ src/tools/windows/converter/ms_symbol_server_converter.h \ - src/tools/windows/converter/ms_symbol_server_converter.gyp \ src/tools/windows/dump_syms/dump_syms.cc \ - src/tools/windows/dump_syms/dump_syms.gyp \ src/tools/windows/dump_syms/run_regtest.sh \ src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc \ src/tools/windows/dump_syms/testdata/dump_syms_regtest.pdb \ @@ -1617,8 +1788,7 @@ EXTRA_DIST = \ src/tools/windows/dump_syms/testdata/omap_reorder_funcs.sym \ src/tools/windows/dump_syms/testdata/omap_stretched.sym \ src/tools/windows/dump_syms/testdata/omap_stretched_filled.sym \ - src/tools/windows/symupload/symupload.cc \ - src/tools/windows/symupload/symupload.gyp + src/tools/windows/symupload/symupload.cc mostlyclean-local: -find src -name '*.dwo' -exec rm -f {} + diff --git a/Makefile.in b/Makefile.in index 55ef6f3fb..7637800c0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.3 from Makefile.am. +# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2020 Free Software Foundation, Inc. +# Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -14,8 +14,7 @@ @SET_MAKE@ -# 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 @@ -27,7 +26,7 @@ # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. -# * Neither the name of Google Inc. nor the names of its +# * Neither the name of Google 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,43 +131,32 @@ host_triplet = @host@ # Build as PIC on Linux, for linux_client_unittest_shlib @LINUX_HOST_TRUE@am__append_2 = -fPIC @LINUX_HOST_TRUE@am__append_3 = -fPIC -libexec_PROGRAMS = $(am__EXEEXT_10) +libexec_PROGRAMS = $(am__EXEEXT_11) bin_PROGRAMS = $(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4) -check_PROGRAMS = $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) \ - $(am__EXEEXT_8) $(am__EXEEXT_9) +check_PROGRAMS = src/common/safe_math_unittest$(EXEEXT) \ + $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) \ + $(am__EXEEXT_8) $(am__EXEEXT_9) $(am__EXEEXT_10) +noinst_PROGRAMS = EXTRA_PROGRAMS = $(am__EXEEXT_1) -@DISABLE_PROCESSOR_FALSE@am__append_4 = src/libbreakpad.a -@DISABLE_PROCESSOR_FALSE@am__append_5 = breakpad.pc -@DISABLE_PROCESSOR_FALSE@am__append_6 = src/third_party/libdisasm/libdisasm.a -@LINUX_HOST_TRUE@am__append_7 = src/client/linux/libbreakpad_client.a -@LINUX_HOST_TRUE@am__append_8 = breakpad-client.pc -@HAVE_GETCONTEXT_FALSE@@LINUX_HOST_TRUE@am__append_9 = \ -@HAVE_GETCONTEXT_FALSE@@LINUX_HOST_TRUE@ src/common/linux/breakpad_getcontext.S - -@DISABLE_PROCESSOR_FALSE@am__append_10 = \ + +# +# Tests helper library +# +@SYSTEM_TEST_LIBS_FALSE@am__append_4 = src/testing/libtesting.a + +# +# Breakpad minidump and microdump +# processor library, tools and tests +# +@DISABLE_PROCESSOR_FALSE@am__append_5 = src/libbreakpad.a +@DISABLE_PROCESSOR_FALSE@am__append_6 = breakpad.pc +@DISABLE_PROCESSOR_FALSE@am__append_7 = src/third_party/libdisasm/libdisasm.a +@DISABLE_PROCESSOR_FALSE@am__append_8 = \ @DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk \ @DISABLE_PROCESSOR_FALSE@ src/processor/minidump_dump \ @DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk -@LINUX_HOST_TRUE@am__append_11 = src/client/linux/linux_dumper_unittest_helper \ -@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest_shlib -@LINUX_HOST_TRUE@am__append_12 = src/client/linux/linux_dumper_unittest_helper \ -@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest_shlib -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__append_13 = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/core2md/core2md \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/pid2md/pid2md \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/dump_syms/dump_syms \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump-2-core \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/minidump_upload \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/sym_upload - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@am__append_14 = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@ src/tools/mac/dump_syms/dump_syms_mac - -@DISABLE_TOOLS_FALSE@@HAVE_MEMFD_CREATE_TRUE@@LINUX_HOST_TRUE@am__append_15 = \ -@DISABLE_TOOLS_FALSE@@HAVE_MEMFD_CREATE_TRUE@@LINUX_HOST_TRUE@ src/tools/linux/core_handler/core_handler - -@DISABLE_PROCESSOR_FALSE@am__append_16 = \ +@DISABLE_PROCESSOR_FALSE@am__append_9 = \ @DISABLE_PROCESSOR_FALSE@ src/common/test_assembler_unittest \ @DISABLE_PROCESSOR_FALSE@ src/common/dwarf/dwarf2reader_lineinfo_unittest \ @DISABLE_PROCESSOR_FALSE@ src/common/dwarf/dwarf2reader_splitfunctions_unittest \ @@ -199,32 +187,116 @@ EXTRA_PROGRAMS = $(am__EXEEXT_1) @DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list_unittest \ @DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips_unittest \ @DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips64_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_riscv_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_riscv64_unittest \ @DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86_unittest \ @DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump_unittest -@LINUX_HOST_TRUE@am__append_17 = \ +@DISABLE_PROCESSOR_FALSE@@LINUX_HOST_TRUE@am__append_10 = \ +@DISABLE_PROCESSOR_FALSE@@LINUX_HOST_TRUE@ src/processor/disassembler_objdump_unittest \ +@DISABLE_PROCESSOR_FALSE@@LINUX_HOST_TRUE@ src/common/linux/scoped_pipe_unittest \ +@DISABLE_PROCESSOR_FALSE@@LINUX_HOST_TRUE@ src/common/linux/scoped_tmpfile_unittest + +@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@am__append_11 = \ +@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@ src/processor/stackwalker_selftest + + +# +# Breakpad client library and tests +# +# Currently Linux only, the macOS client +# is built using an Xcode project instead. +# +@LINUX_HOST_TRUE@am__append_12 = src/client/linux/libbreakpad_client.a +@LINUX_HOST_TRUE@am__append_13 = breakpad-client.pc +@LINUX_HOST_TRUE@am__append_14 = \ @LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest \ @LINUX_HOST_TRUE@ src/common/linux/google_crashdump_uploader_test -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__append_18 = \ +@LINUX_HOST_TRUE@am__append_15 = \ +@LINUX_HOST_TRUE@ src/client/linux/linux_dumper_unittest_helper \ +@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest_shlib + +@LINUX_HOST_TRUE@am__append_16 = \ +@LINUX_HOST_TRUE@ src/client/linux/linux_dumper_unittest_helper \ +@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest_shlib + + +# +# Various Breakpad tools +# This includes symbol dumpers and uploaders +# +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__append_17 = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/core2md/core2md \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/pid2md/pid2md \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/dump_syms/dump_syms \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump-2-core \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/minidump_upload \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/sym_upload + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@am__append_18 = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@ src/tools/mac/dump_syms/dump_syms_mac + +@DISABLE_TOOLS_FALSE@@HAVE_MEMFD_CREATE_TRUE@@LINUX_HOST_TRUE@am__append_19 = \ +@DISABLE_TOOLS_FALSE@@HAVE_MEMFD_CREATE_TRUE@@LINUX_HOST_TRUE@ src/tools/linux/core_handler/core_handler + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__append_20 = \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump_2_core_unittest -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@am__append_19 = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@am__append_21 = \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@ src/common/mac/macho_reader_unittest -@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@am__append_20 = \ -@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@ src/processor/stackwalker_selftest - -@HAVE_GETCONTEXT_FALSE@@LINUX_HOST_TRUE@am__append_21 = src/common/linux/breakpad_getcontext.S \ -@HAVE_GETCONTEXT_FALSE@@LINUX_HOST_TRUE@ src/common/linux/breakpad_getcontext_unittest.cc -@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__append_22 = \ -@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ -llog -lm - -@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__append_23 = \ -@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ -llog +@LINUX_HOST_TRUE@am__append_22 = \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_pipe.h \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_pipe.cc \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_tmpfile.h \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_tmpfile.cc \ +@LINUX_HOST_TRUE@ src/processor/disassembler_objdump.h \ +@LINUX_HOST_TRUE@ src/processor/disassembler_objdump.cc + +@HAVE_GETCONTEXT_FALSE@am__append_23 = \ +@HAVE_GETCONTEXT_FALSE@ src/common/linux/breakpad_getcontext.S + +@HAVE_GETCONTEXT_FALSE@am__append_24 = \ +@HAVE_GETCONTEXT_FALSE@ src/common/linux/breakpad_getcontext.S \ +@HAVE_GETCONTEXT_FALSE@ src/common/linux/breakpad_getcontext_unittest.cc +@ANDROID_HOST_TRUE@am__append_25 = \ +@ANDROID_HOST_TRUE@ -llog -lm + +@ANDROID_HOST_TRUE@am__append_26 = \ +@ANDROID_HOST_TRUE@ -llog + +@LINUX_HOST_TRUE@am__append_27 = \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_pipe.o \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_tmpfile.o \ +@LINUX_HOST_TRUE@ src/processor/disassembler_objdump.o + +@LINUX_HOST_TRUE@am__append_28 = \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_pipe.o \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_tmpfile.o \ +@LINUX_HOST_TRUE@ src/processor/disassembler_objdump.o + +@LINUX_HOST_TRUE@am__append_29 = \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_pipe.o \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_tmpfile.o \ +@LINUX_HOST_TRUE@ src/processor/disassembler_objdump.o + +@LINUX_HOST_TRUE@am__append_30 = \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_pipe.o \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_tmpfile.o \ +@LINUX_HOST_TRUE@ src/processor/disassembler_objdump.o + +@LINUX_HOST_TRUE@am__append_31 = \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_pipe.o \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_tmpfile.o \ +@LINUX_HOST_TRUE@ src/processor/disassembler_objdump.o + +@LINUX_HOST_TRUE@am__append_32 = \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_pipe.o \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_tmpfile.o \ +@LINUX_HOST_TRUE@ src/processor/disassembler_objdump.o -noinst_PROGRAMS = subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_compile_flags.m4 \ @@ -299,15 +371,20 @@ am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" \ @DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list_unittest$(EXEEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips_unittest$(EXEEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips64_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_riscv_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_riscv64_unittest$(EXEEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86_unittest$(EXEEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump_unittest$(EXEEXT) -@LINUX_HOST_TRUE@am__EXEEXT_6 = src/client/linux/linux_client_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@@LINUX_HOST_TRUE@am__EXEEXT_6 = src/processor/disassembler_objdump_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@@LINUX_HOST_TRUE@ src/common/linux/scoped_pipe_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@@LINUX_HOST_TRUE@ src/common/linux/scoped_tmpfile_unittest$(EXEEXT) +@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@am__EXEEXT_7 = src/processor/stackwalker_selftest$(EXEEXT) +@LINUX_HOST_TRUE@am__EXEEXT_8 = src/client/linux/linux_client_unittest$(EXEEXT) \ @LINUX_HOST_TRUE@ src/common/linux/google_crashdump_uploader_test$(EXEEXT) -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__EXEEXT_7 = src/common/dumper_unittest$(EXEEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__EXEEXT_9 = src/common/dumper_unittest$(EXEEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump_2_core_unittest$(EXEEXT) -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@am__EXEEXT_8 = src/common/mac/macho_reader_unittest$(EXEEXT) -@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@am__EXEEXT_9 = src/processor/stackwalker_selftest$(EXEEXT) -@DISABLE_TOOLS_FALSE@@HAVE_MEMFD_CREATE_TRUE@@LINUX_HOST_TRUE@am__EXEEXT_10 = src/tools/linux/core_handler/core_handler$(EXEEXT) +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@am__EXEEXT_10 = src/common/mac/macho_reader_unittest$(EXEEXT) +@DISABLE_TOOLS_FALSE@@HAVE_MEMFD_CREATE_TRUE@@LINUX_HOST_TRUE@am__EXEEXT_11 = src/tools/linux/core_handler/core_handler$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS) $(noinst_PROGRAMS) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ @@ -360,6 +437,7 @@ am__src_client_linux_libbreakpad_client_a_SOURCES_DIST = \ src/client/linux/minidump_writer/linux_dumper.cc \ src/client/linux/minidump_writer/linux_ptrace_dumper.cc \ src/client/linux/minidump_writer/minidump_writer.cc \ + src/client/linux/minidump_writer/pe_file.cc \ src/client/minidump_file_writer-inl.h \ src/client/minidump_file_writer.cc \ src/client/minidump_file_writer.h src/common/convert_UTF.cc \ @@ -374,31 +452,30 @@ am__src_client_linux_libbreakpad_client_a_SOURCES_DIST = \ src/common/linux/safe_readlink.cc \ src/common/linux/breakpad_getcontext.S am__dirstamp = $(am__leading_dot)dirstamp -@HAVE_GETCONTEXT_FALSE@@LINUX_HOST_TRUE@am__objects_1 = src/common/linux/breakpad_getcontext.$(OBJEXT) -@LINUX_HOST_TRUE@am_src_client_linux_libbreakpad_client_a_OBJECTS = src/client/linux/crash_generation/crash_generation_client.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_server.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/thread_info.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/ucontext_reader.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/handler/minidump_descriptor.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/log/log.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/microdump_writer.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_core_dumper.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/minidump_file_writer.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/convert_UTF.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/md5.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/string_conversion.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/linux/elf_core_dump.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/linux/elfutils.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/linux/file_id.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/linux/guid_creator.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.$(OBJEXT) \ -@LINUX_HOST_TRUE@ $(am__objects_1) +@HAVE_GETCONTEXT_FALSE@am__objects_1 = src/common/linux/breakpad_getcontext.$(OBJEXT) +am_src_client_linux_libbreakpad_client_a_OBJECTS = src/client/linux/crash_generation/crash_generation_client.$(OBJEXT) \ + src/client/linux/crash_generation/crash_generation_server.$(OBJEXT) \ + src/client/linux/dump_writer_common/thread_info.$(OBJEXT) \ + src/client/linux/dump_writer_common/ucontext_reader.$(OBJEXT) \ + src/client/linux/handler/exception_handler.$(OBJEXT) \ + src/client/linux/handler/minidump_descriptor.$(OBJEXT) \ + src/client/linux/log/log.$(OBJEXT) \ + src/client/linux/microdump_writer/microdump_writer.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_core_dumper.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_dumper.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_ptrace_dumper.$(OBJEXT) \ + src/client/linux/minidump_writer/minidump_writer.$(OBJEXT) \ + src/client/linux/minidump_writer/pe_file.$(OBJEXT) \ + src/client/minidump_file_writer.$(OBJEXT) \ + src/common/convert_UTF.$(OBJEXT) src/common/md5.$(OBJEXT) \ + src/common/string_conversion.$(OBJEXT) \ + src/common/linux/elf_core_dump.$(OBJEXT) \ + src/common/linux/elfutils.$(OBJEXT) \ + src/common/linux/file_id.$(OBJEXT) \ + src/common/linux/guid_creator.$(OBJEXT) \ + src/common/linux/linux_libc_support.$(OBJEXT) \ + src/common/linux/memory_mapped_file.$(OBJEXT) \ + src/common/linux/safe_readlink.$(OBJEXT) $(am__objects_1) src_client_linux_libbreakpad_client_a_OBJECTS = \ $(am_src_client_linux_libbreakpad_client_a_OBJECTS) src_libbreakpad_a_AR = $(AR) $(ARFLAGS) @@ -494,6 +571,10 @@ am__src_libbreakpad_a_SOURCES_DIST = \ src/processor/stackwalker_ppc.h \ src/processor/stackwalker_ppc64.cc \ src/processor/stackwalker_ppc64.h \ + src/processor/stackwalker_riscv.cc \ + src/processor/stackwalker_riscv.h \ + src/processor/stackwalker_riscv64.cc \ + src/processor/stackwalker_riscv64.h \ src/processor/stackwalker_sparc.cc \ src/processor/stackwalker_sparc.h \ src/processor/stackwalker_x86.cc \ @@ -509,46 +590,58 @@ am__src_libbreakpad_a_SOURCES_DIST = \ src/processor/static_range_map.h \ src/processor/symbolic_constants_win.cc \ src/processor/symbolic_constants_win.h \ - src/processor/tokenize.cc src/processor/tokenize.h -@DISABLE_PROCESSOR_FALSE@am_src_libbreakpad_a_OBJECTS = src/processor/basic_code_modules.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.$(OBJEXT) + src/processor/tokenize.cc src/processor/tokenize.h \ + src/common/linux/scoped_pipe.h src/common/linux/scoped_pipe.cc \ + src/common/linux/scoped_tmpfile.h \ + src/common/linux/scoped_tmpfile.cc \ + src/processor/disassembler_objdump.h \ + src/processor/disassembler_objdump.cc +@LINUX_HOST_TRUE@am__objects_2 = \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_pipe.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/linux/scoped_tmpfile.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/processor/disassembler_objdump.$(OBJEXT) +am_src_libbreakpad_a_OBJECTS = \ + src/processor/basic_code_modules.$(OBJEXT) \ + src/processor/basic_source_line_resolver.$(OBJEXT) \ + src/processor/call_stack.$(OBJEXT) \ + src/processor/cfi_frame_info.$(OBJEXT) \ + src/processor/convert_old_arm64_context.$(OBJEXT) \ + src/processor/disassembler_x86.$(OBJEXT) \ + src/processor/dump_context.$(OBJEXT) \ + src/processor/dump_object.$(OBJEXT) \ + src/processor/exploitability.$(OBJEXT) \ + src/processor/exploitability_linux.$(OBJEXT) \ + src/processor/exploitability_win.$(OBJEXT) \ + src/processor/fast_source_line_resolver.$(OBJEXT) \ + src/processor/logging.$(OBJEXT) \ + src/processor/microdump.$(OBJEXT) \ + src/processor/microdump_processor.$(OBJEXT) \ + src/processor/minidump.$(OBJEXT) \ + src/processor/minidump_processor.$(OBJEXT) \ + src/processor/module_comparer.$(OBJEXT) \ + src/processor/module_serializer.$(OBJEXT) \ + src/processor/pathname_stripper.$(OBJEXT) \ + src/processor/process_state.$(OBJEXT) \ + src/processor/proc_maps_linux.$(OBJEXT) \ + src/processor/simple_symbol_supplier.$(OBJEXT) \ + src/processor/source_line_resolver_base.$(OBJEXT) \ + src/processor/stack_frame_cpu.$(OBJEXT) \ + src/processor/stack_frame_symbolizer.$(OBJEXT) \ + src/processor/stackwalk_common.$(OBJEXT) \ + src/processor/stackwalker.$(OBJEXT) \ + src/processor/stackwalker_amd64.$(OBJEXT) \ + src/processor/stackwalker_arm.$(OBJEXT) \ + src/processor/stackwalker_arm64.$(OBJEXT) \ + src/processor/stackwalker_address_list.$(OBJEXT) \ + src/processor/stackwalker_mips.$(OBJEXT) \ + src/processor/stackwalker_ppc.$(OBJEXT) \ + src/processor/stackwalker_ppc64.$(OBJEXT) \ + src/processor/stackwalker_riscv.$(OBJEXT) \ + src/processor/stackwalker_riscv64.$(OBJEXT) \ + src/processor/stackwalker_sparc.$(OBJEXT) \ + src/processor/stackwalker_x86.$(OBJEXT) \ + src/processor/symbolic_constants_win.$(OBJEXT) \ + src/processor/tokenize.$(OBJEXT) $(am__objects_2) src_libbreakpad_a_OBJECTS = $(am_src_libbreakpad_a_OBJECTS) src_testing_libtesting_a_AR = $(AR) $(ARFLAGS) src_testing_libtesting_a_LIBADD = @@ -564,47 +657,21 @@ src_testing_libtesting_a_OBJECTS = \ $(am_src_testing_libtesting_a_OBJECTS) src_third_party_libdisasm_libdisasm_a_AR = $(AR) $(ARFLAGS) src_third_party_libdisasm_libdisasm_a_LIBADD = -am__src_third_party_libdisasm_libdisasm_a_SOURCES_DIST = \ - src/third_party/libdisasm/ia32_implicit.c \ - src/third_party/libdisasm/ia32_implicit.h \ - src/third_party/libdisasm/ia32_insn.c \ - src/third_party/libdisasm/ia32_insn.h \ - src/third_party/libdisasm/ia32_invariant.c \ - src/third_party/libdisasm/ia32_invariant.h \ - src/third_party/libdisasm/ia32_modrm.c \ - src/third_party/libdisasm/ia32_modrm.h \ - src/third_party/libdisasm/ia32_opcode_tables.c \ - src/third_party/libdisasm/ia32_opcode_tables.h \ - src/third_party/libdisasm/ia32_operand.c \ - src/third_party/libdisasm/ia32_operand.h \ - src/third_party/libdisasm/ia32_reg.c \ - src/third_party/libdisasm/ia32_reg.h \ - src/third_party/libdisasm/ia32_settings.c \ - src/third_party/libdisasm/ia32_settings.h \ - src/third_party/libdisasm/libdis.h \ - src/third_party/libdisasm/qword.h \ - src/third_party/libdisasm/x86_disasm.c \ - src/third_party/libdisasm/x86_format.c \ - src/third_party/libdisasm/x86_imm.c \ - src/third_party/libdisasm/x86_imm.h \ - src/third_party/libdisasm/x86_insn.c \ - src/third_party/libdisasm/x86_misc.c \ - src/third_party/libdisasm/x86_operand_list.c \ - src/third_party/libdisasm/x86_operand_list.h -@DISABLE_PROCESSOR_FALSE@am_src_third_party_libdisasm_libdisasm_a_OBJECTS = src/third_party/libdisasm/ia32_implicit.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_insn.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_invariant.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_modrm.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_opcode_tables.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_operand.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_reg.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_settings.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_disasm.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_format.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_imm.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_insn.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_misc.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_operand_list.$(OBJEXT) +am_src_third_party_libdisasm_libdisasm_a_OBJECTS = \ + src/third_party/libdisasm/ia32_implicit.$(OBJEXT) \ + src/third_party/libdisasm/ia32_insn.$(OBJEXT) \ + src/third_party/libdisasm/ia32_invariant.$(OBJEXT) \ + src/third_party/libdisasm/ia32_modrm.$(OBJEXT) \ + src/third_party/libdisasm/ia32_opcode_tables.$(OBJEXT) \ + src/third_party/libdisasm/ia32_operand.$(OBJEXT) \ + src/third_party/libdisasm/ia32_reg.$(OBJEXT) \ + src/third_party/libdisasm/ia32_settings.$(OBJEXT) \ + src/third_party/libdisasm/x86_disasm.$(OBJEXT) \ + src/third_party/libdisasm/x86_format.$(OBJEXT) \ + src/third_party/libdisasm/x86_imm.$(OBJEXT) \ + src/third_party/libdisasm/x86_insn.$(OBJEXT) \ + src/third_party/libdisasm/x86_misc.$(OBJEXT) \ + src/third_party/libdisasm/x86_operand_list.$(OBJEXT) src_third_party_libdisasm_libdisasm_a_OBJECTS = \ $(am_src_third_party_libdisasm_libdisasm_a_OBJECTS) am_src_client_linux_linux_client_unittest_OBJECTS = @@ -632,10 +699,13 @@ am__src_client_linux_linux_client_unittest_shlib_SOURCES_DIST = \ src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc \ src/client/linux/minidump_writer/minidump_writer_unittest.cc \ src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc \ + src/client/linux/minidump_writer/pe_file.cc \ src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc \ src/common/linux/elf_core_dump.cc \ src/common/linux/linux_libc_support_unittest.cc \ - src/common/linux/tests/auto_testfile.h \ + src/common/linux/scoped_pipe.h src/common/linux/scoped_pipe.cc \ + src/common/linux/scoped_tmpfile.h \ + src/common/linux/scoped_tmpfile.cc \ src/common/linux/tests/crash_generator.cc \ src/common/memory_allocator_unittest.cc \ src/common/tests/auto_tempdir.h src/common/tests/file_utils.cc \ @@ -648,46 +718,48 @@ am__src_client_linux_linux_client_unittest_shlib_SOURCES_DIST = \ src/processor/proc_maps_linux.cc \ src/common/linux/breakpad_getcontext.S \ src/common/linux/breakpad_getcontext_unittest.cc -@SYSTEM_TEST_LIBS_FALSE@am__objects_2 = src/testing/googletest/src/client_linux_linux_client_unittest_shlib-gtest-all.$(OBJEXT) \ +@SYSTEM_TEST_LIBS_FALSE@am__objects_3 = src/testing/googletest/src/client_linux_linux_client_unittest_shlib-gtest-all.$(OBJEXT) \ @SYSTEM_TEST_LIBS_FALSE@ src/testing/googletest/src/client_linux_linux_client_unittest_shlib-gtest_main.$(OBJEXT) \ @SYSTEM_TEST_LIBS_FALSE@ src/testing/googlemock/src/client_linux_linux_client_unittest_shlib-gmock-all.$(OBJEXT) -@HAVE_GETCONTEXT_FALSE@@LINUX_HOST_TRUE@am__objects_3 = src/common/linux/client_linux_linux_client_unittest_shlib-breakpad_getcontext.$(OBJEXT) \ -@HAVE_GETCONTEXT_FALSE@@LINUX_HOST_TRUE@ src/common/linux/client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.$(OBJEXT) -@LINUX_HOST_TRUE@am_src_client_linux_linux_client_unittest_shlib_OBJECTS = \ -@LINUX_HOST_TRUE@ $(am__objects_2) \ -@LINUX_HOST_TRUE@ src/client/linux/handler/linux_client_unittest_shlib-exception_handler_unittest.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/linux_client_unittest_shlib-microdump_writer_unittest.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-directory_reader_unittest.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-cpu_set_unittest.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-line_reader_unittest.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-linux_core_dumper.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-linux_core_dumper_unittest.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-linux_ptrace_dumper_unittest.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_unittest.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_unittest_utils.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/linux/client_linux_linux_client_unittest_shlib-elf_core_dump.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/linux/client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/linux/tests/client_linux_linux_client_unittest_shlib-crash_generator.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/client_linux_linux_client_unittest_shlib-memory_allocator_unittest.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/tests/client_linux_linux_client_unittest_shlib-file_utils.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/processor/client_linux_linux_client_unittest_shlib-basic_code_modules.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/processor/client_linux_linux_client_unittest_shlib-convert_old_arm64_context.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/processor/client_linux_linux_client_unittest_shlib-dump_context.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/processor/client_linux_linux_client_unittest_shlib-dump_object.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/processor/client_linux_linux_client_unittest_shlib-logging.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/processor/client_linux_linux_client_unittest_shlib-minidump.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/processor/client_linux_linux_client_unittest_shlib-pathname_stripper.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/processor/client_linux_linux_client_unittest_shlib-proc_maps_linux.$(OBJEXT) \ -@LINUX_HOST_TRUE@ $(am__objects_3) +@HAVE_GETCONTEXT_FALSE@am__objects_4 = src/common/linux/client_linux_linux_client_unittest_shlib-breakpad_getcontext.$(OBJEXT) \ +@HAVE_GETCONTEXT_FALSE@ src/common/linux/client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.$(OBJEXT) +am_src_client_linux_linux_client_unittest_shlib_OBJECTS = \ + $(am__objects_3) \ + src/client/linux/handler/linux_client_unittest_shlib-exception_handler_unittest.$(OBJEXT) \ + src/client/linux/microdump_writer/linux_client_unittest_shlib-microdump_writer_unittest.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_client_unittest_shlib-directory_reader_unittest.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_client_unittest_shlib-cpu_set_unittest.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_client_unittest_shlib-line_reader_unittest.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_client_unittest_shlib-linux_core_dumper.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_client_unittest_shlib-linux_core_dumper_unittest.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_client_unittest_shlib-linux_ptrace_dumper_unittest.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_unittest.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_unittest_utils.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.$(OBJEXT) \ + src/client/linux/minidump_writer/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.$(OBJEXT) \ + src/common/linux/client_linux_linux_client_unittest_shlib-elf_core_dump.$(OBJEXT) \ + src/common/linux/client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.$(OBJEXT) \ + src/common/linux/client_linux_linux_client_unittest_shlib-scoped_pipe.$(OBJEXT) \ + src/common/linux/client_linux_linux_client_unittest_shlib-scoped_tmpfile.$(OBJEXT) \ + src/common/linux/tests/client_linux_linux_client_unittest_shlib-crash_generator.$(OBJEXT) \ + src/common/client_linux_linux_client_unittest_shlib-memory_allocator_unittest.$(OBJEXT) \ + src/common/tests/client_linux_linux_client_unittest_shlib-file_utils.$(OBJEXT) \ + src/processor/client_linux_linux_client_unittest_shlib-basic_code_modules.$(OBJEXT) \ + src/processor/client_linux_linux_client_unittest_shlib-convert_old_arm64_context.$(OBJEXT) \ + src/processor/client_linux_linux_client_unittest_shlib-dump_context.$(OBJEXT) \ + src/processor/client_linux_linux_client_unittest_shlib-dump_object.$(OBJEXT) \ + src/processor/client_linux_linux_client_unittest_shlib-logging.$(OBJEXT) \ + src/processor/client_linux_linux_client_unittest_shlib-minidump.$(OBJEXT) \ + src/processor/client_linux_linux_client_unittest_shlib-pathname_stripper.$(OBJEXT) \ + src/processor/client_linux_linux_client_unittest_shlib-proc_maps_linux.$(OBJEXT) \ + $(am__objects_4) src_client_linux_linux_client_unittest_shlib_OBJECTS = \ $(am_src_client_linux_linux_client_unittest_shlib_OBJECTS) src_client_linux_linux_client_unittest_shlib_LINK = $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) \ $(src_client_linux_linux_client_unittest_shlib_LDFLAGS) \ $(LDFLAGS) -o $@ -am__src_client_linux_linux_dumper_unittest_helper_SOURCES_DIST = src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc -@LINUX_HOST_TRUE@am_src_client_linux_linux_dumper_unittest_helper_OBJECTS = src/client/linux/minidump_writer/linux_dumper_unittest_helper-linux_dumper_unittest_helper.$(OBJEXT) +am_src_client_linux_linux_dumper_unittest_helper_OBJECTS = src/client/linux/minidump_writer/linux_dumper_unittest_helper-linux_dumper_unittest_helper.$(OBJEXT) src_client_linux_linux_dumper_unittest_helper_OBJECTS = \ $(am_src_client_linux_linux_dumper_unittest_helper_OBJECTS) src_client_linux_linux_dumper_unittest_helper_LDADD = $(LDADD) @@ -696,911 +768,664 @@ src_client_linux_linux_dumper_unittest_helper_LINK = $(CXXLD) \ $(CXXFLAGS) \ $(src_client_linux_linux_dumper_unittest_helper_LDFLAGS) \ $(LDFLAGS) -o $@ -am__src_common_dumper_unittest_SOURCES_DIST = \ - src/common/byte_cursor_unittest.cc src/common/convert_UTF.cc \ - src/common/dwarf_cfi_to_module.cc \ - src/common/dwarf_cfi_to_module_unittest.cc \ - src/common/dwarf_cu_to_module.cc \ - src/common/dwarf_cu_to_module_unittest.cc \ - src/common/dwarf_line_to_module.cc \ - src/common/dwarf_line_to_module_unittest.cc \ - src/common/dwarf_range_list_handler.cc src/common/language.cc \ - src/common/memory_range_unittest.cc src/common/module.cc \ - src/common/module_unittest.cc src/common/path_helper.cc \ - src/common/stabs_reader.cc src/common/stabs_reader_unittest.cc \ - src/common/stabs_to_module.cc \ - src/common/stabs_to_module_unittest.cc \ - src/common/string_conversion.cc \ - src/common/string_conversion_unittest.cc \ - src/common/test_assembler.cc src/common/dwarf/bytereader.cc \ - src/common/dwarf/bytereader.h \ - src/common/dwarf/bytereader-inl.h \ - src/common/dwarf/bytereader_unittest.cc \ - src/common/dwarf/cfi_assembler.cc \ - src/common/dwarf/cfi_assembler.h \ - src/common/dwarf/dwarf2diehandler.cc \ - src/common/dwarf/dwarf2diehandler_unittest.cc \ - src/common/dwarf/dwarf2reader.cc \ - src/common/dwarf/dwarf2reader.h src/common/dwarf/elf_reader.cc \ - src/common/dwarf/elf_reader.h \ - src/common/dwarf/dwarf2reader_cfi_unittest.cc \ - src/common/dwarf/dwarf2reader_die_unittest.cc \ - src/common/dwarf/dwarf2reader_test_common.h \ - src/common/linux/crc32.cc src/common/linux/dump_symbols.cc \ - src/common/linux/dump_symbols_unittest.cc \ - src/common/linux/elf_core_dump.cc \ - src/common/linux/elf_core_dump_unittest.cc \ - src/common/linux/elf_symbols_to_module.cc \ - src/common/linux/elf_symbols_to_module_unittest.cc \ - src/common/linux/elfutils.cc src/common/linux/file_id.cc \ - src/common/linux/file_id_unittest.cc \ - src/common/linux/linux_libc_support.cc \ - src/common/linux/memory_mapped_file.cc \ - src/common/linux/memory_mapped_file_unittest.cc \ - src/common/linux/safe_readlink.cc \ - src/common/linux/safe_readlink_unittest.cc \ - src/common/linux/synth_elf.cc \ - src/common/linux/synth_elf_unittest.cc \ - src/common/linux/tests/crash_generator.cc \ - src/common/linux/tests/crash_generator.h \ - src/common/testdata/func-line-pairing.h \ - src/common/tests/file_utils.cc -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_common_dumper_unittest_OBJECTS = src/common/dumper_unittest-byte_cursor_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-convert_UTF.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-dwarf_cfi_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-dwarf_cfi_to_module_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-dwarf_cu_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-dwarf_cu_to_module_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-dwarf_line_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-dwarf_line_to_module_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-dwarf_range_list_handler.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-language.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-memory_range_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-module_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-path_helper.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-stabs_reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-stabs_reader_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-stabs_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-stabs_to_module_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-string_conversion.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-string_conversion_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest-test_assembler.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dumper_unittest-bytereader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dumper_unittest-bytereader_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dumper_unittest-cfi_assembler.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dumper_unittest-dwarf2diehandler.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dumper_unittest-dwarf2diehandler_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dumper_unittest-dwarf2reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dumper_unittest-elf_reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dumper_unittest-dwarf2reader_cfi_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dumper_unittest-dwarf2reader_die_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-crc32.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-dump_symbols.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-dump_symbols_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-elf_core_dump.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-elf_core_dump_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-elf_symbols_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-elf_symbols_to_module_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-elfutils.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-file_id.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-file_id_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-linux_libc_support.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-memory_mapped_file.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-memory_mapped_file_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-safe_readlink.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-safe_readlink_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-synth_elf.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dumper_unittest-synth_elf_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tests/dumper_unittest-crash_generator.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tests/dumper_unittest-file_utils.$(OBJEXT) +am_src_common_dumper_unittest_OBJECTS = \ + src/common/dumper_unittest-byte_cursor_unittest.$(OBJEXT) \ + src/common/dumper_unittest-convert_UTF.$(OBJEXT) \ + src/common/dumper_unittest-dwarf_cfi_to_module.$(OBJEXT) \ + src/common/dumper_unittest-dwarf_cfi_to_module_unittest.$(OBJEXT) \ + src/common/dumper_unittest-dwarf_cu_to_module.$(OBJEXT) \ + src/common/dumper_unittest-dwarf_cu_to_module_unittest.$(OBJEXT) \ + src/common/dumper_unittest-dwarf_line_to_module.$(OBJEXT) \ + src/common/dumper_unittest-dwarf_line_to_module_unittest.$(OBJEXT) \ + src/common/dumper_unittest-dwarf_range_list_handler.$(OBJEXT) \ + src/common/dumper_unittest-language.$(OBJEXT) \ + src/common/dumper_unittest-memory_range_unittest.$(OBJEXT) \ + src/common/dumper_unittest-module.$(OBJEXT) \ + src/common/dumper_unittest-module_unittest.$(OBJEXT) \ + src/common/dumper_unittest-path_helper.$(OBJEXT) \ + src/common/dumper_unittest-stabs_reader.$(OBJEXT) \ + src/common/dumper_unittest-stabs_reader_unittest.$(OBJEXT) \ + src/common/dumper_unittest-stabs_to_module.$(OBJEXT) \ + src/common/dumper_unittest-stabs_to_module_unittest.$(OBJEXT) \ + src/common/dumper_unittest-string_conversion.$(OBJEXT) \ + src/common/dumper_unittest-string_conversion_unittest.$(OBJEXT) \ + src/common/dumper_unittest-test_assembler.$(OBJEXT) \ + src/common/dwarf/dumper_unittest-bytereader.$(OBJEXT) \ + src/common/dwarf/dumper_unittest-bytereader_unittest.$(OBJEXT) \ + src/common/dwarf/dumper_unittest-cfi_assembler.$(OBJEXT) \ + src/common/dwarf/dumper_unittest-dwarf2diehandler.$(OBJEXT) \ + src/common/dwarf/dumper_unittest-dwarf2diehandler_unittest.$(OBJEXT) \ + src/common/dwarf/dumper_unittest-dwarf2reader.$(OBJEXT) \ + src/common/dwarf/dumper_unittest-elf_reader.$(OBJEXT) \ + src/common/dwarf/dumper_unittest-dwarf2reader_cfi_unittest.$(OBJEXT) \ + src/common/dwarf/dumper_unittest-dwarf2reader_die_unittest.$(OBJEXT) \ + src/common/linux/dumper_unittest-crc32.$(OBJEXT) \ + src/common/linux/dumper_unittest-dump_symbols.$(OBJEXT) \ + src/common/linux/dumper_unittest-dump_symbols_unittest.$(OBJEXT) \ + src/common/linux/dumper_unittest-elf_core_dump.$(OBJEXT) \ + src/common/linux/dumper_unittest-elf_core_dump_unittest.$(OBJEXT) \ + src/common/linux/dumper_unittest-elf_symbols_to_module.$(OBJEXT) \ + src/common/linux/dumper_unittest-elf_symbols_to_module_unittest.$(OBJEXT) \ + src/common/linux/dumper_unittest-elfutils.$(OBJEXT) \ + src/common/linux/dumper_unittest-file_id.$(OBJEXT) \ + src/common/linux/dumper_unittest-file_id_unittest.$(OBJEXT) \ + src/common/linux/dumper_unittest-linux_libc_support.$(OBJEXT) \ + src/common/linux/dumper_unittest-memory_mapped_file.$(OBJEXT) \ + src/common/linux/dumper_unittest-memory_mapped_file_unittest.$(OBJEXT) \ + src/common/linux/dumper_unittest-safe_readlink.$(OBJEXT) \ + src/common/linux/dumper_unittest-safe_readlink_unittest.$(OBJEXT) \ + src/common/linux/dumper_unittest-synth_elf.$(OBJEXT) \ + src/common/linux/dumper_unittest-synth_elf_unittest.$(OBJEXT) \ + src/common/linux/tests/dumper_unittest-crash_generator.$(OBJEXT) \ + src/common/tests/dumper_unittest-file_utils.$(OBJEXT) src_common_dumper_unittest_OBJECTS = \ $(am_src_common_dumper_unittest_OBJECTS) -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_dumper_unittest_DEPENDENCIES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_2) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) -am__src_common_dwarf_dwarf2reader_lineinfo_unittest_SOURCES_DIST = \ - src/common/dwarf/dwarf2reader.h \ - src/common/dwarf/dwarf2reader_lineinfo_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_common_dwarf_dwarf2reader_lineinfo_unittest_OBJECTS = src/common/dwarf/dwarf2reader_lineinfo_unittest-dwarf2reader_lineinfo_unittest.$(OBJEXT) +src_common_dumper_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_common_dwarf_dwarf2reader_lineinfo_unittest_OBJECTS = src/common/dwarf/dwarf2reader_lineinfo_unittest-dwarf2reader_lineinfo_unittest.$(OBJEXT) src_common_dwarf_dwarf2reader_lineinfo_unittest_OBJECTS = \ $(am_src_common_dwarf_dwarf2reader_lineinfo_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_common_dwarf_dwarf2reader_lineinfo_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/bytereader.o \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/dwarf2reader.o \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/elf_reader.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_common_dwarf_dwarf2reader_splitfunctions_unittest_SOURCES_DIST = \ - src/common/dwarf/dwarf2reader.h \ - src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_common_dwarf_dwarf2reader_splitfunctions_unittest_OBJECTS = src/common/dwarf/dwarf2reader_splitfunctions_unittest-dwarf2reader_splitfunctions_unittest.$(OBJEXT) +src_common_dwarf_dwarf2reader_lineinfo_unittest_DEPENDENCIES = \ + src/common/dwarf/bytereader.o src/common/dwarf/dwarf2reader.o \ + src/common/dwarf/elf_reader.o $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_common_dwarf_dwarf2reader_splitfunctions_unittest_OBJECTS = src/common/dwarf/dwarf2reader_splitfunctions_unittest-dwarf2reader_splitfunctions_unittest.$(OBJEXT) src_common_dwarf_dwarf2reader_splitfunctions_unittest_OBJECTS = $(am_src_common_dwarf_dwarf2reader_splitfunctions_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_common_dwarf_dwarf2reader_splitfunctions_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/bytereader.o \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/dwarf2reader.o \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/elf_reader.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_common_linux_google_crashdump_uploader_test_SOURCES_DIST = \ - src/common/linux/google_crashdump_uploader.cc \ - src/common/linux/google_crashdump_uploader_test.cc \ - src/common/linux/libcurl_wrapper.cc -@LINUX_HOST_TRUE@am_src_common_linux_google_crashdump_uploader_test_OBJECTS = src/common/linux/google_crashdump_uploader_test-google_crashdump_uploader.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/linux/google_crashdump_uploader_test-google_crashdump_uploader_test.$(OBJEXT) \ -@LINUX_HOST_TRUE@ src/common/linux/google_crashdump_uploader_test-libcurl_wrapper.$(OBJEXT) +src_common_dwarf_dwarf2reader_splitfunctions_unittest_DEPENDENCIES = \ + src/common/dwarf/bytereader.o src/common/dwarf/dwarf2reader.o \ + src/common/dwarf/elf_reader.o $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_common_linux_google_crashdump_uploader_test_OBJECTS = src/common/linux/google_crashdump_uploader_test-google_crashdump_uploader.$(OBJEXT) \ + src/common/linux/google_crashdump_uploader_test-google_crashdump_uploader_test.$(OBJEXT) \ + src/common/linux/google_crashdump_uploader_test-libcurl_wrapper.$(OBJEXT) src_common_linux_google_crashdump_uploader_test_OBJECTS = \ $(am_src_common_linux_google_crashdump_uploader_test_OBJECTS) -@LINUX_HOST_TRUE@src_common_linux_google_crashdump_uploader_test_DEPENDENCIES = \ -@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ -@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) -am__src_common_mac_macho_reader_unittest_SOURCES_DIST = \ - src/common/dwarf_cfi_to_module.cc \ - src/common/dwarf_cu_to_module.cc \ - src/common/dwarf_line_to_module.cc src/common/language.cc \ - src/common/md5.cc src/common/module.cc \ - src/common/path_helper.cc src/common/stabs_reader.cc \ - src/common/stabs_to_module.cc src/common/test_assembler.cc \ - src/common/dwarf/bytereader.cc \ - src/common/dwarf/cfi_assembler.cc \ - src/common/dwarf/dwarf2diehandler.cc \ - src/common/dwarf/dwarf2reader.cc \ - src/common/dwarf/elf_reader.cc \ - src/common/mac/arch_utilities.cc src/common/mac/file_id.cc \ - src/common/mac/macho_id.cc src/common/mac/macho_reader.cc \ - src/common/mac/macho_reader_unittest.cc \ - src/common/mac/macho_utilities.cc \ - src/common/mac/macho_walker.cc src/common/tests/file_utils.cc -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_common_mac_macho_reader_unittest_OBJECTS = src/common/mac_macho_reader_unittest-dwarf_cfi_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac_macho_reader_unittest-dwarf_cu_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac_macho_reader_unittest-dwarf_line_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac_macho_reader_unittest-language.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac_macho_reader_unittest-md5.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac_macho_reader_unittest-module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac_macho_reader_unittest-path_helper.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac_macho_reader_unittest-stabs_reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac_macho_reader_unittest-stabs_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac_macho_reader_unittest-test_assembler.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/mac_macho_reader_unittest-bytereader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/mac_macho_reader_unittest-cfi_assembler.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/mac_macho_reader_unittest-dwarf2diehandler.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/mac_macho_reader_unittest-dwarf2reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/mac_macho_reader_unittest-elf_reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader_unittest-arch_utilities.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader_unittest-file_id.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader_unittest-macho_id.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader_unittest-macho_reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader_unittest-macho_reader_unittest.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader_unittest-macho_utilities.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader_unittest-macho_walker.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tests/mac_macho_reader_unittest-file_utils.$(OBJEXT) +src_common_linux_google_crashdump_uploader_test_DEPENDENCIES = \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_common_linux_scoped_pipe_unittest_OBJECTS = src/common/linux/scoped_pipe_unittest-scoped_pipe_unittest.$(OBJEXT) +src_common_linux_scoped_pipe_unittest_OBJECTS = \ + $(am_src_common_linux_scoped_pipe_unittest_OBJECTS) +src_common_linux_scoped_pipe_unittest_DEPENDENCIES = \ + src/common/linux/scoped_pipe.o $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_common_linux_scoped_tmpfile_unittest_OBJECTS = src/common/linux/scoped_tmpfile_unittest-scoped_tmpfile_unittest.$(OBJEXT) +src_common_linux_scoped_tmpfile_unittest_OBJECTS = \ + $(am_src_common_linux_scoped_tmpfile_unittest_OBJECTS) +src_common_linux_scoped_tmpfile_unittest_DEPENDENCIES = \ + src/common/linux/scoped_tmpfile.o $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_common_mac_macho_reader_unittest_OBJECTS = src/common/mac_macho_reader_unittest-dwarf_cfi_to_module.$(OBJEXT) \ + src/common/mac_macho_reader_unittest-dwarf_cu_to_module.$(OBJEXT) \ + src/common/mac_macho_reader_unittest-dwarf_line_to_module.$(OBJEXT) \ + src/common/mac_macho_reader_unittest-language.$(OBJEXT) \ + src/common/mac_macho_reader_unittest-md5.$(OBJEXT) \ + src/common/mac_macho_reader_unittest-module.$(OBJEXT) \ + src/common/mac_macho_reader_unittest-path_helper.$(OBJEXT) \ + src/common/mac_macho_reader_unittest-stabs_reader.$(OBJEXT) \ + src/common/mac_macho_reader_unittest-stabs_to_module.$(OBJEXT) \ + src/common/mac_macho_reader_unittest-test_assembler.$(OBJEXT) \ + src/common/dwarf/mac_macho_reader_unittest-bytereader.$(OBJEXT) \ + src/common/dwarf/mac_macho_reader_unittest-cfi_assembler.$(OBJEXT) \ + src/common/dwarf/mac_macho_reader_unittest-dwarf2diehandler.$(OBJEXT) \ + src/common/dwarf/mac_macho_reader_unittest-dwarf2reader.$(OBJEXT) \ + src/common/dwarf/mac_macho_reader_unittest-elf_reader.$(OBJEXT) \ + src/common/mac/macho_reader_unittest-arch_utilities.$(OBJEXT) \ + src/common/mac/macho_reader_unittest-file_id.$(OBJEXT) \ + src/common/mac/macho_reader_unittest-macho_id.$(OBJEXT) \ + src/common/mac/macho_reader_unittest-macho_reader.$(OBJEXT) \ + src/common/mac/macho_reader_unittest-macho_reader_unittest.$(OBJEXT) \ + src/common/mac/macho_reader_unittest-macho_utilities.$(OBJEXT) \ + src/common/mac/macho_reader_unittest-macho_walker.$(OBJEXT) \ + src/common/tests/mac_macho_reader_unittest-file_utils.$(OBJEXT) src_common_mac_macho_reader_unittest_OBJECTS = \ $(am_src_common_mac_macho_reader_unittest_OBJECTS) -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_mac_macho_reader_unittest_DEPENDENCIES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_2) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) -am__src_common_test_assembler_unittest_SOURCES_DIST = \ - src/common/test_assembler.cc src/common/test_assembler.h \ - src/common/test_assembler_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_common_test_assembler_unittest_OBJECTS = src/common/test_assembler_unittest-test_assembler.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler_unittest-test_assembler_unittest.$(OBJEXT) +src_common_mac_macho_reader_unittest_DEPENDENCIES = \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_common_safe_math_unittest_OBJECTS = \ + src/common/safe_math_unittest-safe_math_unittest.$(OBJEXT) +src_common_safe_math_unittest_OBJECTS = \ + $(am_src_common_safe_math_unittest_OBJECTS) +src_common_safe_math_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_common_test_assembler_unittest_OBJECTS = \ + src/common/test_assembler_unittest-test_assembler.$(OBJEXT) \ + src/common/test_assembler_unittest-test_assembler_unittest.$(OBJEXT) src_common_test_assembler_unittest_OBJECTS = \ $(am_src_common_test_assembler_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_common_test_assembler_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_address_map_unittest_SOURCES_DIST = \ - src/processor/address_map_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_address_map_unittest_OBJECTS = src/processor/address_map_unittest.$(OBJEXT) +src_common_test_assembler_unittest_DEPENDENCIES = \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_address_map_unittest_OBJECTS = \ + src/processor/address_map_unittest.$(OBJEXT) src_processor_address_map_unittest_OBJECTS = \ $(am_src_processor_address_map_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_address_map_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o -am__src_processor_basic_source_line_resolver_unittest_SOURCES_DIST = \ - src/processor/basic_source_line_resolver_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_basic_source_line_resolver_unittest_OBJECTS = src/processor/basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.$(OBJEXT) +src_processor_address_map_unittest_DEPENDENCIES = \ + src/processor/logging.o src/processor/pathname_stripper.o +am_src_processor_basic_source_line_resolver_unittest_OBJECTS = src/processor/basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.$(OBJEXT) src_processor_basic_source_line_resolver_unittest_OBJECTS = $(am_src_processor_basic_source_line_resolver_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_basic_source_line_resolver_unittest_DEPENDENCIES = src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_cfi_frame_info_unittest_SOURCES_DIST = \ - src/processor/cfi_frame_info_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_cfi_frame_info_unittest_OBJECTS = src/processor/cfi_frame_info_unittest-cfi_frame_info_unittest.$(OBJEXT) +src_processor_basic_source_line_resolver_unittest_DEPENDENCIES = \ + src/processor/basic_source_line_resolver.o \ + src/processor/cfi_frame_info.o \ + src/processor/pathname_stripper.o src/processor/logging.o \ + src/processor/source_line_resolver_base.o \ + src/processor/tokenize.o $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_processor_cfi_frame_info_unittest_OBJECTS = src/processor/cfi_frame_info_unittest-cfi_frame_info_unittest.$(OBJEXT) src_processor_cfi_frame_info_unittest_OBJECTS = \ $(am_src_processor_cfi_frame_info_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_contained_range_map_unittest_SOURCES_DIST = \ - src/processor/contained_range_map_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_contained_range_map_unittest_OBJECTS = src/processor/contained_range_map_unittest.$(OBJEXT) +src_processor_cfi_frame_info_unittest_DEPENDENCIES = \ + src/processor/cfi_frame_info.o src/processor/logging.o \ + src/processor/pathname_stripper.o $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_processor_contained_range_map_unittest_OBJECTS = \ + src/processor/contained_range_map_unittest.$(OBJEXT) src_processor_contained_range_map_unittest_OBJECTS = \ $(am_src_processor_contained_range_map_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_contained_range_map_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o -am__src_processor_disassembler_x86_unittest_SOURCES_DIST = \ - src/processor/disassembler_x86_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_disassembler_x86_unittest_OBJECTS = src/processor/disassembler_x86_unittest-disassembler_x86_unittest.$(OBJEXT) +src_processor_contained_range_map_unittest_DEPENDENCIES = \ + src/processor/logging.o src/processor/pathname_stripper.o +am_src_processor_disassembler_objdump_unittest_OBJECTS = src/processor/disassembler_objdump_unittest-disassembler_objdump_unittest.$(OBJEXT) +src_processor_disassembler_objdump_unittest_OBJECTS = \ + $(am_src_processor_disassembler_objdump_unittest_OBJECTS) +src_processor_disassembler_objdump_unittest_DEPENDENCIES = \ + src/common/linux/scoped_pipe.o \ + src/common/linux/scoped_tmpfile.o \ + src/processor/disassembler_objdump.o \ + src/processor/dump_context.o src/processor/dump_object.o \ + src/processor/logging.o src/processor/pathname_stripper.o \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_disassembler_x86_unittest_OBJECTS = src/processor/disassembler_x86_unittest-disassembler_x86_unittest.$(OBJEXT) src_processor_disassembler_x86_unittest_OBJECTS = \ $(am_src_processor_disassembler_x86_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_disassembler_x86_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_exploitability_unittest_SOURCES_DIST = \ - src/processor/exploitability_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_exploitability_unittest_OBJECTS = src/processor/exploitability_unittest-exploitability_unittest.$(OBJEXT) +src_processor_disassembler_x86_unittest_DEPENDENCIES = \ + src/processor/disassembler_x86.o \ + src/third_party/libdisasm/libdisasm.a $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_processor_exploitability_unittest_OBJECTS = src/processor/exploitability_unittest-exploitability_unittest.$(OBJEXT) src_processor_exploitability_unittest_OBJECTS = \ $(am_src_processor_exploitability_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_exploitability_unittest_DEPENDENCIES = src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_fast_source_line_resolver_unittest_SOURCES_DIST = \ - src/processor/fast_source_line_resolver_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_fast_source_line_resolver_unittest_OBJECTS = src/processor/fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.$(OBJEXT) +src_processor_exploitability_unittest_DEPENDENCIES = \ + src/processor/convert_old_arm64_context.o \ + src/processor/minidump_processor.o \ + src/processor/process_state.o src/processor/disassembler_x86.o \ + src/processor/exploitability.o \ + src/processor/exploitability_linux.o \ + src/processor/exploitability_win.o \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o src/processor/cfi_frame_info.o \ + src/processor/dump_context.o src/processor/dump_object.o \ + src/processor/logging.o src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/proc_maps_linux.o \ + src/processor/simple_symbol_supplier.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o \ + src/processor/symbolic_constants_win.o \ + src/processor/tokenize.o src/third_party/libdisasm/libdisasm.a \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__append_27) +am_src_processor_fast_source_line_resolver_unittest_OBJECTS = src/processor/fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.$(OBJEXT) src_processor_fast_source_line_resolver_unittest_OBJECTS = $(am_src_processor_fast_source_line_resolver_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_DEPENDENCIES = src/processor/fast_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_map_serializers_unittest_SOURCES_DIST = \ - src/processor/map_serializers_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_map_serializers_unittest_OBJECTS = src/processor/map_serializers_unittest-map_serializers_unittest.$(OBJEXT) +src_processor_fast_source_line_resolver_unittest_DEPENDENCIES = \ + src/processor/fast_source_line_resolver.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/cfi_frame_info.o src/processor/module_comparer.o \ + src/processor/module_serializer.o \ + src/processor/pathname_stripper.o src/processor/logging.o \ + src/processor/source_line_resolver_base.o \ + src/processor/tokenize.o $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_processor_map_serializers_unittest_OBJECTS = src/processor/map_serializers_unittest-map_serializers_unittest.$(OBJEXT) src_processor_map_serializers_unittest_OBJECTS = \ $(am_src_processor_map_serializers_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_map_serializers_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_microdump_processor_unittest_SOURCES_DIST = \ - src/processor/microdump_processor_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_microdump_processor_unittest_OBJECTS = src/processor/microdump_processor_unittest-microdump_processor_unittest.$(OBJEXT) +src_processor_map_serializers_unittest_DEPENDENCIES = \ + src/processor/logging.o src/processor/pathname_stripper.o \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_microdump_processor_unittest_OBJECTS = src/processor/microdump_processor_unittest-microdump_processor_unittest.$(OBJEXT) src_processor_microdump_processor_unittest_OBJECTS = \ $(am_src_processor_microdump_processor_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_microdump_processor_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_microdump_stackwalk_SOURCES_DIST = \ - src/processor/microdump_stackwalk.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_microdump_stackwalk_OBJECTS = src/processor/microdump_stackwalk.$(OBJEXT) +src_processor_microdump_processor_unittest_DEPENDENCIES = \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/cfi_frame_info.o src/processor/dump_context.o \ + src/processor/dump_object.o src/processor/logging.o \ + src/processor/microdump.o src/processor/microdump_processor.o \ + src/processor/pathname_stripper.o \ + src/processor/process_state.o \ + src/processor/simple_symbol_supplier.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o src/processor/tokenize.o \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__append_28) +am_src_processor_microdump_stackwalk_OBJECTS = \ + src/processor/microdump_stackwalk.$(OBJEXT) src_processor_microdump_stackwalk_OBJECTS = \ $(am_src_processor_microdump_stackwalk_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_microdump_stackwalk_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/path_helper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a -am__src_processor_minidump_dump_SOURCES_DIST = \ - src/processor/minidump_dump.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_dump_OBJECTS = src/processor/minidump_dump.$(OBJEXT) +src_processor_microdump_stackwalk_DEPENDENCIES = \ + src/common/path_helper.o src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/cfi_frame_info.o \ + src/processor/disassembler_x86.o src/processor/dump_context.o \ + src/processor/dump_object.o src/processor/logging.o \ + src/processor/microdump.o src/processor/microdump_processor.o \ + src/processor/pathname_stripper.o \ + src/processor/process_state.o \ + src/processor/simple_symbol_supplier.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalk_common.o src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o src/processor/tokenize.o \ + src/third_party/libdisasm/libdisasm.a $(am__append_31) +am_src_processor_minidump_dump_OBJECTS = \ + src/processor/minidump_dump.$(OBJEXT) src_processor_minidump_dump_OBJECTS = \ $(am_src_processor_minidump_dump_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_dump_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o -am__src_processor_minidump_processor_unittest_SOURCES_DIST = \ - src/processor/minidump_processor_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_processor_unittest_OBJECTS = src/processor/minidump_processor_unittest-minidump_processor_unittest.$(OBJEXT) +src_processor_minidump_dump_DEPENDENCIES = src/common/path_helper.o \ + src/processor/basic_code_modules.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/dump_context.o src/processor/dump_object.o \ + src/processor/logging.o src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/proc_maps_linux.o +am_src_processor_minidump_processor_unittest_OBJECTS = src/processor/minidump_processor_unittest-minidump_processor_unittest.$(OBJEXT) src_processor_minidump_processor_unittest_OBJECTS = \ $(am_src_processor_minidump_processor_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_minidump_stackwalk_SOURCES_DIST = \ - src/processor/minidump_stackwalk.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_stackwalk_OBJECTS = src/processor/minidump_stackwalk.$(OBJEXT) +src_processor_minidump_processor_unittest_DEPENDENCIES = \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o src/processor/cfi_frame_info.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/disassembler_x86.o src/processor/dump_context.o \ + src/processor/dump_object.o src/processor/exploitability.o \ + src/processor/exploitability_linux.o \ + src/processor/exploitability_win.o src/processor/logging.o \ + src/processor/minidump_processor.o src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/process_state.o src/processor/proc_maps_linux.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o \ + src/processor/symbolic_constants_win.o \ + src/processor/tokenize.o src/third_party/libdisasm/libdisasm.a \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__append_29) +am_src_processor_minidump_stackwalk_OBJECTS = \ + src/processor/minidump_stackwalk.$(OBJEXT) src_processor_minidump_stackwalk_OBJECTS = \ $(am_src_processor_minidump_stackwalk_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/path_helper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a -am__src_processor_minidump_unittest_SOURCES_DIST = \ - src/common/test_assembler.cc \ - src/processor/minidump_unittest.cc \ - src/processor/synth_minidump.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_unittest_OBJECTS = src/common/processor_minidump_unittest-test_assembler.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_unittest-minidump_unittest.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_unittest-synth_minidump.$(OBJEXT) +src_processor_minidump_stackwalk_DEPENDENCIES = \ + src/common/path_helper.o src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o src/processor/cfi_frame_info.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/disassembler_x86.o src/processor/dump_context.o \ + src/processor/dump_object.o src/processor/exploitability.o \ + src/processor/exploitability_linux.o \ + src/processor/exploitability_win.o src/processor/logging.o \ + src/processor/minidump.o src/processor/minidump_processor.o \ + src/processor/pathname_stripper.o \ + src/processor/process_state.o src/processor/proc_maps_linux.o \ + src/processor/simple_symbol_supplier.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalk_common.o src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o \ + src/processor/symbolic_constants_win.o \ + src/processor/tokenize.o src/third_party/libdisasm/libdisasm.a \ + $(am__append_32) +am_src_processor_minidump_unittest_OBJECTS = src/common/processor_minidump_unittest-test_assembler.$(OBJEXT) \ + src/processor/minidump_unittest-minidump_unittest.$(OBJEXT) \ + src/processor/minidump_unittest-synth_minidump.$(OBJEXT) src_processor_minidump_unittest_OBJECTS = \ $(am_src_processor_minidump_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_pathname_stripper_unittest_SOURCES_DIST = \ - src/processor/pathname_stripper_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_pathname_stripper_unittest_OBJECTS = src/processor/pathname_stripper_unittest.$(OBJEXT) +src_processor_minidump_unittest_DEPENDENCIES = \ + src/processor/basic_code_modules.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/dump_context.o src/processor/dump_object.o \ + src/processor/logging.o src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/proc_maps_linux.o $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_processor_pathname_stripper_unittest_OBJECTS = \ + src/processor/pathname_stripper_unittest.$(OBJEXT) src_processor_pathname_stripper_unittest_OBJECTS = \ $(am_src_processor_pathname_stripper_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_pathname_stripper_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_postfix_evaluator_unittest_SOURCES_DIST = \ - src/processor/postfix_evaluator_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_postfix_evaluator_unittest_OBJECTS = src/processor/postfix_evaluator_unittest.$(OBJEXT) +src_processor_pathname_stripper_unittest_DEPENDENCIES = \ + src/processor/pathname_stripper.o $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_postfix_evaluator_unittest_OBJECTS = \ + src/processor/postfix_evaluator_unittest.$(OBJEXT) src_processor_postfix_evaluator_unittest_OBJECTS = \ $(am_src_processor_postfix_evaluator_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_postfix_evaluator_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_proc_maps_linux_unittest_SOURCES_DIST = \ - src/processor/proc_maps_linux.cc \ - src/processor/proc_maps_linux_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_proc_maps_linux_unittest_OBJECTS = src/processor/proc_maps_linux_unittest-proc_maps_linux.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux_unittest-proc_maps_linux_unittest.$(OBJEXT) +src_processor_postfix_evaluator_unittest_DEPENDENCIES = \ + src/processor/logging.o src/processor/pathname_stripper.o \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_processor_proc_maps_linux_unittest_OBJECTS = src/processor/proc_maps_linux_unittest-proc_maps_linux.$(OBJEXT) \ + src/processor/proc_maps_linux_unittest-proc_maps_linux_unittest.$(OBJEXT) src_processor_proc_maps_linux_unittest_OBJECTS = \ $(am_src_processor_proc_maps_linux_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_proc_maps_linux_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_range_map_truncate_lower_unittest_SOURCES_DIST = \ - src/processor/range_map_truncate_lower_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_range_map_truncate_lower_unittest_OBJECTS = src/processor/range_map_truncate_lower_unittest-range_map_truncate_lower_unittest.$(OBJEXT) +src_processor_proc_maps_linux_unittest_DEPENDENCIES = \ + src/processor/logging.o src/processor/pathname_stripper.o \ + src/third_party/libdisasm/libdisasm.a $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_processor_range_map_truncate_lower_unittest_OBJECTS = src/processor/range_map_truncate_lower_unittest-range_map_truncate_lower_unittest.$(OBJEXT) src_processor_range_map_truncate_lower_unittest_OBJECTS = \ $(am_src_processor_range_map_truncate_lower_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_range_map_truncate_lower_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_range_map_truncate_upper_unittest_SOURCES_DIST = \ - src/processor/range_map_truncate_upper_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_range_map_truncate_upper_unittest_OBJECTS = src/processor/range_map_truncate_upper_unittest-range_map_truncate_upper_unittest.$(OBJEXT) +src_processor_range_map_truncate_lower_unittest_DEPENDENCIES = \ + src/processor/logging.o src/processor/pathname_stripper.o \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_range_map_truncate_upper_unittest_OBJECTS = src/processor/range_map_truncate_upper_unittest-range_map_truncate_upper_unittest.$(OBJEXT) src_processor_range_map_truncate_upper_unittest_OBJECTS = \ $(am_src_processor_range_map_truncate_upper_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_range_map_truncate_upper_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_range_map_unittest_SOURCES_DIST = \ - src/processor/range_map_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_range_map_unittest_OBJECTS = src/processor/range_map_unittest.$(OBJEXT) +src_processor_range_map_truncate_upper_unittest_DEPENDENCIES = \ + src/processor/logging.o src/processor/pathname_stripper.o \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_range_map_unittest_OBJECTS = \ + src/processor/range_map_unittest.$(OBJEXT) src_processor_range_map_unittest_OBJECTS = \ $(am_src_processor_range_map_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_range_map_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_stackwalker_address_list_unittest_SOURCES_DIST = \ - src/common/test_assembler.cc \ - src/processor/stackwalker_address_list_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_address_list_unittest_OBJECTS = src/common/processor_stackwalker_address_list_unittest-test_assembler.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list_unittest-stackwalker_address_list_unittest.$(OBJEXT) +src_processor_range_map_unittest_DEPENDENCIES = \ + src/processor/logging.o src/processor/pathname_stripper.o \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_src_processor_stackwalker_address_list_unittest_OBJECTS = src/common/processor_stackwalker_address_list_unittest-test_assembler.$(OBJEXT) \ + src/processor/stackwalker_address_list_unittest-stackwalker_address_list_unittest.$(OBJEXT) src_processor_stackwalker_address_list_unittest_OBJECTS = \ $(am_src_processor_stackwalker_address_list_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_address_list_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_stackwalker_amd64_unittest_SOURCES_DIST = \ - src/common/test_assembler.cc \ - src/processor/stackwalker_amd64_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_amd64_unittest_OBJECTS = src/common/processor_stackwalker_amd64_unittest-test_assembler.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64_unittest-stackwalker_amd64_unittest.$(OBJEXT) +src_processor_stackwalker_address_list_unittest_DEPENDENCIES = \ + src/libbreakpad.a $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_stackwalker_amd64_unittest_OBJECTS = src/common/processor_stackwalker_amd64_unittest-test_assembler.$(OBJEXT) \ + src/processor/stackwalker_amd64_unittest-stackwalker_amd64_unittest.$(OBJEXT) src_processor_stackwalker_amd64_unittest_OBJECTS = \ $(am_src_processor_stackwalker_amd64_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_amd64_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_stackwalker_arm64_unittest_SOURCES_DIST = \ - src/common/test_assembler.cc \ - src/processor/stackwalker_arm64_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_arm64_unittest_OBJECTS = src/common/processor_stackwalker_arm64_unittest-test_assembler.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64_unittest-stackwalker_arm64_unittest.$(OBJEXT) +src_processor_stackwalker_amd64_unittest_DEPENDENCIES = \ + src/libbreakpad.a $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_stackwalker_arm64_unittest_OBJECTS = src/common/processor_stackwalker_arm64_unittest-test_assembler.$(OBJEXT) \ + src/processor/stackwalker_arm64_unittest-stackwalker_arm64_unittest.$(OBJEXT) src_processor_stackwalker_arm64_unittest_OBJECTS = \ $(am_src_processor_stackwalker_arm64_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm64_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_stackwalker_arm_unittest_SOURCES_DIST = \ - src/common/test_assembler.cc \ - src/processor/stackwalker_arm_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_arm_unittest_OBJECTS = src/common/processor_stackwalker_arm_unittest-test_assembler.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm_unittest-stackwalker_arm_unittest.$(OBJEXT) +src_processor_stackwalker_arm64_unittest_DEPENDENCIES = \ + src/libbreakpad.a $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_stackwalker_arm_unittest_OBJECTS = src/common/processor_stackwalker_arm_unittest-test_assembler.$(OBJEXT) \ + src/processor/stackwalker_arm_unittest-stackwalker_arm_unittest.$(OBJEXT) src_processor_stackwalker_arm_unittest_OBJECTS = \ $(am_src_processor_stackwalker_arm_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_stackwalker_mips64_unittest_SOURCES_DIST = \ - src/common/test_assembler.cc \ - src/processor/stackwalker_mips64_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_mips64_unittest_OBJECTS = src/common/processor_stackwalker_mips64_unittest-test_assembler.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips64_unittest-stackwalker_mips64_unittest.$(OBJEXT) +src_processor_stackwalker_arm_unittest_DEPENDENCIES = \ + src/libbreakpad.a $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_stackwalker_mips64_unittest_OBJECTS = src/common/processor_stackwalker_mips64_unittest-test_assembler.$(OBJEXT) \ + src/processor/stackwalker_mips64_unittest-stackwalker_mips64_unittest.$(OBJEXT) src_processor_stackwalker_mips64_unittest_OBJECTS = \ $(am_src_processor_stackwalker_mips64_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips64_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_stackwalker_mips_unittest_SOURCES_DIST = \ - src/common/test_assembler.cc \ - src/processor/stackwalker_mips_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_mips_unittest_OBJECTS = src/common/processor_stackwalker_mips_unittest-test_assembler.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips_unittest-stackwalker_mips_unittest.$(OBJEXT) +src_processor_stackwalker_mips64_unittest_DEPENDENCIES = \ + src/libbreakpad.a $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_stackwalker_mips_unittest_OBJECTS = src/common/processor_stackwalker_mips_unittest-test_assembler.$(OBJEXT) \ + src/processor/stackwalker_mips_unittest-stackwalker_mips_unittest.$(OBJEXT) src_processor_stackwalker_mips_unittest_OBJECTS = \ $(am_src_processor_stackwalker_mips_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_stackwalker_selftest_SOURCES_DIST = \ - src/processor/stackwalker_selftest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_selftest_OBJECTS = src/processor/stackwalker_selftest.$(OBJEXT) +src_processor_stackwalker_mips_unittest_DEPENDENCIES = \ + src/libbreakpad.a $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_stackwalker_riscv64_unittest_OBJECTS = src/common/processor_stackwalker_riscv64_unittest-test_assembler.$(OBJEXT) \ + src/processor/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.$(OBJEXT) +src_processor_stackwalker_riscv64_unittest_OBJECTS = \ + $(am_src_processor_stackwalker_riscv64_unittest_OBJECTS) +src_processor_stackwalker_riscv64_unittest_DEPENDENCIES = \ + src/libbreakpad.a $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_stackwalker_riscv_unittest_OBJECTS = src/common/processor_stackwalker_riscv_unittest-test_assembler.$(OBJEXT) \ + src/processor/stackwalker_riscv_unittest-stackwalker_riscv_unittest.$(OBJEXT) +src_processor_stackwalker_riscv_unittest_OBJECTS = \ + $(am_src_processor_stackwalker_riscv_unittest_OBJECTS) +src_processor_stackwalker_riscv_unittest_DEPENDENCIES = \ + src/libbreakpad.a $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_stackwalker_selftest_OBJECTS = \ + src/processor/stackwalker_selftest.$(OBJEXT) src_processor_stackwalker_selftest_OBJECTS = \ $(am_src_processor_stackwalker_selftest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_selftest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_stackwalker_x86_unittest_SOURCES_DIST = \ - src/common/test_assembler.cc \ - src/processor/stackwalker_x86_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_x86_unittest_OBJECTS = src/common/processor_stackwalker_x86_unittest-test_assembler.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86_unittest-stackwalker_x86_unittest.$(OBJEXT) +src_processor_stackwalker_selftest_DEPENDENCIES = \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o src/processor/disassembler_x86.o \ + src/processor/exploitability.o \ + src/processor/exploitability_linux.o \ + src/processor/exploitability_win.o src/processor/logging.o \ + src/processor/minidump.o src/processor/pathname_stripper.o \ + src/processor/proc_maps_linux.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o src/processor/tokenize.o \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(am__append_30) +am_src_processor_stackwalker_x86_unittest_OBJECTS = src/common/processor_stackwalker_x86_unittest-test_assembler.$(OBJEXT) \ + src/processor/stackwalker_x86_unittest-stackwalker_x86_unittest.$(OBJEXT) src_processor_stackwalker_x86_unittest_OBJECTS = \ $(am_src_processor_stackwalker_x86_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_x86_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_static_address_map_unittest_SOURCES_DIST = \ - src/processor/static_address_map_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_static_address_map_unittest_OBJECTS = src/processor/static_address_map_unittest-static_address_map_unittest.$(OBJEXT) +src_processor_stackwalker_x86_unittest_DEPENDENCIES = \ + src/libbreakpad.a $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_static_address_map_unittest_OBJECTS = src/processor/static_address_map_unittest-static_address_map_unittest.$(OBJEXT) src_processor_static_address_map_unittest_OBJECTS = \ $(am_src_processor_static_address_map_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_static_address_map_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_static_contained_range_map_unittest_SOURCES_DIST = \ - src/processor/static_contained_range_map_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_static_contained_range_map_unittest_OBJECTS = src/processor/static_contained_range_map_unittest-static_contained_range_map_unittest.$(OBJEXT) +src_processor_static_address_map_unittest_DEPENDENCIES = \ + src/processor/logging.o src/processor/pathname_stripper.o \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_static_contained_range_map_unittest_OBJECTS = src/processor/static_contained_range_map_unittest-static_contained_range_map_unittest.$(OBJEXT) src_processor_static_contained_range_map_unittest_OBJECTS = $(am_src_processor_static_contained_range_map_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_static_contained_range_map_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_static_map_unittest_SOURCES_DIST = \ - src/processor/static_map_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_static_map_unittest_OBJECTS = src/processor/static_map_unittest-static_map_unittest.$(OBJEXT) +src_processor_static_contained_range_map_unittest_DEPENDENCIES = \ + src/processor/logging.o src/processor/pathname_stripper.o \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_static_map_unittest_OBJECTS = src/processor/static_map_unittest-static_map_unittest.$(OBJEXT) src_processor_static_map_unittest_OBJECTS = \ $(am_src_processor_static_map_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_static_map_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_static_range_map_unittest_SOURCES_DIST = \ - src/processor/static_range_map_unittest.cc -@DISABLE_PROCESSOR_FALSE@am_src_processor_static_range_map_unittest_OBJECTS = src/processor/static_range_map_unittest-static_range_map_unittest.$(OBJEXT) +src_processor_static_map_unittest_DEPENDENCIES = \ + src/processor/logging.o src/processor/pathname_stripper.o \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_static_range_map_unittest_OBJECTS = src/processor/static_range_map_unittest-static_range_map_unittest.$(OBJEXT) src_processor_static_range_map_unittest_OBJECTS = \ $(am_src_processor_static_range_map_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_static_range_map_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_processor_synth_minidump_unittest_SOURCES_DIST = \ - src/common/test_assembler.cc src/common/test_assembler.h \ - src/processor/synth_minidump_unittest.cc \ - src/processor/synth_minidump.cc src/processor/synth_minidump.h -@DISABLE_PROCESSOR_FALSE@am_src_processor_synth_minidump_unittest_OBJECTS = src/common/processor_synth_minidump_unittest-test_assembler.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump_unittest-synth_minidump_unittest.$(OBJEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump_unittest-synth_minidump.$(OBJEXT) +src_processor_static_range_map_unittest_DEPENDENCIES = \ + src/processor/logging.o src/processor/pathname_stripper.o \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_processor_synth_minidump_unittest_OBJECTS = src/common/processor_synth_minidump_unittest-test_assembler.$(OBJEXT) \ + src/processor/synth_minidump_unittest-synth_minidump_unittest.$(OBJEXT) \ + src/processor/synth_minidump_unittest-synth_minidump.$(OBJEXT) src_processor_synth_minidump_unittest_OBJECTS = \ $(am_src_processor_synth_minidump_unittest_OBJECTS) -@DISABLE_PROCESSOR_FALSE@src_processor_synth_minidump_unittest_DEPENDENCIES = \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ -@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) -am__src_tools_linux_core2md_core2md_SOURCES_DIST = \ - src/tools/linux/core2md/core2md.cc -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_core2md_core2md_OBJECTS = src/tools/linux/core2md/core2md.$(OBJEXT) +src_processor_synth_minidump_unittest_DEPENDENCIES = \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_tools_linux_core2md_core2md_OBJECTS = \ + src/tools/linux/core2md/core2md.$(OBJEXT) src_tools_linux_core2md_core2md_OBJECTS = \ $(am_src_tools_linux_core2md_core2md_OBJECTS) -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_core2md_core2md_DEPENDENCIES = src/client/linux/libbreakpad_client.a -am__src_tools_linux_core_handler_core_handler_SOURCES_DIST = \ - src/tools/linux/core_handler/core_handler.cc -@DISABLE_TOOLS_FALSE@@HAVE_MEMFD_CREATE_TRUE@@LINUX_HOST_TRUE@am_src_tools_linux_core_handler_core_handler_OBJECTS = src/tools/linux/core_handler/core_handler.$(OBJEXT) +src_tools_linux_core2md_core2md_DEPENDENCIES = \ + src/client/linux/libbreakpad_client.a src/common/path_helper.o +am_src_tools_linux_core_handler_core_handler_OBJECTS = \ + src/tools/linux/core_handler/core_handler.$(OBJEXT) src_tools_linux_core_handler_core_handler_OBJECTS = \ $(am_src_tools_linux_core_handler_core_handler_OBJECTS) -@DISABLE_TOOLS_FALSE@@HAVE_MEMFD_CREATE_TRUE@@LINUX_HOST_TRUE@src_tools_linux_core_handler_core_handler_DEPENDENCIES = src/client/linux/libbreakpad_client.a -am__src_tools_linux_dump_syms_dump_syms_SOURCES_DIST = \ - src/common/dwarf_cfi_to_module.cc \ - src/common/dwarf_cu_to_module.cc \ - src/common/dwarf_line_to_module.cc \ - src/common/dwarf_range_list_handler.cc src/common/language.cc \ - src/common/module.cc src/common/path_helper.cc \ - src/common/stabs_reader.cc src/common/stabs_to_module.cc \ - src/common/dwarf/bytereader.cc \ - src/common/dwarf/dwarf2diehandler.cc \ - src/common/dwarf/dwarf2reader.cc \ - src/common/dwarf/elf_reader.cc src/common/linux/crc32.cc \ - src/common/linux/dump_symbols.cc \ - src/common/linux/dump_symbols.h \ - src/common/linux/elf_symbols_to_module.cc \ - src/common/linux/elf_symbols_to_module.h \ - src/common/linux/elfutils.cc src/common/linux/file_id.cc \ - src/common/linux/linux_libc_support.cc \ - src/common/linux/memory_mapped_file.cc \ - src/common/linux/safe_readlink.cc \ - src/tools/linux/dump_syms/dump_syms.cc -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_dump_syms_dump_syms_OBJECTS = src/common/tools_linux_dump_syms_dump_syms-dwarf_cfi_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_linux_dump_syms_dump_syms-dwarf_cu_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_linux_dump_syms_dump_syms-dwarf_line_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_linux_dump_syms_dump_syms-language.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_linux_dump_syms_dump_syms-module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_linux_dump_syms_dump_syms-path_helper.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_linux_dump_syms_dump_syms-stabs_reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_linux_dump_syms_dump_syms-stabs_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/tools_linux_dump_syms_dump_syms-bytereader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/tools_linux_dump_syms_dump_syms-dwarf2diehandler.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/tools_linux_dump_syms_dump_syms-dwarf2reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/tools_linux_dump_syms_dump_syms-elf_reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tools_linux_dump_syms_dump_syms-crc32.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tools_linux_dump_syms_dump_syms-dump_symbols.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tools_linux_dump_syms_dump_syms-elf_symbols_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tools_linux_dump_syms_dump_syms-elfutils.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tools_linux_dump_syms_dump_syms-file_id.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tools_linux_dump_syms_dump_syms-linux_libc_support.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tools_linux_dump_syms_dump_syms-memory_mapped_file.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tools_linux_dump_syms_dump_syms-safe_readlink.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/dump_syms/dump_syms-dump_syms.$(OBJEXT) +src_tools_linux_core_handler_core_handler_DEPENDENCIES = \ + src/client/linux/libbreakpad_client.a src/common/path_helper.o +am_src_tools_linux_dump_syms_dump_syms_OBJECTS = src/common/tools_linux_dump_syms_dump_syms-dwarf_cfi_to_module.$(OBJEXT) \ + src/common/tools_linux_dump_syms_dump_syms-dwarf_cu_to_module.$(OBJEXT) \ + src/common/tools_linux_dump_syms_dump_syms-dwarf_line_to_module.$(OBJEXT) \ + src/common/tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.$(OBJEXT) \ + src/common/tools_linux_dump_syms_dump_syms-language.$(OBJEXT) \ + src/common/tools_linux_dump_syms_dump_syms-module.$(OBJEXT) \ + src/common/tools_linux_dump_syms_dump_syms-path_helper.$(OBJEXT) \ + src/common/tools_linux_dump_syms_dump_syms-stabs_reader.$(OBJEXT) \ + src/common/tools_linux_dump_syms_dump_syms-stabs_to_module.$(OBJEXT) \ + src/common/dwarf/tools_linux_dump_syms_dump_syms-bytereader.$(OBJEXT) \ + src/common/dwarf/tools_linux_dump_syms_dump_syms-dwarf2diehandler.$(OBJEXT) \ + src/common/dwarf/tools_linux_dump_syms_dump_syms-dwarf2reader.$(OBJEXT) \ + src/common/dwarf/tools_linux_dump_syms_dump_syms-elf_reader.$(OBJEXT) \ + src/common/linux/tools_linux_dump_syms_dump_syms-crc32.$(OBJEXT) \ + src/common/linux/tools_linux_dump_syms_dump_syms-dump_symbols.$(OBJEXT) \ + src/common/linux/tools_linux_dump_syms_dump_syms-elf_symbols_to_module.$(OBJEXT) \ + src/common/linux/tools_linux_dump_syms_dump_syms-elfutils.$(OBJEXT) \ + src/common/linux/tools_linux_dump_syms_dump_syms-file_id.$(OBJEXT) \ + src/common/linux/tools_linux_dump_syms_dump_syms-linux_libc_support.$(OBJEXT) \ + src/common/linux/tools_linux_dump_syms_dump_syms-memory_mapped_file.$(OBJEXT) \ + src/common/linux/tools_linux_dump_syms_dump_syms-safe_readlink.$(OBJEXT) \ + src/tools/linux/dump_syms/dump_syms-dump_syms.$(OBJEXT) src_tools_linux_dump_syms_dump_syms_OBJECTS = \ $(am_src_tools_linux_dump_syms_dump_syms_OBJECTS) -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_dump_syms_dump_syms_DEPENDENCIES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) +src_tools_linux_dump_syms_dump_syms_DEPENDENCIES = \ + $(am__DEPENDENCIES_1) src_tools_linux_dump_syms_dump_syms_LINK = $(CXXLD) \ $(src_tools_linux_dump_syms_dump_syms_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ -am__src_tools_linux_md2core_minidump_2_core_SOURCES_DIST = \ - src/common/linux/memory_mapped_file.cc \ - src/common/path_helper.cc \ - src/tools/linux/md2core/minidump-2-core.cc \ - src/tools/linux/md2core/minidump_memory_range.h -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_md2core_minidump_2_core_OBJECTS = src/common/linux/memory_mapped_file.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/path_helper.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump-2-core.$(OBJEXT) +am_src_tools_linux_md2core_minidump_2_core_OBJECTS = \ + src/common/linux/memory_mapped_file.$(OBJEXT) \ + src/common/path_helper.$(OBJEXT) \ + src/tools/linux/md2core/minidump-2-core.$(OBJEXT) src_tools_linux_md2core_minidump_2_core_OBJECTS = \ $(am_src_tools_linux_md2core_minidump_2_core_OBJECTS) src_tools_linux_md2core_minidump_2_core_LDADD = $(LDADD) -am__src_tools_linux_md2core_minidump_2_core_unittest_SOURCES_DIST = \ - src/tools/linux/md2core/minidump_memory_range_unittest.cc -@LINUX_HOST_TRUE@am_src_tools_linux_md2core_minidump_2_core_unittest_OBJECTS = src/tools/linux/md2core/minidump_2_core_unittest-minidump_memory_range_unittest.$(OBJEXT) +am_src_tools_linux_md2core_minidump_2_core_unittest_OBJECTS = src/tools/linux/md2core/minidump_2_core_unittest-minidump_memory_range_unittest.$(OBJEXT) src_tools_linux_md2core_minidump_2_core_unittest_OBJECTS = $(am_src_tools_linux_md2core_minidump_2_core_unittest_OBJECTS) -@LINUX_HOST_TRUE@src_tools_linux_md2core_minidump_2_core_unittest_DEPENDENCIES = \ -@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ -@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) -am__src_tools_linux_pid2md_pid2md_SOURCES_DIST = \ - src/tools/linux/pid2md/pid2md.cc -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_pid2md_pid2md_OBJECTS = src/tools/linux/pid2md/pid2md.$(OBJEXT) +src_tools_linux_md2core_minidump_2_core_unittest_DEPENDENCIES = \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am_src_tools_linux_pid2md_pid2md_OBJECTS = \ + src/tools/linux/pid2md/pid2md.$(OBJEXT) src_tools_linux_pid2md_pid2md_OBJECTS = \ $(am_src_tools_linux_pid2md_pid2md_OBJECTS) -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_pid2md_pid2md_DEPENDENCIES = src/client/linux/libbreakpad_client.a -am__src_tools_linux_symupload_minidump_upload_SOURCES_DIST = \ - src/common/linux/http_upload.cc \ - src/tools/linux/symupload/minidump_upload.cc -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_symupload_minidump_upload_OBJECTS = src/common/linux/http_upload.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/minidump_upload.$(OBJEXT) +src_tools_linux_pid2md_pid2md_DEPENDENCIES = \ + src/client/linux/libbreakpad_client.a src/common/path_helper.o +am_src_tools_linux_symupload_minidump_upload_OBJECTS = \ + src/common/linux/http_upload.$(OBJEXT) \ + src/common/path_helper.$(OBJEXT) \ + src/tools/linux/symupload/minidump_upload.$(OBJEXT) src_tools_linux_symupload_minidump_upload_OBJECTS = \ $(am_src_tools_linux_symupload_minidump_upload_OBJECTS) src_tools_linux_symupload_minidump_upload_DEPENDENCIES = -am__src_tools_linux_symupload_sym_upload_SOURCES_DIST = \ - src/common/linux/http_upload.cc src/common/linux/http_upload.h \ - src/common/linux/libcurl_wrapper.cc \ - src/common/linux/libcurl_wrapper.h \ - src/common/linux/symbol_collector_client.cc \ - src/common/linux/symbol_collector_client.h \ - src/common/linux/symbol_upload.cc \ - src/common/linux/symbol_upload.h \ - src/tools/linux/symupload/sym_upload.cc -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_symupload_sym_upload_OBJECTS = src/common/linux/http_upload.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/libcurl_wrapper.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/symbol_collector_client.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/symbol_upload.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/sym_upload.$(OBJEXT) +am_src_tools_linux_symupload_sym_upload_OBJECTS = \ + src/common/linux/http_upload.$(OBJEXT) \ + src/common/linux/libcurl_wrapper.$(OBJEXT) \ + src/common/linux/symbol_collector_client.$(OBJEXT) \ + src/common/linux/symbol_upload.$(OBJEXT) \ + src/common/path_helper.$(OBJEXT) \ + src/tools/linux/symupload/sym_upload.$(OBJEXT) src_tools_linux_symupload_sym_upload_OBJECTS = \ $(am_src_tools_linux_symupload_sym_upload_OBJECTS) src_tools_linux_symupload_sym_upload_DEPENDENCIES = -am__src_tools_mac_dump_syms_dump_syms_mac_SOURCES_DIST = \ - src/common/dwarf_cfi_to_module.cc \ - src/common/dwarf_cu_to_module.cc \ - src/common/dwarf_line_to_module.cc \ - src/common/dwarf_range_list_handler.cc src/common/language.cc \ - src/common/md5.cc src/common/module.cc \ - src/common/path_helper.cc src/common/stabs_reader.cc \ - src/common/stabs_to_module.cc src/common/dwarf/bytereader.cc \ - src/common/dwarf/dwarf2diehandler.cc \ - src/common/dwarf/dwarf2reader.cc \ - src/common/dwarf/elf_reader.cc \ - src/common/mac/arch_utilities.cc src/common/mac/dump_syms.cc \ - src/common/mac/dump_syms.h src/common/mac/file_id.cc \ - src/common/mac/file_id.h src/common/mac/macho_id.cc \ - src/common/mac/macho_id.h src/common/mac/macho_reader.cc \ - src/common/mac/macho_reader.h \ - src/common/mac/macho_utilities.cc \ - src/common/mac/macho_utilities.h \ - src/common/mac/macho_walker.cc src/common/mac/macho_walker.h \ - src/tools/mac/dump_syms/dump_syms_tool.cc -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_mac_dump_syms_dump_syms_mac_OBJECTS = src/common/tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_mac_dump_syms_dump_syms_mac-language.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_mac_dump_syms_dump_syms_mac-md5.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_mac_dump_syms_dump_syms_mac-module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_mac_dump_syms_dump_syms_mac-path_helper.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_mac_dump_syms_dump_syms_mac-stabs_reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tools_mac_dump_syms_dump_syms_mac-stabs_to_module.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/tools_mac_dump_syms_dump_syms_mac-bytereader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/tools_mac_dump_syms_dump_syms_mac-dwarf2reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/tools_mac_dump_syms_dump_syms_mac-elf_reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/tools_mac_dump_syms_dump_syms_mac-arch_utilities.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/tools_mac_dump_syms_dump_syms_mac-dump_syms.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/tools_mac_dump_syms_dump_syms_mac-file_id.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/tools_mac_dump_syms_dump_syms_mac-macho_id.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/tools_mac_dump_syms_dump_syms_mac-macho_reader.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/tools_mac_dump_syms_dump_syms_mac-macho_utilities.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/tools_mac_dump_syms_dump_syms_mac-macho_walker.$(OBJEXT) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/mac/dump_syms/dump_syms_mac-dump_syms_tool.$(OBJEXT) +am_src_tools_mac_dump_syms_dump_syms_mac_OBJECTS = src/common/tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.$(OBJEXT) \ + src/common/tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.$(OBJEXT) \ + src/common/tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.$(OBJEXT) \ + src/common/tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.$(OBJEXT) \ + src/common/tools_mac_dump_syms_dump_syms_mac-language.$(OBJEXT) \ + src/common/tools_mac_dump_syms_dump_syms_mac-md5.$(OBJEXT) \ + src/common/tools_mac_dump_syms_dump_syms_mac-module.$(OBJEXT) \ + src/common/tools_mac_dump_syms_dump_syms_mac-path_helper.$(OBJEXT) \ + src/common/tools_mac_dump_syms_dump_syms_mac-stabs_reader.$(OBJEXT) \ + src/common/tools_mac_dump_syms_dump_syms_mac-stabs_to_module.$(OBJEXT) \ + src/common/dwarf/tools_mac_dump_syms_dump_syms_mac-bytereader.$(OBJEXT) \ + src/common/dwarf/tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.$(OBJEXT) \ + src/common/dwarf/tools_mac_dump_syms_dump_syms_mac-dwarf2reader.$(OBJEXT) \ + src/common/dwarf/tools_mac_dump_syms_dump_syms_mac-elf_reader.$(OBJEXT) \ + src/common/mac/tools_mac_dump_syms_dump_syms_mac-arch_utilities.$(OBJEXT) \ + src/common/mac/tools_mac_dump_syms_dump_syms_mac-dump_syms.$(OBJEXT) \ + src/common/mac/tools_mac_dump_syms_dump_syms_mac-file_id.$(OBJEXT) \ + src/common/mac/tools_mac_dump_syms_dump_syms_mac-macho_id.$(OBJEXT) \ + src/common/mac/tools_mac_dump_syms_dump_syms_mac-macho_reader.$(OBJEXT) \ + src/common/mac/tools_mac_dump_syms_dump_syms_mac-macho_utilities.$(OBJEXT) \ + src/common/mac/tools_mac_dump_syms_dump_syms_mac-macho_walker.$(OBJEXT) \ + src/tools/mac/dump_syms/dump_syms_mac-dump_syms_tool.$(OBJEXT) src_tools_mac_dump_syms_dump_syms_mac_OBJECTS = \ $(am_src_tools_mac_dump_syms_dump_syms_mac_OBJECTS) -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_mac_dump_syms_dump_syms_mac_DEPENDENCIES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) +src_tools_mac_dump_syms_dump_syms_mac_DEPENDENCIES = \ + $(am__DEPENDENCIES_1) src_tools_mac_dump_syms_dump_syms_mac_LINK = $(CXXLD) \ $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ @@ -1639,12 +1464,14 @@ am__depfiles_remade = src/client/$(DEPDIR)/minidump_file_writer.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest_utils.Po \ + src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_core_dumper.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper_unittest_helper-linux_dumper_unittest_helper.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_ptrace_dumper.Po \ src/client/linux/minidump_writer/$(DEPDIR)/minidump_writer.Po \ + src/client/linux/minidump_writer/$(DEPDIR)/pe_file.Po \ src/common/$(DEPDIR)/client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Po \ src/common/$(DEPDIR)/convert_UTF.Po \ src/common/$(DEPDIR)/dumper_unittest-byte_cursor_unittest.Po \ @@ -1687,8 +1514,11 @@ am__depfiles_remade = src/client/$(DEPDIR)/minidump_file_writer.Po \ src/common/$(DEPDIR)/processor_stackwalker_arm_unittest-test_assembler.Po \ src/common/$(DEPDIR)/processor_stackwalker_mips64_unittest-test_assembler.Po \ src/common/$(DEPDIR)/processor_stackwalker_mips_unittest-test_assembler.Po \ + src/common/$(DEPDIR)/processor_stackwalker_riscv64_unittest-test_assembler.Po \ + src/common/$(DEPDIR)/processor_stackwalker_riscv_unittest-test_assembler.Po \ src/common/$(DEPDIR)/processor_stackwalker_x86_unittest-test_assembler.Po \ src/common/$(DEPDIR)/processor_synth_minidump_unittest-test_assembler.Po \ + src/common/$(DEPDIR)/safe_math_unittest-safe_math_unittest.Po \ src/common/$(DEPDIR)/string_conversion.Po \ src/common/$(DEPDIR)/test_assembler_unittest-test_assembler.Po \ src/common/$(DEPDIR)/test_assembler_unittest-test_assembler_unittest.Po \ @@ -1740,6 +1570,8 @@ am__depfiles_remade = src/client/$(DEPDIR)/minidump_file_writer.Po \ src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Po \ src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-elf_core_dump.Po \ src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.Po \ + src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_pipe.Po \ + src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_tmpfile.Po \ src/common/linux/$(DEPDIR)/dumper_unittest-crc32.Po \ src/common/linux/$(DEPDIR)/dumper_unittest-dump_symbols.Po \ src/common/linux/$(DEPDIR)/dumper_unittest-dump_symbols_unittest.Po \ @@ -1769,6 +1601,10 @@ am__depfiles_remade = src/client/$(DEPDIR)/minidump_file_writer.Po \ src/common/linux/$(DEPDIR)/linux_libc_support.Po \ src/common/linux/$(DEPDIR)/memory_mapped_file.Po \ src/common/linux/$(DEPDIR)/safe_readlink.Po \ + src/common/linux/$(DEPDIR)/scoped_pipe.Po \ + src/common/linux/$(DEPDIR)/scoped_pipe_unittest-scoped_pipe_unittest.Po \ + src/common/linux/$(DEPDIR)/scoped_tmpfile.Po \ + src/common/linux/$(DEPDIR)/scoped_tmpfile_unittest-scoped_tmpfile_unittest.Po \ src/common/linux/$(DEPDIR)/symbol_collector_client.Po \ src/common/linux/$(DEPDIR)/symbol_upload.Po \ src/common/linux/$(DEPDIR)/tools_linux_dump_syms_dump_syms-crc32.Po \ @@ -1815,6 +1651,8 @@ am__depfiles_remade = src/client/$(DEPDIR)/minidump_file_writer.Po \ src/processor/$(DEPDIR)/client_linux_linux_client_unittest_shlib-proc_maps_linux.Po \ src/processor/$(DEPDIR)/contained_range_map_unittest.Po \ src/processor/$(DEPDIR)/convert_old_arm64_context.Po \ + src/processor/$(DEPDIR)/disassembler_objdump.Po \ + src/processor/$(DEPDIR)/disassembler_objdump_unittest-disassembler_objdump_unittest.Po \ src/processor/$(DEPDIR)/disassembler_x86.Po \ src/processor/$(DEPDIR)/disassembler_x86_unittest-disassembler_x86_unittest.Po \ src/processor/$(DEPDIR)/dump_context.Po \ @@ -1869,6 +1707,10 @@ am__depfiles_remade = src/client/$(DEPDIR)/minidump_file_writer.Po \ src/processor/$(DEPDIR)/stackwalker_mips_unittest-stackwalker_mips_unittest.Po \ src/processor/$(DEPDIR)/stackwalker_ppc.Po \ src/processor/$(DEPDIR)/stackwalker_ppc64.Po \ + src/processor/$(DEPDIR)/stackwalker_riscv.Po \ + src/processor/$(DEPDIR)/stackwalker_riscv64.Po \ + src/processor/$(DEPDIR)/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.Po \ + src/processor/$(DEPDIR)/stackwalker_riscv_unittest-stackwalker_riscv_unittest.Po \ src/processor/$(DEPDIR)/stackwalker_selftest.Po \ src/processor/$(DEPDIR)/stackwalker_sparc.Po \ src/processor/$(DEPDIR)/stackwalker_x86.Po \ @@ -1957,12 +1799,16 @@ SOURCES = $(src_client_linux_libbreakpad_client_a_SOURCES) \ $(src_common_dwarf_dwarf2reader_lineinfo_unittest_SOURCES) \ $(src_common_dwarf_dwarf2reader_splitfunctions_unittest_SOURCES) \ $(src_common_linux_google_crashdump_uploader_test_SOURCES) \ + $(src_common_linux_scoped_pipe_unittest_SOURCES) \ + $(src_common_linux_scoped_tmpfile_unittest_SOURCES) \ $(src_common_mac_macho_reader_unittest_SOURCES) \ + $(src_common_safe_math_unittest_SOURCES) \ $(src_common_test_assembler_unittest_SOURCES) \ $(src_processor_address_map_unittest_SOURCES) \ $(src_processor_basic_source_line_resolver_unittest_SOURCES) \ $(src_processor_cfi_frame_info_unittest_SOURCES) \ $(src_processor_contained_range_map_unittest_SOURCES) \ + $(src_processor_disassembler_objdump_unittest_SOURCES) \ $(src_processor_disassembler_x86_unittest_SOURCES) \ $(src_processor_exploitability_unittest_SOURCES) \ $(src_processor_fast_source_line_resolver_unittest_SOURCES) \ @@ -1985,6 +1831,8 @@ SOURCES = $(src_client_linux_libbreakpad_client_a_SOURCES) \ $(src_processor_stackwalker_arm_unittest_SOURCES) \ $(src_processor_stackwalker_mips64_unittest_SOURCES) \ $(src_processor_stackwalker_mips_unittest_SOURCES) \ + $(src_processor_stackwalker_riscv64_unittest_SOURCES) \ + $(src_processor_stackwalker_riscv_unittest_SOURCES) \ $(src_processor_stackwalker_selftest_SOURCES) \ $(src_processor_stackwalker_x86_unittest_SOURCES) \ $(src_processor_static_address_map_unittest_SOURCES) \ @@ -2005,99 +1853,102 @@ DIST_SOURCES = \ $(am__src_client_linux_libbreakpad_client_a_SOURCES_DIST) \ $(am__src_libbreakpad_a_SOURCES_DIST) \ $(am__src_testing_libtesting_a_SOURCES_DIST) \ - $(am__src_third_party_libdisasm_libdisasm_a_SOURCES_DIST) \ + $(src_third_party_libdisasm_libdisasm_a_SOURCES) \ $(src_client_linux_linux_client_unittest_SOURCES) \ $(am__src_client_linux_linux_client_unittest_shlib_SOURCES_DIST) \ - $(am__src_client_linux_linux_dumper_unittest_helper_SOURCES_DIST) \ - $(am__src_common_dumper_unittest_SOURCES_DIST) \ - $(am__src_common_dwarf_dwarf2reader_lineinfo_unittest_SOURCES_DIST) \ - $(am__src_common_dwarf_dwarf2reader_splitfunctions_unittest_SOURCES_DIST) \ - $(am__src_common_linux_google_crashdump_uploader_test_SOURCES_DIST) \ - $(am__src_common_mac_macho_reader_unittest_SOURCES_DIST) \ - $(am__src_common_test_assembler_unittest_SOURCES_DIST) \ - $(am__src_processor_address_map_unittest_SOURCES_DIST) \ - $(am__src_processor_basic_source_line_resolver_unittest_SOURCES_DIST) \ - $(am__src_processor_cfi_frame_info_unittest_SOURCES_DIST) \ - $(am__src_processor_contained_range_map_unittest_SOURCES_DIST) \ - $(am__src_processor_disassembler_x86_unittest_SOURCES_DIST) \ - $(am__src_processor_exploitability_unittest_SOURCES_DIST) \ - $(am__src_processor_fast_source_line_resolver_unittest_SOURCES_DIST) \ - $(am__src_processor_map_serializers_unittest_SOURCES_DIST) \ - $(am__src_processor_microdump_processor_unittest_SOURCES_DIST) \ - $(am__src_processor_microdump_stackwalk_SOURCES_DIST) \ - $(am__src_processor_minidump_dump_SOURCES_DIST) \ - $(am__src_processor_minidump_processor_unittest_SOURCES_DIST) \ - $(am__src_processor_minidump_stackwalk_SOURCES_DIST) \ - $(am__src_processor_minidump_unittest_SOURCES_DIST) \ - $(am__src_processor_pathname_stripper_unittest_SOURCES_DIST) \ - $(am__src_processor_postfix_evaluator_unittest_SOURCES_DIST) \ - $(am__src_processor_proc_maps_linux_unittest_SOURCES_DIST) \ - $(am__src_processor_range_map_truncate_lower_unittest_SOURCES_DIST) \ - $(am__src_processor_range_map_truncate_upper_unittest_SOURCES_DIST) \ - $(am__src_processor_range_map_unittest_SOURCES_DIST) \ - $(am__src_processor_stackwalker_address_list_unittest_SOURCES_DIST) \ - $(am__src_processor_stackwalker_amd64_unittest_SOURCES_DIST) \ - $(am__src_processor_stackwalker_arm64_unittest_SOURCES_DIST) \ - $(am__src_processor_stackwalker_arm_unittest_SOURCES_DIST) \ - $(am__src_processor_stackwalker_mips64_unittest_SOURCES_DIST) \ - $(am__src_processor_stackwalker_mips_unittest_SOURCES_DIST) \ - $(am__src_processor_stackwalker_selftest_SOURCES_DIST) \ - $(am__src_processor_stackwalker_x86_unittest_SOURCES_DIST) \ - $(am__src_processor_static_address_map_unittest_SOURCES_DIST) \ - $(am__src_processor_static_contained_range_map_unittest_SOURCES_DIST) \ - $(am__src_processor_static_map_unittest_SOURCES_DIST) \ - $(am__src_processor_static_range_map_unittest_SOURCES_DIST) \ - $(am__src_processor_synth_minidump_unittest_SOURCES_DIST) \ - $(am__src_tools_linux_core2md_core2md_SOURCES_DIST) \ - $(am__src_tools_linux_core_handler_core_handler_SOURCES_DIST) \ - $(am__src_tools_linux_dump_syms_dump_syms_SOURCES_DIST) \ - $(am__src_tools_linux_md2core_minidump_2_core_SOURCES_DIST) \ - $(am__src_tools_linux_md2core_minidump_2_core_unittest_SOURCES_DIST) \ - $(am__src_tools_linux_pid2md_pid2md_SOURCES_DIST) \ - $(am__src_tools_linux_symupload_minidump_upload_SOURCES_DIST) \ - $(am__src_tools_linux_symupload_sym_upload_SOURCES_DIST) \ - $(am__src_tools_mac_dump_syms_dump_syms_mac_SOURCES_DIST) -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -DATA = $(dist_doc_DATA) $(pkgconfig_DATA) -am__includecl_HEADERS_DIST = $(top_srcdir)/src/common/linux/*.h -am__includeclc_HEADERS_DIST = \ - $(top_srcdir)/src/client/linux/crash_generation/*.h -am__includecldwc_HEADERS_DIST = \ - $(top_srcdir)/src/client/linux/dump_writer_common/*.h -am__includeclh_HEADERS_DIST = \ - $(top_srcdir)/src/client/linux/handler/*.h -am__includeclm_HEADERS_DIST = \ - $(top_srcdir)/src/client/linux/minidump_writer/*.h -am__includelss_HEADERS_DIST = $(top_srcdir)/src/third_party/lss/*.h -HEADERS = $(includec_HEADERS) $(includecl_HEADERS) \ - $(includeclc_HEADERS) $(includecldwc_HEADERS) \ - $(includeclh_HEADERS) $(includeclm_HEADERS) \ - $(includegbc_HEADERS) $(includelss_HEADERS) \ - $(includep_HEADERS) -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -CSCOPE = cscope + $(src_client_linux_linux_dumper_unittest_helper_SOURCES) \ + $(src_common_dumper_unittest_SOURCES) \ + $(src_common_dwarf_dwarf2reader_lineinfo_unittest_SOURCES) \ + $(src_common_dwarf_dwarf2reader_splitfunctions_unittest_SOURCES) \ + $(src_common_linux_google_crashdump_uploader_test_SOURCES) \ + $(src_common_linux_scoped_pipe_unittest_SOURCES) \ + $(src_common_linux_scoped_tmpfile_unittest_SOURCES) \ + $(src_common_mac_macho_reader_unittest_SOURCES) \ + $(src_common_safe_math_unittest_SOURCES) \ + $(src_common_test_assembler_unittest_SOURCES) \ + $(src_processor_address_map_unittest_SOURCES) \ + $(src_processor_basic_source_line_resolver_unittest_SOURCES) \ + $(src_processor_cfi_frame_info_unittest_SOURCES) \ + $(src_processor_contained_range_map_unittest_SOURCES) \ + $(src_processor_disassembler_objdump_unittest_SOURCES) \ + $(src_processor_disassembler_x86_unittest_SOURCES) \ + $(src_processor_exploitability_unittest_SOURCES) \ + $(src_processor_fast_source_line_resolver_unittest_SOURCES) \ + $(src_processor_map_serializers_unittest_SOURCES) \ + $(src_processor_microdump_processor_unittest_SOURCES) \ + $(src_processor_microdump_stackwalk_SOURCES) \ + $(src_processor_minidump_dump_SOURCES) \ + $(src_processor_minidump_processor_unittest_SOURCES) \ + $(src_processor_minidump_stackwalk_SOURCES) \ + $(src_processor_minidump_unittest_SOURCES) \ + $(src_processor_pathname_stripper_unittest_SOURCES) \ + $(src_processor_postfix_evaluator_unittest_SOURCES) \ + $(src_processor_proc_maps_linux_unittest_SOURCES) \ + $(src_processor_range_map_truncate_lower_unittest_SOURCES) \ + $(src_processor_range_map_truncate_upper_unittest_SOURCES) \ + $(src_processor_range_map_unittest_SOURCES) \ + $(src_processor_stackwalker_address_list_unittest_SOURCES) \ + $(src_processor_stackwalker_amd64_unittest_SOURCES) \ + $(src_processor_stackwalker_arm64_unittest_SOURCES) \ + $(src_processor_stackwalker_arm_unittest_SOURCES) \ + $(src_processor_stackwalker_mips64_unittest_SOURCES) \ + $(src_processor_stackwalker_mips_unittest_SOURCES) \ + $(src_processor_stackwalker_riscv64_unittest_SOURCES) \ + $(src_processor_stackwalker_riscv_unittest_SOURCES) \ + $(src_processor_stackwalker_selftest_SOURCES) \ + $(src_processor_stackwalker_x86_unittest_SOURCES) \ + $(src_processor_static_address_map_unittest_SOURCES) \ + $(src_processor_static_contained_range_map_unittest_SOURCES) \ + $(src_processor_static_map_unittest_SOURCES) \ + $(src_processor_static_range_map_unittest_SOURCES) \ + $(src_processor_synth_minidump_unittest_SOURCES) \ + $(src_tools_linux_core2md_core2md_SOURCES) \ + $(src_tools_linux_core_handler_core_handler_SOURCES) \ + $(src_tools_linux_dump_syms_dump_syms_SOURCES) \ + $(src_tools_linux_md2core_minidump_2_core_SOURCES) \ + $(src_tools_linux_md2core_minidump_2_core_unittest_SOURCES) \ + $(src_tools_linux_pid2md_pid2md_SOURCES) \ + $(src_tools_linux_symupload_minidump_upload_SOURCES) \ + $(src_tools_linux_symupload_sym_upload_SOURCES) \ + $(src_tools_mac_dump_syms_dump_syms_mac_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +DATA = $(dist_doc_DATA) $(pkgconfig_DATA) +am__includecl_HEADERS_DIST = $(top_srcdir)/src/common/linux/*.h +am__includeclc_HEADERS_DIST = \ + $(top_srcdir)/src/client/linux/crash_generation/*.h +am__includecldwc_HEADERS_DIST = \ + $(top_srcdir)/src/client/linux/dump_writer_common/*.h +am__includeclh_HEADERS_DIST = \ + $(top_srcdir)/src/client/linux/handler/*.h +am__includeclm_HEADERS_DIST = \ + $(top_srcdir)/src/client/linux/minidump_writer/*.h +am__includelss_HEADERS_DIST = $(top_srcdir)/src/third_party/lss/*.h +HEADERS = $(includec_HEADERS) $(includecl_HEADERS) \ + $(includeclc_HEADERS) $(includecldwc_HEADERS) \ + $(includeclh_HEADERS) $(includeclm_HEADERS) \ + $(includegbc_HEADERS) $(includelss_HEADERS) \ + $(includep_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` AM_RECURSIVE_TARGETS = cscope check recheck am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ @@ -2285,9 +2136,9 @@ am__DIST_COMMON = $(srcdir)/Makefile.in \ $(top_srcdir)/autotools/missing \ $(top_srcdir)/autotools/test-driver \ $(top_srcdir)/src/config.h.in AUTHORS ChangeLog INSTALL NEWS \ - autotools/ar-lib autotools/compile autotools/config.guess \ - autotools/config.sub autotools/depcomp autotools/install-sh \ - autotools/ltmain.sh autotools/missing + README.md autotools/ar-lib autotools/compile \ + autotools/config.guess autotools/config.sub autotools/depcomp \ + autotools/install-sh autotools/ltmain.sh autotools/missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) @@ -2323,6 +2174,8 @@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ CXX = @CXX@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ @@ -2332,14 +2185,13 @@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ -EGREP = @EGREP@ +ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GMOCK_CFLAGS = @GMOCK_CFLAGS@ GMOCK_LIBS = @GMOCK_LIBS@ -GREP = @GREP@ GTEST_CFLAGS = @GTEST_CFLAGS@ GTEST_LIBS = @GTEST_LIBS@ -HAVE_CXX11 = @HAVE_CXX11@ +HAVE_CXX17 = @HAVE_CXX17@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ @@ -2365,8 +2217,8 @@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ RANLIB = @RANLIB@ -RUST_DEMANGLE_CFLAGS = @RUST_DEMANGLE_CFLAGS@ -RUST_DEMANGLE_LIBS = @RUST_DEMANGLE_LIBS@ +RUSTC_DEMANGLE_CFLAGS = @RUSTC_DEMANGLE_CFLAGS@ +RUSTC_DEMANGLE_LIBS = @RUSTC_DEMANGLE_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ @@ -2427,1194 +2279,1252 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -# This allows #includes to be relative to src/ -AM_CPPFLAGS = -I$(top_srcdir)/src -AM_CFLAGS = $(am__append_2) -AM_CXXFLAGS = $(am__append_1) $(WARN_CXXFLAGS) $(am__append_3) +# This allows #includes to be relative to src/ +AM_CPPFLAGS = -I$(top_srcdir)/src +AM_CFLAGS = $(am__append_2) +AM_CXXFLAGS = $(am__append_1) $(WARN_CXXFLAGS) $(am__append_3) + +# Specify include paths for ac macros +ACLOCAL_AMFLAGS = -I m4 + +# License file is called LICENSE not COPYING +AUTOMAKE_OPTIONS = foreign +dist_doc_DATA = \ + AUTHORS \ + ChangeLog \ + INSTALL \ + LICENSE \ + NEWS \ + README.md + +@LINUX_HOST_TRUE@includeclhdir = $(includedir)/$(PACKAGE)/client/linux/handler +@LINUX_HOST_TRUE@includeclh_HEADERS = $(top_srcdir)/src/client/linux/handler/*.h +@LINUX_HOST_TRUE@includecldwcdir = $(includedir)/$(PACKAGE)/client/linux/dump_writer_common +@LINUX_HOST_TRUE@includecldwc_HEADERS = $(top_srcdir)/src/client/linux/dump_writer_common/*.h +@LINUX_HOST_TRUE@includeclmdir = $(includedir)/$(PACKAGE)/client/linux/minidump_writer +@LINUX_HOST_TRUE@includeclm_HEADERS = $(top_srcdir)/src/client/linux/minidump_writer/*.h +@LINUX_HOST_TRUE@includeclcdir = $(includedir)/$(PACKAGE)/client/linux/crash_generation +@LINUX_HOST_TRUE@includeclc_HEADERS = $(top_srcdir)/src/client/linux/crash_generation/*.h +@LINUX_HOST_TRUE@includelssdir = $(includedir)/$(PACKAGE)/third_party/lss +@LINUX_HOST_TRUE@includelss_HEADERS = $(top_srcdir)/src/third_party/lss/*.h +@LINUX_HOST_TRUE@includecldir = $(includedir)/$(PACKAGE)/common/linux +@LINUX_HOST_TRUE@includecl_HEADERS = $(top_srcdir)/src/common/linux/*.h +includegbcdir = $(includedir)/$(PACKAGE)/google_breakpad/common +includegbc_HEADERS = $(top_srcdir)/src/google_breakpad/common/*.h +includecdir = $(includedir)/$(PACKAGE)/common +includec_HEADERS = $(top_srcdir)/src/common/*.h +includepdir = $(includedir)/$(PACKAGE)/processor +includep_HEADERS = $(top_srcdir)/src/processor/*.h +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = $(am__append_6) $(am__append_13) +@SYSTEM_TEST_LIBS_FALSE@TEST_CFLAGS = \ +@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/include \ +@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/googletest/include \ +@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/googletest \ +@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/googlemock/include \ +@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/googlemock \ +@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing + +@SYSTEM_TEST_LIBS_TRUE@TEST_CFLAGS = $(GTEST_CFLAGS) $(GMOCK_CFLAGS) +@SYSTEM_TEST_LIBS_FALSE@TEST_LIBS = src/testing/libtesting.a +@SYSTEM_TEST_LIBS_TRUE@TEST_LIBS = $(GTEST_LIBS) -lgtest_main $(GMOCK_LIBS) +@SYSTEM_TEST_LIBS_FALSE@TEST_DEPS = $(TEST_LIBS) +@SYSTEM_TEST_LIBS_TRUE@TEST_DEPS = +@ANDROID_HOST_FALSE@@TESTS_AS_ROOT_FALSE@LOG_DRIVER = $(top_srcdir)/autotools/test-driver +@ANDROID_HOST_FALSE@@TESTS_AS_ROOT_TRUE@LOG_DRIVER = $(top_srcdir)/autotools/root-test-driver $(top_srcdir)/autotools/test-driver + +# Since Autotools 1.2, tests are run through a special "test driver" script. +# Unfortunately, it's not possible anymore to specify an alternative shell to +# run them on connected devices, so use a slightly modified version of the +# driver for Android. +@ANDROID_HOST_TRUE@LOG_DRIVER = $(top_srcdir)/android/test-driver +check_LIBRARIES = $(am__append_4) +noinst_LIBRARIES = $(am__append_7) +lib_LIBRARIES = $(am__append_5) $(am__append_12) +noinst_SCRIPTS = $(check_SCRIPTS) +CLEANFILES = $(am__append_16) +@SYSTEM_TEST_LIBS_FALSE@src_testing_libtesting_a_SOURCES = \ +@SYSTEM_TEST_LIBS_FALSE@ src/breakpad_googletest_includes.h \ +@SYSTEM_TEST_LIBS_FALSE@ src/testing/googletest/src/gtest-all.cc \ +@SYSTEM_TEST_LIBS_FALSE@ src/testing/googletest/src/gtest_main.cc \ +@SYSTEM_TEST_LIBS_FALSE@ src/testing/googlemock/src/gmock-all.cc + +@SYSTEM_TEST_LIBS_FALSE@src_testing_libtesting_a_CPPFLAGS = \ +@SYSTEM_TEST_LIBS_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@check_SCRIPTS = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk_test \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk_machine_readable_test \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_dump_test \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk_test \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk_machine_readable_test + +TESTS = $(check_PROGRAMS) $(check_SCRIPTS) + +# All targets that were defined above should now be +# declared below. This should be done unconditionally +# so DO NOT wrap them in conditions! +# Execept for conditionally adding a specific file or +# flag that should only be added for a specific arch, +# system, etc. +src_common_safe_math_unittest_SOURCES = \ + src/common/safe_math.h \ + src/common/safe_math_unittest.cc + +src_common_safe_math_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_common_safe_math_unittest_LDADD = \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + + +# Breakpad processor library +src_libbreakpad_a_SOURCES = \ + src/google_breakpad/common/breakpad_types.h \ + src/google_breakpad/common/minidump_format.h \ + src/google_breakpad/common/minidump_size.h \ + src/google_breakpad/processor/basic_source_line_resolver.h \ + src/google_breakpad/processor/call_stack.h \ + src/google_breakpad/processor/code_module.h \ + src/google_breakpad/processor/code_modules.h \ + src/google_breakpad/processor/dump_context.h \ + src/google_breakpad/processor/dump_object.h \ + src/google_breakpad/processor/exploitability.h \ + src/google_breakpad/processor/fast_source_line_resolver.h \ + src/google_breakpad/processor/memory_region.h \ + src/google_breakpad/processor/microdump.h \ + src/google_breakpad/processor/microdump_processor.h \ + src/google_breakpad/processor/minidump.h \ + src/google_breakpad/processor/minidump_processor.h \ + src/google_breakpad/processor/process_result.h \ + src/google_breakpad/processor/process_state.h \ + src/google_breakpad/processor/proc_maps_linux.h \ + src/google_breakpad/processor/source_line_resolver_base.h \ + src/google_breakpad/processor/source_line_resolver_interface.h \ + src/google_breakpad/processor/stack_frame.h \ + src/google_breakpad/processor/stack_frame_cpu.h \ + src/google_breakpad/processor/stack_frame_symbolizer.h \ + src/google_breakpad/processor/stackwalker.h \ + src/google_breakpad/processor/symbol_supplier.h \ + src/google_breakpad/processor/system_info.h \ + src/processor/address_map-inl.h src/processor/address_map.h \ + src/processor/basic_code_module.h \ + src/processor/basic_code_modules.cc \ + src/processor/basic_code_modules.h \ + src/processor/basic_source_line_resolver_types.h \ + src/processor/basic_source_line_resolver.cc \ + src/processor/call_stack.cc src/processor/cfi_frame_info.cc \ + src/processor/cfi_frame_info.h \ + src/processor/contained_range_map-inl.h \ + src/processor/contained_range_map.h \ + src/processor/convert_old_arm64_context.cc \ + src/processor/convert_old_arm64_context.h \ + src/processor/disassembler_x86.h \ + src/processor/disassembler_x86.cc \ + src/processor/dump_context.cc src/processor/dump_object.cc \ + src/processor/exploitability.cc \ + src/processor/exploitability_linux.h \ + src/processor/exploitability_linux.cc \ + src/processor/exploitability_win.h \ + src/processor/exploitability_win.cc \ + src/processor/fast_source_line_resolver_types.h \ + src/processor/fast_source_line_resolver.cc \ + src/processor/linked_ptr.h src/processor/logging.h \ + src/processor/logging.cc src/processor/map_serializers-inl.h \ + src/processor/map_serializers.h src/processor/microdump.cc \ + src/processor/microdump_processor.cc src/processor/minidump.cc \ + src/processor/minidump_processor.cc \ + src/processor/module_comparer.cc \ + src/processor/module_comparer.h src/processor/module_factory.h \ + src/processor/module_serializer.cc \ + src/processor/module_serializer.h \ + src/processor/pathname_stripper.cc \ + src/processor/pathname_stripper.h \ + src/processor/postfix_evaluator-inl.h \ + src/processor/postfix_evaluator.h \ + src/processor/process_state.cc \ + src/processor/proc_maps_linux.cc src/processor/range_map-inl.h \ + src/processor/range_map.h \ + src/processor/simple_serializer-inl.h \ + src/processor/simple_serializer.h \ + src/processor/simple_symbol_supplier.cc \ + src/processor/simple_symbol_supplier.h \ + src/processor/windows_frame_info.h \ + src/processor/source_line_resolver_base_types.h \ + src/processor/source_line_resolver_base.cc \ + src/processor/stack_frame_cpu.cc \ + src/processor/stack_frame_symbolizer.cc \ + src/processor/stackwalk_common.cc \ + src/processor/stackwalk_common.h src/processor/stackwalker.cc \ + src/processor/stackwalker_amd64.cc \ + src/processor/stackwalker_amd64.h \ + src/processor/stackwalker_arm.cc \ + src/processor/stackwalker_arm.h \ + src/processor/stackwalker_arm64.cc \ + src/processor/stackwalker_arm64.h \ + src/processor/stackwalker_address_list.cc \ + src/processor/stackwalker_address_list.h \ + src/processor/stackwalker_mips.cc \ + src/processor/stackwalker_mips.h \ + src/processor/stackwalker_ppc.cc \ + src/processor/stackwalker_ppc.h \ + src/processor/stackwalker_ppc64.cc \ + src/processor/stackwalker_ppc64.h \ + src/processor/stackwalker_riscv.cc \ + src/processor/stackwalker_riscv.h \ + src/processor/stackwalker_riscv64.cc \ + src/processor/stackwalker_riscv64.h \ + src/processor/stackwalker_sparc.cc \ + src/processor/stackwalker_sparc.h \ + src/processor/stackwalker_x86.cc \ + src/processor/stackwalker_x86.h \ + src/processor/static_address_map-inl.h \ + src/processor/static_address_map.h \ + src/processor/static_contained_range_map-inl.h \ + src/processor/static_contained_range_map.h \ + src/processor/static_map_iterator-inl.h \ + src/processor/static_map_iterator.h \ + src/processor/static_map-inl.h src/processor/static_map.h \ + src/processor/static_range_map-inl.h \ + src/processor/static_range_map.h \ + src/processor/symbolic_constants_win.cc \ + src/processor/symbolic_constants_win.h \ + src/processor/tokenize.cc src/processor/tokenize.h \ + $(am__append_22) + +# libdisasm 3rd party library +src_third_party_libdisasm_libdisasm_a_SOURCES = \ + src/third_party/libdisasm/ia32_implicit.c \ + src/third_party/libdisasm/ia32_implicit.h \ + src/third_party/libdisasm/ia32_insn.c \ + src/third_party/libdisasm/ia32_insn.h \ + src/third_party/libdisasm/ia32_invariant.c \ + src/third_party/libdisasm/ia32_invariant.h \ + src/third_party/libdisasm/ia32_modrm.c \ + src/third_party/libdisasm/ia32_modrm.h \ + src/third_party/libdisasm/ia32_opcode_tables.c \ + src/third_party/libdisasm/ia32_opcode_tables.h \ + src/third_party/libdisasm/ia32_operand.c \ + src/third_party/libdisasm/ia32_operand.h \ + src/third_party/libdisasm/ia32_reg.c \ + src/third_party/libdisasm/ia32_reg.h \ + src/third_party/libdisasm/ia32_settings.c \ + src/third_party/libdisasm/ia32_settings.h \ + src/third_party/libdisasm/libdis.h \ + src/third_party/libdisasm/qword.h \ + src/third_party/libdisasm/x86_disasm.c \ + src/third_party/libdisasm/x86_format.c \ + src/third_party/libdisasm/x86_imm.c \ + src/third_party/libdisasm/x86_imm.h \ + src/third_party/libdisasm/x86_insn.c \ + src/third_party/libdisasm/x86_misc.c \ + src/third_party/libdisasm/x86_operand_list.c \ + src/third_party/libdisasm/x86_operand_list.h + + +# Breakpad client +src_client_linux_libbreakpad_client_a_SOURCES = \ + src/client/linux/crash_generation/crash_generation_client.cc \ + src/client/linux/crash_generation/crash_generation_server.cc \ + src/client/linux/dump_writer_common/thread_info.cc \ + src/client/linux/dump_writer_common/ucontext_reader.cc \ + src/client/linux/handler/exception_handler.cc \ + src/client/linux/handler/exception_handler.h \ + src/client/linux/handler/minidump_descriptor.cc \ + src/client/linux/handler/minidump_descriptor.h \ + src/client/linux/log/log.cc src/client/linux/log/log.h \ + src/client/linux/microdump_writer/microdump_writer.cc \ + src/client/linux/microdump_writer/microdump_writer.h \ + src/client/linux/minidump_writer/linux_core_dumper.cc \ + src/client/linux/minidump_writer/linux_dumper.cc \ + src/client/linux/minidump_writer/linux_ptrace_dumper.cc \ + src/client/linux/minidump_writer/minidump_writer.cc \ + src/client/linux/minidump_writer/pe_file.cc \ + src/client/minidump_file_writer-inl.h \ + src/client/minidump_file_writer.cc \ + src/client/minidump_file_writer.h src/common/convert_UTF.cc \ + src/common/convert_UTF.h src/common/md5.cc src/common/md5.h \ + src/common/string_conversion.cc src/common/string_conversion.h \ + src/common/linux/elf_core_dump.cc src/common/linux/elfutils.cc \ + src/common/linux/elfutils.h src/common/linux/file_id.cc \ + src/common/linux/file_id.h src/common/linux/guid_creator.cc \ + src/common/linux/guid_creator.h \ + src/common/linux/linux_libc_support.cc \ + src/common/linux/memory_mapped_file.cc \ + src/common/linux/safe_readlink.cc $(am__append_23) + +# Client tests +src_client_linux_linux_dumper_unittest_helper_SOURCES = \ + src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc + +src_client_linux_linux_dumper_unittest_helper_LDFLAGS = $(PTHREAD_CFLAGS) +src_client_linux_linux_dumper_unittest_helper_CC = $(PTHREAD_CC) +@ANDROID_HOST_FALSE@src_client_linux_linux_dumper_unittest_helper_CXXFLAGS = $(PTHREAD_CFLAGS) +# On Android PTHREAD_CFLAGS is empty, and adding src/common/android/include +# to the include path is necessary to build this program. +@ANDROID_HOST_TRUE@src_client_linux_linux_dumper_unittest_helper_CXXFLAGS = $(AM_CXXFLAGS) +src_client_linux_linux_client_unittest_shlib_SOURCES = \ + $(src_testing_libtesting_a_SOURCES) \ + src/client/linux/handler/exception_handler_unittest.cc \ + src/client/linux/microdump_writer/microdump_writer_unittest.cc \ + src/client/linux/minidump_writer/directory_reader_unittest.cc \ + src/client/linux/minidump_writer/cpu_set_unittest.cc \ + src/client/linux/minidump_writer/line_reader_unittest.cc \ + src/client/linux/minidump_writer/linux_core_dumper.cc \ + src/client/linux/minidump_writer/linux_core_dumper_unittest.cc \ + src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc \ + src/client/linux/minidump_writer/minidump_writer_unittest.cc \ + src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc \ + src/client/linux/minidump_writer/pe_file.cc \ + src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc \ + src/common/linux/elf_core_dump.cc \ + src/common/linux/linux_libc_support_unittest.cc \ + src/common/linux/scoped_pipe.h src/common/linux/scoped_pipe.cc \ + src/common/linux/scoped_tmpfile.h \ + src/common/linux/scoped_tmpfile.cc \ + src/common/linux/tests/crash_generator.cc \ + src/common/memory_allocator_unittest.cc \ + src/common/tests/auto_tempdir.h src/common/tests/file_utils.cc \ + src/common/tests/file_utils.h \ + src/processor/basic_code_modules.cc \ + src/processor/convert_old_arm64_context.cc \ + src/processor/dump_context.cc src/processor/dump_object.cc \ + src/processor/logging.cc src/processor/minidump.cc \ + src/processor/pathname_stripper.cc \ + src/processor/proc_maps_linux.cc $(am__append_24) +src_client_linux_linux_client_unittest_shlib_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_client_linux_linux_client_unittest_shlib_LDFLAGS = -shared \ + -Wl,-h,linux_client_unittest_shlib $(am__append_25) +src_client_linux_linux_client_unittest_shlib_LDADD = \ + src/client/linux/crash_generation/crash_generation_client.o \ + src/client/linux/dump_writer_common/thread_info.o \ + src/client/linux/dump_writer_common/ucontext_reader.o \ + src/client/linux/handler/exception_handler.o \ + src/client/linux/handler/minidump_descriptor.o \ + src/client/linux/log/log.o \ + src/client/linux/microdump_writer/microdump_writer.o \ + src/client/linux/minidump_writer/linux_dumper.o \ + src/client/linux/minidump_writer/linux_ptrace_dumper.o \ + src/client/linux/minidump_writer/minidump_writer.o \ + src/client/minidump_file_writer.o \ + src/common/convert_UTF.o \ + src/common/md5.o \ + src/common/linux/elfutils.o \ + src/common/linux/file_id.o \ + src/common/linux/guid_creator.o \ + src/common/linux/linux_libc_support.o \ + src/common/linux/memory_mapped_file.o \ + src/common/linux/safe_readlink.o \ + src/common/string_conversion.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_client_linux_linux_client_unittest_shlib_DEPENDENCIES = \ + src/client/linux/linux_dumper_unittest_helper \ + src/client/linux/libbreakpad_client.a \ + $(TEST_DEPS) \ + src/libbreakpad.a + +src_client_linux_linux_client_unittest_SOURCES = +# The extra-long build id is for a test in minidump_writer_unittest.cc. +src_client_linux_linux_client_unittest_LDFLAGS = \ + -Wl,-rpath,'$$ORIGIN' \ + -Wl,--build-id=0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \ + $(am__append_26) +src_client_linux_linux_client_unittest_LDADD = \ + src/client/linux/linux_client_unittest_shlib \ + $(TEST_LIBS) + +src_client_linux_linux_client_unittest_DEPENDENCIES = \ + src/client/linux/linux_client_unittest_shlib + + +# Tools +src_tools_linux_core2md_core2md_SOURCES = \ + src/tools/linux/core2md/core2md.cc + +src_tools_linux_core2md_core2md_LDADD = \ + src/client/linux/libbreakpad_client.a \ + src/common/path_helper.o + +src_tools_linux_core_handler_core_handler_SOURCES = \ + src/tools/linux/core_handler/core_handler.cc + +src_tools_linux_core_handler_core_handler_LDADD = \ + src/client/linux/libbreakpad_client.a \ + src/common/path_helper.o + +src_tools_linux_pid2md_pid2md_SOURCES = \ + src/tools/linux/pid2md/pid2md.cc + +src_tools_linux_pid2md_pid2md_LDADD = \ + src/client/linux/libbreakpad_client.a \ + src/common/path_helper.o + +src_tools_linux_dump_syms_dump_syms_SOURCES = \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_line_to_module.cc \ + src/common/dwarf_range_list_handler.cc \ + src/common/language.cc \ + src/common/module.cc \ + src/common/path_helper.cc \ + src/common/stabs_reader.cc \ + src/common/stabs_to_module.cc \ + src/common/dwarf/bytereader.cc \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2reader.cc \ + src/common/dwarf/elf_reader.cc \ + src/common/linux/crc32.cc \ + src/common/linux/dump_symbols.cc \ + src/common/linux/dump_symbols.h \ + src/common/linux/elf_symbols_to_module.cc \ + src/common/linux/elf_symbols_to_module.h \ + src/common/linux/elfutils.cc \ + src/common/linux/file_id.cc \ + src/common/linux/linux_libc_support.cc \ + src/common/linux/memory_mapped_file.cc \ + src/common/linux/safe_readlink.cc \ + src/tools/linux/dump_syms/dump_syms.cc + +src_tools_linux_dump_syms_dump_syms_CXXFLAGS = \ + $(RUSTC_DEMANGLE_CFLAGS) \ + $(ZSTD_CFLAGS) + +src_tools_linux_dump_syms_dump_syms_LDADD = \ + $(RUSTC_DEMANGLE_LIBS) \ + $(ZSTD_CFLAGS) \ + -lz + +src_tools_linux_md2core_minidump_2_core_SOURCES = \ + src/common/linux/memory_mapped_file.cc \ + src/common/path_helper.cc \ + src/tools/linux/md2core/minidump-2-core.cc \ + src/tools/linux/md2core/minidump_memory_range.h + +src_tools_linux_symupload_minidump_upload_SOURCES = \ + src/common/linux/http_upload.cc \ + src/common/path_helper.cc \ + src/tools/linux/symupload/minidump_upload.cc + +src_tools_linux_symupload_minidump_upload_LDADD = -ldl +src_tools_linux_symupload_sym_upload_SOURCES = \ + src/common/linux/http_upload.cc \ + src/common/linux/http_upload.h \ + src/common/linux/libcurl_wrapper.cc \ + src/common/linux/libcurl_wrapper.h \ + src/common/linux/symbol_collector_client.cc \ + src/common/linux/symbol_collector_client.h \ + src/common/linux/symbol_upload.cc \ + src/common/linux/symbol_upload.h \ + src/common/path_helper.cc \ + src/tools/linux/symupload/sym_upload.cc + +src_tools_linux_symupload_sym_upload_LDADD = -ldl +src_tools_mac_dump_syms_dump_syms_mac_SOURCES = \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_line_to_module.cc \ + src/common/dwarf_range_list_handler.cc \ + src/common/language.cc \ + src/common/md5.cc \ + src/common/module.cc \ + src/common/path_helper.cc \ + src/common/stabs_reader.cc \ + src/common/stabs_to_module.cc \ + src/common/dwarf/bytereader.cc \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2reader.cc \ + src/common/dwarf/elf_reader.cc \ + src/common/mac/arch_utilities.cc \ + src/common/mac/dump_syms.cc \ + src/common/mac/dump_syms.h \ + src/common/mac/file_id.cc \ + src/common/mac/file_id.h \ + src/common/mac/macho_id.cc \ + src/common/mac/macho_id.h \ + src/common/mac/macho_reader.cc \ + src/common/mac/macho_reader.h \ + src/common/mac/macho_utilities.cc \ + src/common/mac/macho_utilities.h \ + src/common/mac/macho_walker.cc \ + src/common/mac/macho_walker.h \ + src/tools/mac/dump_syms/dump_syms_tool.cc + +src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS = \ + -I$(top_srcdir)/src/third_party/mac_headers \ + $(RUSTC_DEMANGLE_CFLAGS) \ + -DHAVE_MACH_O_NLIST_H + +src_tools_mac_dump_syms_dump_syms_mac_LDADD = \ + $(RUSTC_DEMANGLE_LIBS) + +src_common_dumper_unittest_SOURCES = \ + src/common/byte_cursor_unittest.cc \ + src/common/convert_UTF.cc \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cfi_to_module_unittest.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_cu_to_module_unittest.cc \ + src/common/dwarf_line_to_module.cc \ + src/common/dwarf_line_to_module_unittest.cc \ + src/common/dwarf_range_list_handler.cc \ + src/common/language.cc \ + src/common/memory_range_unittest.cc \ + src/common/module.cc \ + src/common/module_unittest.cc \ + src/common/path_helper.cc \ + src/common/stabs_reader.cc \ + src/common/stabs_reader_unittest.cc \ + src/common/stabs_to_module.cc \ + src/common/stabs_to_module_unittest.cc \ + src/common/string_conversion.cc \ + src/common/string_conversion_unittest.cc \ + src/common/test_assembler.cc \ + src/common/dwarf/bytereader.cc \ + src/common/dwarf/bytereader.h \ + src/common/dwarf/bytereader-inl.h \ + src/common/dwarf/bytereader_unittest.cc \ + src/common/dwarf/cfi_assembler.cc \ + src/common/dwarf/cfi_assembler.h \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2diehandler_unittest.cc \ + src/common/dwarf/dwarf2reader.cc \ + src/common/dwarf/dwarf2reader.h \ + src/common/dwarf/elf_reader.cc \ + src/common/dwarf/elf_reader.h \ + src/common/dwarf/dwarf2reader_cfi_unittest.cc \ + src/common/dwarf/dwarf2reader_die_unittest.cc \ + src/common/dwarf/dwarf2reader_test_common.h \ + src/common/linux/crc32.cc \ + src/common/linux/dump_symbols.cc \ + src/common/linux/dump_symbols_unittest.cc \ + src/common/linux/elf_core_dump.cc \ + src/common/linux/elf_core_dump_unittest.cc \ + src/common/linux/elf_symbols_to_module.cc \ + src/common/linux/elf_symbols_to_module_unittest.cc \ + src/common/linux/elfutils.cc \ + src/common/linux/file_id.cc \ + src/common/linux/file_id_unittest.cc \ + src/common/linux/linux_libc_support.cc \ + src/common/linux/memory_mapped_file.cc \ + src/common/linux/memory_mapped_file_unittest.cc \ + src/common/linux/safe_readlink.cc \ + src/common/linux/safe_readlink_unittest.cc \ + src/common/linux/synth_elf.cc \ + src/common/linux/synth_elf_unittest.cc \ + src/common/linux/tests/crash_generator.cc \ + src/common/linux/tests/crash_generator.h \ + src/common/testdata/func-line-pairing.h \ + src/common/tests/file_utils.cc + +src_common_dumper_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) \ + $(RUSTC_DEMANGLE_CFLAGS) \ + $(PTHREAD_CFLAGS) \ + $(ZSTD_CFLAGS) + +src_common_dumper_unittest_LDADD = \ + $(TEST_LIBS) \ + $(RUSTC_DEMANGLE_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \ + $(ZSTD_LIBS) \ + -lz + +src_common_mac_macho_reader_unittest_SOURCES = \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_line_to_module.cc \ + src/common/language.cc \ + src/common/md5.cc \ + src/common/module.cc \ + src/common/path_helper.cc \ + src/common/stabs_reader.cc \ + src/common/stabs_to_module.cc \ + src/common/test_assembler.cc \ + src/common/dwarf/bytereader.cc \ + src/common/dwarf/cfi_assembler.cc \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2reader.cc \ + src/common/dwarf/elf_reader.cc \ + src/common/mac/arch_utilities.cc \ + src/common/mac/file_id.cc \ + src/common/mac/macho_id.cc \ + src/common/mac/macho_reader.cc \ + src/common/mac/macho_reader_unittest.cc \ + src/common/mac/macho_utilities.cc \ + src/common/mac/macho_walker.cc \ + src/common/tests/file_utils.cc + +src_common_mac_macho_reader_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) \ + -I$(top_srcdir)/src/third_party/mac_headers \ + -DHAVE_MACH_O_NLIST_H \ + $(PTHREAD_CFLAGS) + +src_common_mac_macho_reader_unittest_LDADD = \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_common_linux_google_crashdump_uploader_test_SOURCES = \ + src/common/linux/google_crashdump_uploader.cc \ + src/common/linux/google_crashdump_uploader_test.cc \ + src/common/linux/libcurl_wrapper.cc + +src_common_linux_google_crashdump_uploader_test_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_common_linux_google_crashdump_uploader_test_LDADD = \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \ + -ldl + +src_tools_linux_md2core_minidump_2_core_unittest_SOURCES = \ + src/tools/linux/md2core/minidump_memory_range_unittest.cc + +src_tools_linux_md2core_minidump_2_core_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_tools_linux_md2core_minidump_2_core_unittest_LDADD = \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_address_map_unittest_SOURCES = \ + src/processor/address_map_unittest.cc + +src_processor_address_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o + +src_processor_basic_source_line_resolver_unittest_SOURCES = \ + src/processor/basic_source_line_resolver_unittest.cc + +src_processor_basic_source_line_resolver_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_basic_source_line_resolver_unittest_LDADD = \ + src/processor/basic_source_line_resolver.o \ + src/processor/cfi_frame_info.o \ + src/processor/pathname_stripper.o \ + src/processor/logging.o \ + src/processor/source_line_resolver_base.o \ + src/processor/tokenize.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_cfi_frame_info_unittest_SOURCES = \ + src/processor/cfi_frame_info_unittest.cc + +src_processor_cfi_frame_info_unittest_LDADD = \ + src/processor/cfi_frame_info.o \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_cfi_frame_info_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_contained_range_map_unittest_SOURCES = \ + src/processor/contained_range_map_unittest.cc + +src_processor_contained_range_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o + +src_processor_exploitability_unittest_SOURCES = \ + src/processor/exploitability_unittest.cc + +src_processor_exploitability_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_exploitability_unittest_LDADD = \ + src/processor/convert_old_arm64_context.o \ + src/processor/minidump_processor.o \ + src/processor/process_state.o src/processor/disassembler_x86.o \ + src/processor/exploitability.o \ + src/processor/exploitability_linux.o \ + src/processor/exploitability_win.o \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o src/processor/cfi_frame_info.o \ + src/processor/dump_context.o src/processor/dump_object.o \ + src/processor/logging.o src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/proc_maps_linux.o \ + src/processor/simple_symbol_supplier.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o \ + src/processor/symbolic_constants_win.o \ + src/processor/tokenize.o src/third_party/libdisasm/libdisasm.a \ + $(TEST_LIBS) $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \ + $(am__append_27) +src_common_linux_scoped_pipe_unittest_SOURCES = \ + src/common/linux/scoped_pipe_unittest.cc + +src_common_linux_scoped_pipe_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_common_linux_scoped_pipe_unittest_LDADD = \ + src/common/linux/scoped_pipe.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_common_linux_scoped_tmpfile_unittest_SOURCES = \ + src/common/linux/scoped_tmpfile_unittest.cc + +src_common_linux_scoped_tmpfile_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_common_linux_scoped_tmpfile_unittest_LDADD = \ + src/common/linux/scoped_tmpfile.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_disassembler_objdump_unittest_SOURCES = \ + src/processor/disassembler_objdump_unittest.cc + +src_processor_disassembler_objdump_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_disassembler_objdump_unittest_LDADD = \ + src/common/linux/scoped_pipe.o \ + src/common/linux/scoped_tmpfile.o \ + src/processor/disassembler_objdump.o \ + src/processor/dump_context.o \ + src/processor/dump_object.o \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_disassembler_x86_unittest_SOURCES = \ + src/processor/disassembler_x86_unittest.cc + +src_processor_disassembler_x86_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_disassembler_x86_unittest_LDADD = \ + src/processor/disassembler_x86.o \ + src/third_party/libdisasm/libdisasm.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_fast_source_line_resolver_unittest_SOURCES = \ + src/processor/fast_source_line_resolver_unittest.cc + +src_processor_fast_source_line_resolver_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_fast_source_line_resolver_unittest_LDADD = \ + src/processor/fast_source_line_resolver.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/cfi_frame_info.o \ + src/processor/module_comparer.o \ + src/processor/module_serializer.o \ + src/processor/pathname_stripper.o \ + src/processor/logging.o \ + src/processor/source_line_resolver_base.o \ + src/processor/tokenize.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_map_serializers_unittest_SOURCES = \ + src/processor/map_serializers_unittest.cc + +src_processor_map_serializers_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_map_serializers_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_microdump_processor_unittest_SOURCES = \ + src/processor/microdump_processor_unittest.cc + +src_processor_microdump_processor_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_microdump_processor_unittest_LDADD = \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/cfi_frame_info.o src/processor/dump_context.o \ + src/processor/dump_object.o src/processor/logging.o \ + src/processor/microdump.o src/processor/microdump_processor.o \ + src/processor/pathname_stripper.o \ + src/processor/process_state.o \ + src/processor/simple_symbol_supplier.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o src/processor/tokenize.o \ + $(TEST_LIBS) $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \ + $(am__append_28) +src_processor_minidump_processor_unittest_SOURCES = \ + src/processor/minidump_processor_unittest.cc + +src_processor_minidump_processor_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_minidump_processor_unittest_LDADD = \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o src/processor/cfi_frame_info.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/disassembler_x86.o src/processor/dump_context.o \ + src/processor/dump_object.o src/processor/exploitability.o \ + src/processor/exploitability_linux.o \ + src/processor/exploitability_win.o src/processor/logging.o \ + src/processor/minidump_processor.o src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/process_state.o src/processor/proc_maps_linux.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o \ + src/processor/symbolic_constants_win.o \ + src/processor/tokenize.o src/third_party/libdisasm/libdisasm.a \ + $(TEST_LIBS) $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \ + $(am__append_29) +src_processor_minidump_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/minidump_unittest.cc \ + src/processor/synth_minidump.cc + +src_processor_minidump_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_minidump_unittest_LDADD = \ + src/processor/basic_code_modules.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/dump_context.o \ + src/processor/dump_object.o \ + src/processor/logging.o \ + src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/proc_maps_linux.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_proc_maps_linux_unittest_SOURCES = \ + src/processor/proc_maps_linux.cc \ + src/processor/proc_maps_linux_unittest.cc + +src_processor_proc_maps_linux_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_proc_maps_linux_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + src/third_party/libdisasm/libdisasm.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_static_address_map_unittest_SOURCES = \ + src/processor/static_address_map_unittest.cc + +src_processor_static_address_map_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_static_address_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_static_contained_range_map_unittest_SOURCES = \ + src/processor/static_contained_range_map_unittest.cc + +src_processor_static_contained_range_map_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_static_contained_range_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_static_map_unittest_SOURCES = \ + src/processor/static_map_unittest.cc + +src_processor_static_map_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_static_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_static_range_map_unittest_SOURCES = \ + src/processor/static_range_map_unittest.cc + +src_processor_static_range_map_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_static_range_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_pathname_stripper_unittest_SOURCES = \ + src/processor/pathname_stripper_unittest.cc + +src_processor_pathname_stripper_unittest_LDADD = \ + src/processor/pathname_stripper.o \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_postfix_evaluator_unittest_SOURCES = \ + src/processor/postfix_evaluator_unittest.cc + +src_processor_postfix_evaluator_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_range_map_truncate_lower_unittest_SOURCES = \ + src/processor/range_map_truncate_lower_unittest.cc + +src_processor_range_map_truncate_lower_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_range_map_truncate_lower_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_range_map_truncate_upper_unittest_SOURCES = \ + src/processor/range_map_truncate_upper_unittest.cc + +src_processor_range_map_truncate_upper_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_range_map_truncate_upper_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_range_map_unittest_SOURCES = \ + src/processor/range_map_unittest.cc -# Specify include paths for ac macros -ACLOCAL_AMFLAGS = -I m4 +src_processor_range_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) -# License file is called LICENSE not COPYING -AUTOMAKE_OPTIONS = foreign -dist_doc_DATA = \ - AUTHORS \ - ChangeLog \ - INSTALL \ - LICENSE \ - NEWS \ - README.md +src_processor_stackwalker_selftest_SOURCES = \ + src/processor/stackwalker_selftest.cc -@LINUX_HOST_TRUE@includeclhdir = $(includedir)/$(PACKAGE)/client/linux/handler -@LINUX_HOST_TRUE@includeclh_HEADERS = $(top_srcdir)/src/client/linux/handler/*.h -@LINUX_HOST_TRUE@includecldwcdir = $(includedir)/$(PACKAGE)/client/linux/dump_writer_common -@LINUX_HOST_TRUE@includecldwc_HEADERS = $(top_srcdir)/src/client/linux/dump_writer_common/*.h -@LINUX_HOST_TRUE@includeclmdir = $(includedir)/$(PACKAGE)/client/linux/minidump_writer -@LINUX_HOST_TRUE@includeclm_HEADERS = $(top_srcdir)/src/client/linux/minidump_writer/*.h -@LINUX_HOST_TRUE@includeclcdir = $(includedir)/$(PACKAGE)/client/linux/crash_generation -@LINUX_HOST_TRUE@includeclc_HEADERS = $(top_srcdir)/src/client/linux/crash_generation/*.h -@LINUX_HOST_TRUE@includelssdir = $(includedir)/$(PACKAGE)/third_party/lss -@LINUX_HOST_TRUE@includelss_HEADERS = $(top_srcdir)/src/third_party/lss/*.h -@LINUX_HOST_TRUE@includecldir = $(includedir)/$(PACKAGE)/common/linux -@LINUX_HOST_TRUE@includecl_HEADERS = $(top_srcdir)/src/common/linux/*.h -includegbcdir = $(includedir)/$(PACKAGE)/google_breakpad/common -includegbc_HEADERS = $(top_srcdir)/src/google_breakpad/common/*.h -includecdir = $(includedir)/$(PACKAGE)/common -includec_HEADERS = $(top_srcdir)/src/common/*.h -includepdir = $(includedir)/$(PACKAGE)/processor -includep_HEADERS = $(top_srcdir)/src/processor/*.h -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = $(am__append_5) $(am__append_8) -@SYSTEM_TEST_LIBS_FALSE@TEST_CFLAGS = \ -@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/include \ -@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/googletest/include \ -@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/googletest \ -@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/googlemock/include \ -@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/googlemock \ -@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing +src_processor_stackwalker_selftest_LDADD = \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o src/processor/disassembler_x86.o \ + src/processor/exploitability.o \ + src/processor/exploitability_linux.o \ + src/processor/exploitability_win.o src/processor/logging.o \ + src/processor/minidump.o src/processor/pathname_stripper.o \ + src/processor/proc_maps_linux.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o src/processor/tokenize.o \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) $(am__append_30) +src_processor_stackwalker_amd64_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_amd64_unittest.cc -@SYSTEM_TEST_LIBS_TRUE@TEST_CFLAGS = $(GTEST_CFLAGS) $(GMOCK_CFLAGS) -@SYSTEM_TEST_LIBS_FALSE@TEST_LIBS = src/testing/libtesting.a -@SYSTEM_TEST_LIBS_TRUE@TEST_LIBS = $(GTEST_LIBS) -lgtest_main $(GMOCK_LIBS) -@SYSTEM_TEST_LIBS_FALSE@TEST_DEPS = $(TEST_LIBS) -@SYSTEM_TEST_LIBS_TRUE@TEST_DEPS = -check_LIBRARIES = src/testing/libtesting.a -noinst_LIBRARIES = $(am__append_6) -lib_LIBRARIES = $(am__append_4) $(am__append_7) -CLEANFILES = $(am__append_12) -@SYSTEM_TEST_LIBS_FALSE@src_testing_libtesting_a_SOURCES = \ -@SYSTEM_TEST_LIBS_FALSE@ src/breakpad_googletest_includes.h \ -@SYSTEM_TEST_LIBS_FALSE@ src/testing/googletest/src/gtest-all.cc \ -@SYSTEM_TEST_LIBS_FALSE@ src/testing/googletest/src/gtest_main.cc \ -@SYSTEM_TEST_LIBS_FALSE@ src/testing/googlemock/src/gmock-all.cc +src_processor_stackwalker_amd64_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) -@SYSTEM_TEST_LIBS_FALSE@src_testing_libtesting_a_CPPFLAGS = \ -@SYSTEM_TEST_LIBS_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_stackwalker_amd64_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) -@LINUX_HOST_TRUE@src_client_linux_libbreakpad_client_a_SOURCES = src/client/linux/crash_generation/crash_generation_client.cc \ -@LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_server.cc \ -@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/thread_info.cc \ -@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/ucontext_reader.cc \ -@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.cc \ -@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.h \ -@LINUX_HOST_TRUE@ src/client/linux/handler/minidump_descriptor.cc \ -@LINUX_HOST_TRUE@ src/client/linux/handler/minidump_descriptor.h \ -@LINUX_HOST_TRUE@ src/client/linux/log/log.cc \ -@LINUX_HOST_TRUE@ src/client/linux/log/log.h \ -@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/microdump_writer.cc \ -@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/microdump_writer.h \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_core_dumper.cc \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper.cc \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper.cc \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer.cc \ -@LINUX_HOST_TRUE@ src/client/minidump_file_writer-inl.h \ -@LINUX_HOST_TRUE@ src/client/minidump_file_writer.cc \ -@LINUX_HOST_TRUE@ src/client/minidump_file_writer.h \ -@LINUX_HOST_TRUE@ src/common/convert_UTF.cc \ -@LINUX_HOST_TRUE@ src/common/convert_UTF.h src/common/md5.cc \ -@LINUX_HOST_TRUE@ src/common/md5.h \ -@LINUX_HOST_TRUE@ src/common/string_conversion.cc \ -@LINUX_HOST_TRUE@ src/common/string_conversion.h \ -@LINUX_HOST_TRUE@ src/common/linux/elf_core_dump.cc \ -@LINUX_HOST_TRUE@ src/common/linux/elfutils.cc \ -@LINUX_HOST_TRUE@ src/common/linux/elfutils.h \ -@LINUX_HOST_TRUE@ src/common/linux/file_id.cc \ -@LINUX_HOST_TRUE@ src/common/linux/file_id.h \ -@LINUX_HOST_TRUE@ src/common/linux/guid_creator.cc \ -@LINUX_HOST_TRUE@ src/common/linux/guid_creator.h \ -@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.cc \ -@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.cc \ -@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.cc \ -@LINUX_HOST_TRUE@ $(am__append_9) -@DISABLE_PROCESSOR_FALSE@src_libbreakpad_a_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/common/breakpad_types.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/common/minidump_format.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/common/minidump_size.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/basic_source_line_resolver.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/call_stack.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/code_module.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/code_modules.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/dump_context.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/dump_object.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/exploitability.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/fast_source_line_resolver.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/memory_region.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/microdump.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/microdump_processor.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/minidump.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/minidump_processor.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/process_result.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/process_state.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/proc_maps_linux.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/source_line_resolver_base.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/source_line_resolver_interface.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stack_frame.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stack_frame_cpu.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stack_frame_symbolizer.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stackwalker.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/symbol_supplier.h \ -@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/system_info.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/address_map-inl.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/address_map.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_module.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver_types.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/contained_range_map-inl.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/contained_range_map.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver_types.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/linked_ptr.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/map_serializers-inl.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/map_serializers.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/module_factory.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/postfix_evaluator-inl.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/postfix_evaluator.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/range_map-inl.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/range_map.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_serializer-inl.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_serializer.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/windows_frame_info.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base_types.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_address_map-inl.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_address_map.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_contained_range_map-inl.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_contained_range_map.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_map_iterator-inl.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_map_iterator.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_map-inl.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_map.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_range_map-inl.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_range_map.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.h - -@DISABLE_PROCESSOR_FALSE@src_third_party_libdisasm_libdisasm_a_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_implicit.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_implicit.h \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_insn.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_insn.h \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_invariant.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_invariant.h \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_modrm.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_modrm.h \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_opcode_tables.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_opcode_tables.h \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_operand.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_operand.h \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_reg.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_reg.h \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_settings.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_settings.h \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdis.h \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/qword.h \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_disasm.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_format.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_imm.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_imm.h \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_insn.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_misc.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_operand_list.c \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_operand_list.h +src_processor_stackwalker_arm_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_arm_unittest.cc -@DISABLE_PROCESSOR_FALSE@check_SCRIPTS = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk_test \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk_machine_readable_test \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_dump_test \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk_test \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk_machine_readable_test +src_processor_stackwalker_arm_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) -TESTS = $(check_PROGRAMS) $(check_SCRIPTS) -@ANDROID_HOST_FALSE@@TESTS_AS_ROOT_FALSE@LOG_DRIVER = $(top_srcdir)/autotools/test-driver -# The default Autotools test driver script. -@ANDROID_HOST_FALSE@@TESTS_AS_ROOT_TRUE@LOG_DRIVER = $(top_srcdir)/autotools/root-test-driver $(top_srcdir)/autotools/test-driver +src_processor_stackwalker_arm_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) -# Since Autotools 1.2, tests are run through a special "test driver" script. -# Unfortunately, it's not possible anymore to specify an alternative shell to -# run them on connected devices, so use a slightly modified version of the -# driver for Android. -@ANDROID_HOST_TRUE@LOG_DRIVER = $(top_srcdir)/android/test-driver -@LINUX_HOST_TRUE@src_client_linux_linux_dumper_unittest_helper_SOURCES = \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc +src_processor_stackwalker_arm64_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_arm64_unittest.cc -@LINUX_HOST_TRUE@src_client_linux_linux_dumper_unittest_helper_LDFLAGS = $(PTHREAD_CFLAGS) -@LINUX_HOST_TRUE@src_client_linux_linux_dumper_unittest_helper_CC = $(PTHREAD_CC) -@ANDROID_HOST_FALSE@@LINUX_HOST_TRUE@src_client_linux_linux_dumper_unittest_helper_CXXFLAGS = $(PTHREAD_CFLAGS) -# On Android PTHREAD_CFLAGS is empty, and adding src/common/android/include -# to the include path is necessary to build this program. -@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@src_client_linux_linux_dumper_unittest_helper_CXXFLAGS = $(AM_CXXFLAGS) -@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_SOURCES = \ -@LINUX_HOST_TRUE@ $(src_testing_libtesting_a_SOURCES) \ -@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler_unittest.cc \ -@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/microdump_writer_unittest.cc \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/directory_reader_unittest.cc \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/cpu_set_unittest.cc \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/line_reader_unittest.cc \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_core_dumper.cc \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_core_dumper_unittest.cc \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer_unittest.cc \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc \ -@LINUX_HOST_TRUE@ src/common/linux/elf_core_dump.cc \ -@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support_unittest.cc \ -@LINUX_HOST_TRUE@ src/common/linux/tests/auto_testfile.h \ -@LINUX_HOST_TRUE@ src/common/linux/tests/crash_generator.cc \ -@LINUX_HOST_TRUE@ src/common/memory_allocator_unittest.cc \ -@LINUX_HOST_TRUE@ src/common/tests/auto_tempdir.h \ -@LINUX_HOST_TRUE@ src/common/tests/file_utils.cc \ -@LINUX_HOST_TRUE@ src/common/tests/file_utils.h \ -@LINUX_HOST_TRUE@ src/processor/basic_code_modules.cc \ -@LINUX_HOST_TRUE@ src/processor/convert_old_arm64_context.cc \ -@LINUX_HOST_TRUE@ src/processor/dump_context.cc \ -@LINUX_HOST_TRUE@ src/processor/dump_object.cc \ -@LINUX_HOST_TRUE@ src/processor/logging.cc \ -@LINUX_HOST_TRUE@ src/processor/minidump.cc \ -@LINUX_HOST_TRUE@ src/processor/pathname_stripper.cc \ -@LINUX_HOST_TRUE@ src/processor/proc_maps_linux.cc \ -@LINUX_HOST_TRUE@ $(am__append_21) -@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_CPPFLAGS = \ -@LINUX_HOST_TRUE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_LDFLAGS = \ -@LINUX_HOST_TRUE@ -shared -Wl,-h,linux_client_unittest_shlib \ -@LINUX_HOST_TRUE@ $(am__append_22) -@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_LDADD = \ -@LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_client.o \ -@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/thread_info.o \ -@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/ucontext_reader.o \ -@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.o \ -@LINUX_HOST_TRUE@ src/client/linux/handler/minidump_descriptor.o \ -@LINUX_HOST_TRUE@ src/client/linux/log/log.o \ -@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/microdump_writer.o \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper.o \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper.o \ -@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer.o \ -@LINUX_HOST_TRUE@ src/client/minidump_file_writer.o \ -@LINUX_HOST_TRUE@ src/common/convert_UTF.o \ -@LINUX_HOST_TRUE@ src/common/md5.o \ -@LINUX_HOST_TRUE@ src/common/linux/elfutils.o \ -@LINUX_HOST_TRUE@ src/common/linux/file_id.o \ -@LINUX_HOST_TRUE@ src/common/linux/guid_creator.o \ -@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.o \ -@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.o \ -@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.o \ -@LINUX_HOST_TRUE@ src/common/string_conversion.o \ -@LINUX_HOST_TRUE@ $(TEST_LIBS) \ -@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_DEPENDENCIES = \ -@LINUX_HOST_TRUE@ src/client/linux/linux_dumper_unittest_helper \ -@LINUX_HOST_TRUE@ src/client/linux/libbreakpad_client.a \ -@LINUX_HOST_TRUE@ $(TEST_DEPS) \ -@LINUX_HOST_TRUE@ src/libbreakpad.a +src_processor_stackwalker_arm64_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) -@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_SOURCES = -# The extra-long build id is for a test in minidump_writer_unittest.cc. -@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_LDFLAGS = \ -@LINUX_HOST_TRUE@ -Wl,-rpath,'$$ORIGIN' \ -@LINUX_HOST_TRUE@ -Wl,--build-id=0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \ -@LINUX_HOST_TRUE@ $(am__append_23) -@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_LDADD = \ -@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest_shlib \ -@LINUX_HOST_TRUE@ $(TEST_LIBS) - -@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_DEPENDENCIES = \ -@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest_shlib +src_processor_stackwalker_arm64_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_address_list_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_address_list_unittest.cc + +src_processor_stackwalker_address_list_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_stackwalker_address_list_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_mips_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_mips_unittest.cc + +src_processor_stackwalker_mips_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_stackwalker_mips_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_mips64_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_mips64_unittest.cc + +src_processor_stackwalker_mips64_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_stackwalker_mips64_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_riscv_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_riscv_unittest.cc + +src_processor_stackwalker_riscv_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_stackwalker_riscv_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_riscv64_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_riscv64_unittest.cc + +src_processor_stackwalker_riscv64_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_stackwalker_riscv64_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_x86_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_x86_unittest.cc + +src_processor_stackwalker_x86_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_stackwalker_x86_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_synth_minidump_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/common/test_assembler.h \ + src/processor/synth_minidump_unittest.cc \ + src/processor/synth_minidump.cc \ + src/processor/synth_minidump.h + +src_processor_synth_minidump_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_synth_minidump_unittest_LDADD = \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_common_test_assembler_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/common/test_assembler.h \ + src/common/test_assembler_unittest.cc + +src_common_test_assembler_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_common_test_assembler_unittest_LDADD = \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_common_dwarf_dwarf2reader_lineinfo_unittest_SOURCES = \ + src/common/dwarf/dwarf2reader.h \ + src/common/dwarf/dwarf2reader_lineinfo_unittest.cc + +src_common_dwarf_dwarf2reader_lineinfo_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_common_dwarf_dwarf2reader_lineinfo_unittest_LDADD = \ + src/common/dwarf/bytereader.o \ + src/common/dwarf/dwarf2reader.o \ + src/common/dwarf/elf_reader.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_common_dwarf_dwarf2reader_splitfunctions_unittest_SOURCES = \ + src/common/dwarf/dwarf2reader.h \ + src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc + +src_common_dwarf_dwarf2reader_splitfunctions_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_common_dwarf_dwarf2reader_splitfunctions_unittest_LDADD = \ + src/common/dwarf/bytereader.o \ + src/common/dwarf/dwarf2reader.o \ + src/common/dwarf/elf_reader.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_core2md_core2md_SOURCES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/core2md/core2md.cc - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_core2md_core2md_LDADD = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/client/linux/libbreakpad_client.a - -@DISABLE_TOOLS_FALSE@@HAVE_MEMFD_CREATE_TRUE@@LINUX_HOST_TRUE@src_tools_linux_core_handler_core_handler_SOURCES = \ -@DISABLE_TOOLS_FALSE@@HAVE_MEMFD_CREATE_TRUE@@LINUX_HOST_TRUE@ src/tools/linux/core_handler/core_handler.cc - -@DISABLE_TOOLS_FALSE@@HAVE_MEMFD_CREATE_TRUE@@LINUX_HOST_TRUE@src_tools_linux_core_handler_core_handler_LDADD = \ -@DISABLE_TOOLS_FALSE@@HAVE_MEMFD_CREATE_TRUE@@LINUX_HOST_TRUE@ src/client/linux/libbreakpad_client.a - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_pid2md_pid2md_SOURCES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/pid2md/pid2md.cc - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_pid2md_pid2md_LDADD = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/client/linux/libbreakpad_client.a - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_dump_syms_dump_syms_SOURCES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_range_list_handler.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/language.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/path_helper.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/crc32.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elfutils.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/file_id.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/dump_syms/dump_syms.cc - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_dump_syms_dump_syms_CXXFLAGS = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(RUST_DEMANGLE_CFLAGS) - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_dump_syms_dump_syms_LDADD = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(RUST_DEMANGLE_LIBS) - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_md2core_minidump_2_core_SOURCES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/path_helper.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump-2-core.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump_memory_range.h - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_symupload_minidump_upload_SOURCES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/http_upload.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/minidump_upload.cc - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_symupload_minidump_upload_LDADD = -ldl -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_symupload_sym_upload_SOURCES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/http_upload.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/http_upload.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/libcurl_wrapper.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/libcurl_wrapper.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/symbol_collector_client.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/symbol_collector_client.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/symbol_upload.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/symbol_upload.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/sym_upload.cc - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_symupload_sym_upload_LDADD = -ldl -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_mac_dump_syms_dump_syms_mac_SOURCES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_range_list_handler.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/language.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/md5.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/path_helper.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/arch_utilities.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/dump_syms.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/dump_syms.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/file_id.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/file_id.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_id.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_id.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_utilities.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_utilities.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_walker.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_walker.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/mac/dump_syms/dump_syms_tool.cc - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ -I$(top_srcdir)/src/third_party/mac_headers \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(RUST_DEMANGLE_CFLAGS) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ -DHAVE_MACH_O_NLIST_H - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_mac_dump_syms_dump_syms_mac_LDADD = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(RUST_DEMANGLE_LIBS) - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_dumper_unittest_SOURCES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/byte_cursor_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/convert_UTF.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_range_list_handler.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/language.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/memory_range_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/path_helper.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/string_conversion.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/string_conversion_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/test_assembler.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader-inl.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/cfi_assembler.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/cfi_assembler.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader_cfi_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader_die_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader_test_common.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/crc32.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_core_dump.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_core_dump_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elfutils.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/file_id.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/file_id_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/safe_readlink_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/synth_elf.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/synth_elf_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tests/crash_generator.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tests/crash_generator.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/testdata/func-line-pairing.h \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tests/file_utils.cc - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_dumper_unittest_CPPFLAGS = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(RUST_DEMANGLE_CFLAGS) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_dumper_unittest_LDADD = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(TEST_LIBS) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(RUST_DEMANGLE_LIBS) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_mac_macho_reader_unittest_SOURCES = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/language.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/md5.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/path_helper.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/test_assembler.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/cfi_assembler.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/arch_utilities.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/file_id.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_id.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader_unittest.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_utilities.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_walker.cc \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tests/file_utils.cc - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_mac_macho_reader_unittest_CPPFLAGS = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ -I$(top_srcdir)/src/third_party/mac_headers \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ -DHAVE_MACH_O_NLIST_H \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) - -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_mac_macho_reader_unittest_LDADD = \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(TEST_LIBS) \ -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@LINUX_HOST_TRUE@src_common_linux_google_crashdump_uploader_test_SOURCES = \ -@LINUX_HOST_TRUE@ src/common/linux/google_crashdump_uploader.cc \ -@LINUX_HOST_TRUE@ src/common/linux/google_crashdump_uploader_test.cc \ -@LINUX_HOST_TRUE@ src/common/linux/libcurl_wrapper.cc - -@LINUX_HOST_TRUE@src_common_linux_google_crashdump_uploader_test_CPPFLAGS = \ -@LINUX_HOST_TRUE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@LINUX_HOST_TRUE@src_common_linux_google_crashdump_uploader_test_LDADD = \ -@LINUX_HOST_TRUE@ $(TEST_LIBS) \ -@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \ -@LINUX_HOST_TRUE@ -ldl - -@LINUX_HOST_TRUE@src_tools_linux_md2core_minidump_2_core_unittest_SOURCES = \ -@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump_memory_range_unittest.cc - -@LINUX_HOST_TRUE@src_tools_linux_md2core_minidump_2_core_unittest_CPPFLAGS = \ -@LINUX_HOST_TRUE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@LINUX_HOST_TRUE@src_tools_linux_md2core_minidump_2_core_unittest_LDADD = \ -@LINUX_HOST_TRUE@ $(TEST_LIBS) \ -@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_address_map_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/address_map_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_address_map_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o - -@DISABLE_PROCESSOR_FALSE@src_processor_basic_source_line_resolver_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_basic_source_line_resolver_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_basic_source_line_resolver_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_contained_range_map_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/contained_range_map_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_contained_range_map_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o - -@DISABLE_PROCESSOR_FALSE@src_processor_exploitability_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_exploitability_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_exploitability_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_disassembler_x86_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_disassembler_x86_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_disassembler_x86_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_map_serializers_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/map_serializers_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_map_serializers_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_map_serializers_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_microdump_processor_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_microdump_processor_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_microdump_processor_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_unittest.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_proc_maps_linux_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_proc_maps_linux_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_proc_maps_linux_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_static_address_map_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_address_map_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_static_address_map_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_static_address_map_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_static_contained_range_map_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_contained_range_map_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_static_contained_range_map_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_static_contained_range_map_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_static_map_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_map_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_static_map_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_static_map_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_static_range_map_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/static_range_map_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_static_range_map_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_static_range_map_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_pathname_stripper_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_pathname_stripper_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_postfix_evaluator_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/postfix_evaluator_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_postfix_evaluator_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_range_map_truncate_lower_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/range_map_truncate_lower_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_range_map_truncate_lower_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_range_map_truncate_lower_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_range_map_truncate_upper_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/range_map_truncate_upper_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_range_map_truncate_upper_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_range_map_truncate_upper_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_range_map_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/range_map_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_range_map_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_selftest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_selftest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_selftest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_amd64_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_amd64_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_amd64_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm64_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm64_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm64_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_address_list_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_address_list_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_address_list_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips64_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips64_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips64_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips64_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_x86_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_x86_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_x86_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_synth_minidump_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.h \ -@DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump_unittest.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump.cc \ -@DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump.h - -@DISABLE_PROCESSOR_FALSE@src_processor_synth_minidump_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_processor_synth_minidump_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_common_test_assembler_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.h \ -@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_common_test_assembler_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_common_test_assembler_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_common_dwarf_dwarf2reader_lineinfo_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/dwarf2reader.h \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/dwarf2reader_lineinfo_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_common_dwarf_dwarf2reader_lineinfo_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_common_dwarf_dwarf2reader_lineinfo_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/bytereader.o \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/dwarf2reader.o \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/elf_reader.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@src_common_dwarf_dwarf2reader_splitfunctions_unittest_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/dwarf2reader.h \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc - -@DISABLE_PROCESSOR_FALSE@src_common_dwarf_dwarf2reader_splitfunctions_unittest_CPPFLAGS = \ -@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) - -@DISABLE_PROCESSOR_FALSE@src_common_dwarf_dwarf2reader_splitfunctions_unittest_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/bytereader.o \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/dwarf2reader.o \ -@DISABLE_PROCESSOR_FALSE@ src/common/dwarf/elf_reader.o \ -@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ -@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) - -@DISABLE_PROCESSOR_FALSE@noinst_SCRIPTS = $(check_SCRIPTS) -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_dump_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_dump.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_dump_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o - -@DISABLE_PROCESSOR_FALSE@src_processor_microdump_stackwalk_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_microdump_stackwalk_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/common/path_helper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a - -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_SOURCES = \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk.cc - -@DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_LDADD = \ -@DISABLE_PROCESSOR_FALSE@ src/common/path_helper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/convert_old_arm64_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.o \ -@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ -@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a +src_processor_minidump_dump_SOURCES = \ + src/processor/minidump_dump.cc + +src_processor_minidump_dump_LDADD = \ + src/common/path_helper.o \ + src/processor/basic_code_modules.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/dump_context.o \ + src/processor/dump_object.o \ + src/processor/logging.o \ + src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/proc_maps_linux.o + +src_processor_microdump_stackwalk_SOURCES = \ + src/processor/microdump_stackwalk.cc + +src_processor_microdump_stackwalk_LDADD = src/common/path_helper.o \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/cfi_frame_info.o \ + src/processor/disassembler_x86.o src/processor/dump_context.o \ + src/processor/dump_object.o src/processor/logging.o \ + src/processor/microdump.o src/processor/microdump_processor.o \ + src/processor/pathname_stripper.o \ + src/processor/process_state.o \ + src/processor/simple_symbol_supplier.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalk_common.o src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o src/processor/tokenize.o \ + src/third_party/libdisasm/libdisasm.a $(am__append_31) +src_processor_minidump_stackwalk_SOURCES = \ + src/processor/minidump_stackwalk.cc +src_processor_minidump_stackwalk_LDADD = src/common/path_helper.o \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o src/processor/cfi_frame_info.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/disassembler_x86.o src/processor/dump_context.o \ + src/processor/dump_object.o src/processor/exploitability.o \ + src/processor/exploitability_linux.o \ + src/processor/exploitability_win.o src/processor/logging.o \ + src/processor/minidump.o src/processor/minidump_processor.o \ + src/processor/pathname_stripper.o \ + src/processor/process_state.o src/processor/proc_maps_linux.o \ + src/processor/simple_symbol_supplier.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalk_common.o src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_riscv.o \ + src/processor/stackwalker_riscv64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o \ + src/processor/symbolic_constants_win.o \ + src/processor/tokenize.o src/third_party/libdisasm/libdisasm.a \ + $(am__append_32) EXTRA_DIST = \ $(SCRIPTS) \ src/client/linux/data/linux-gate-amd.sym \ @@ -3653,13 +3563,10 @@ EXTRA_DIST = \ src/client/solaris/handler/minidump_test.cc \ src/client/solaris/handler/solaris_lwp.cc \ src/client/solaris/handler/solaris_lwp.h \ - src/client/windows/breakpad_client.gyp \ src/client/windows/handler/exception_handler.cc \ src/client/windows/handler/exception_handler.h \ - src/client/windows/handler/exception_handler.gyp \ src/client/windows/sender/crash_report_sender.cc \ src/client/windows/sender/crash_report_sender.h \ - src/client/windows/sender/crash_report_sender.gyp \ src/common/dwarf/dwarf2diehandler.h \ src/common/dwarf/dwarf2enums.h \ src/common/dwarf/line_state_machine.h \ @@ -3829,10 +3736,12 @@ EXTRA_DIST = \ src/third_party/curl/typecheck-gcc.h \ src/third_party/curl/types.h \ src/third_party/mac_headers/architecture/byte_order.h \ + src/third_party/mac_headers/arm/_types.h \ src/third_party/mac_headers/i386/_types.h \ src/third_party/mac_headers/mach/boolean.h \ + src/third_party/mac_headers/mach/arm/boolean.h \ + src/third_party/mac_headers/mach/arm/vm_types.h \ src/third_party/mac_headers/mach/i386/boolean.h \ - src/third_party/mac_headers/mach/i386/vm_param.h \ src/third_party/mac_headers/mach/i386/vm_types.h \ src/third_party/mac_headers/mach/machine/boolean.h \ src/third_party/mac_headers/mach/machine.h \ @@ -3869,9 +3778,7 @@ EXTRA_DIST = \ src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym \ src/tools/windows/converter/ms_symbol_server_converter.cc \ src/tools/windows/converter/ms_symbol_server_converter.h \ - src/tools/windows/converter/ms_symbol_server_converter.gyp \ src/tools/windows/dump_syms/dump_syms.cc \ - src/tools/windows/dump_syms/dump_syms.gyp \ src/tools/windows/dump_syms/run_regtest.sh \ src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc \ src/tools/windows/dump_syms/testdata/dump_syms_regtest.pdb \ @@ -3881,8 +3788,7 @@ EXTRA_DIST = \ src/tools/windows/dump_syms/testdata/omap_reorder_funcs.sym \ src/tools/windows/dump_syms/testdata/omap_stretched.sym \ src/tools/windows/dump_syms/testdata/omap_stretched_filled.sym \ - src/tools/windows/symupload/symupload.cc \ - src/tools/windows/symupload/symupload.gyp + src/tools/windows/symupload/symupload.cc all: all-am @@ -4139,6 +4045,9 @@ src/client/linux/minidump_writer/linux_ptrace_dumper.$(OBJEXT): \ src/client/linux/minidump_writer/minidump_writer.$(OBJEXT): \ src/client/linux/minidump_writer/$(am__dirstamp) \ src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/pe_file.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) src/client/$(am__dirstamp): @$(MKDIR_P) src/client @: > src/client/$(am__dirstamp) @@ -4296,6 +4205,12 @@ src/processor/stackwalker_ppc.$(OBJEXT): \ src/processor/stackwalker_ppc64.$(OBJEXT): \ src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_riscv.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_riscv64.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) src/processor/stackwalker_sparc.$(OBJEXT): \ src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) @@ -4307,6 +4222,15 @@ src/processor/symbolic_constants_win.$(OBJEXT): \ src/processor/$(DEPDIR)/$(am__dirstamp) src/processor/tokenize.$(OBJEXT): src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) +src/common/linux/scoped_pipe.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/scoped_tmpfile.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/processor/disassembler_objdump.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) src/$(am__dirstamp): @$(MKDIR_P) src @: > src/$(am__dirstamp) @@ -4440,6 +4364,9 @@ src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_uni src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_unittest_utils.$(OBJEXT): \ src/client/linux/minidump_writer/$(am__dirstamp) \ src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) src/client/linux/minidump_writer/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.$(OBJEXT): \ src/client/linux/minidump_writer/$(am__dirstamp) \ src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) @@ -4449,6 +4376,12 @@ src/common/linux/client_linux_linux_client_unittest_shlib-elf_core_dump.$(OBJEXT src/common/linux/client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.$(OBJEXT): \ src/common/linux/$(am__dirstamp) \ src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/client_linux_linux_client_unittest_shlib-scoped_pipe.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/client_linux_linux_client_unittest_shlib-scoped_tmpfile.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) src/common/linux/tests/$(am__dirstamp): @$(MKDIR_P) src/common/linux/tests @: > src/common/linux/tests/$(am__dirstamp) @@ -4695,6 +4628,20 @@ src/common/linux/google_crashdump_uploader_test-libcurl_wrapper.$(OBJEXT): \ src/common/linux/google_crashdump_uploader_test$(EXEEXT): $(src_common_linux_google_crashdump_uploader_test_OBJECTS) $(src_common_linux_google_crashdump_uploader_test_DEPENDENCIES) $(EXTRA_src_common_linux_google_crashdump_uploader_test_DEPENDENCIES) src/common/linux/$(am__dirstamp) @rm -f src/common/linux/google_crashdump_uploader_test$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(src_common_linux_google_crashdump_uploader_test_OBJECTS) $(src_common_linux_google_crashdump_uploader_test_LDADD) $(LIBS) +src/common/linux/scoped_pipe_unittest-scoped_pipe_unittest.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) + +src/common/linux/scoped_pipe_unittest$(EXEEXT): $(src_common_linux_scoped_pipe_unittest_OBJECTS) $(src_common_linux_scoped_pipe_unittest_DEPENDENCIES) $(EXTRA_src_common_linux_scoped_pipe_unittest_DEPENDENCIES) src/common/linux/$(am__dirstamp) + @rm -f src/common/linux/scoped_pipe_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_common_linux_scoped_pipe_unittest_OBJECTS) $(src_common_linux_scoped_pipe_unittest_LDADD) $(LIBS) +src/common/linux/scoped_tmpfile_unittest-scoped_tmpfile_unittest.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) + +src/common/linux/scoped_tmpfile_unittest$(EXEEXT): $(src_common_linux_scoped_tmpfile_unittest_OBJECTS) $(src_common_linux_scoped_tmpfile_unittest_DEPENDENCIES) $(EXTRA_src_common_linux_scoped_tmpfile_unittest_DEPENDENCIES) src/common/linux/$(am__dirstamp) + @rm -f src/common/linux/scoped_tmpfile_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_common_linux_scoped_tmpfile_unittest_OBJECTS) $(src_common_linux_scoped_tmpfile_unittest_LDADD) $(LIBS) src/common/mac_macho_reader_unittest-dwarf_cfi_to_module.$(OBJEXT): \ src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) @@ -4774,6 +4721,13 @@ src/common/tests/mac_macho_reader_unittest-file_utils.$(OBJEXT): \ src/common/mac/macho_reader_unittest$(EXEEXT): $(src_common_mac_macho_reader_unittest_OBJECTS) $(src_common_mac_macho_reader_unittest_DEPENDENCIES) $(EXTRA_src_common_mac_macho_reader_unittest_DEPENDENCIES) src/common/mac/$(am__dirstamp) @rm -f src/common/mac/macho_reader_unittest$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(src_common_mac_macho_reader_unittest_OBJECTS) $(src_common_mac_macho_reader_unittest_LDADD) $(LIBS) +src/common/safe_math_unittest-safe_math_unittest.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) + +src/common/safe_math_unittest$(EXEEXT): $(src_common_safe_math_unittest_OBJECTS) $(src_common_safe_math_unittest_DEPENDENCIES) $(EXTRA_src_common_safe_math_unittest_DEPENDENCIES) src/common/$(am__dirstamp) + @rm -f src/common/safe_math_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_common_safe_math_unittest_OBJECTS) $(src_common_safe_math_unittest_LDADD) $(LIBS) src/common/test_assembler_unittest-test_assembler.$(OBJEXT): \ src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) @@ -4812,6 +4766,13 @@ src/processor/contained_range_map_unittest.$(OBJEXT): \ src/processor/contained_range_map_unittest$(EXEEXT): $(src_processor_contained_range_map_unittest_OBJECTS) $(src_processor_contained_range_map_unittest_DEPENDENCIES) $(EXTRA_src_processor_contained_range_map_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) @rm -f src/processor/contained_range_map_unittest$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(src_processor_contained_range_map_unittest_OBJECTS) $(src_processor_contained_range_map_unittest_LDADD) $(LIBS) +src/processor/disassembler_objdump_unittest-disassembler_objdump_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/disassembler_objdump_unittest$(EXEEXT): $(src_processor_disassembler_objdump_unittest_OBJECTS) $(src_processor_disassembler_objdump_unittest_DEPENDENCIES) $(EXTRA_src_processor_disassembler_objdump_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/disassembler_objdump_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_disassembler_objdump_unittest_OBJECTS) $(src_processor_disassembler_objdump_unittest_LDADD) $(LIBS) src/processor/disassembler_x86_unittest-disassembler_x86_unittest.$(OBJEXT): \ src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) @@ -4992,6 +4953,26 @@ src/processor/stackwalker_mips_unittest-stackwalker_mips_unittest.$(OBJEXT): \ src/processor/stackwalker_mips_unittest$(EXEEXT): $(src_processor_stackwalker_mips_unittest_OBJECTS) $(src_processor_stackwalker_mips_unittest_DEPENDENCIES) $(EXTRA_src_processor_stackwalker_mips_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) @rm -f src/processor/stackwalker_mips_unittest$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(src_processor_stackwalker_mips_unittest_OBJECTS) $(src_processor_stackwalker_mips_unittest_LDADD) $(LIBS) +src/common/processor_stackwalker_riscv64_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/stackwalker_riscv64_unittest$(EXEEXT): $(src_processor_stackwalker_riscv64_unittest_OBJECTS) $(src_processor_stackwalker_riscv64_unittest_DEPENDENCIES) $(EXTRA_src_processor_stackwalker_riscv64_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/stackwalker_riscv64_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_stackwalker_riscv64_unittest_OBJECTS) $(src_processor_stackwalker_riscv64_unittest_LDADD) $(LIBS) +src/common/processor_stackwalker_riscv_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_riscv_unittest-stackwalker_riscv_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/stackwalker_riscv_unittest$(EXEEXT): $(src_processor_stackwalker_riscv_unittest_OBJECTS) $(src_processor_stackwalker_riscv_unittest_DEPENDENCIES) $(EXTRA_src_processor_stackwalker_riscv_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/stackwalker_riscv_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_stackwalker_riscv_unittest_OBJECTS) $(src_processor_stackwalker_riscv_unittest_LDADD) $(LIBS) src/processor/stackwalker_selftest.$(OBJEXT): \ src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) @@ -5345,12 +5326,14 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest_utils.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_core_dumper.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper_unittest_helper-linux_dumper_unittest_helper.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_ptrace_dumper.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/minidump_writer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/pe_file.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/convert_UTF.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/dumper_unittest-byte_cursor_unittest.Po@am__quote@ # am--include-marker @@ -5393,8 +5376,11 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/processor_stackwalker_arm_unittest-test_assembler.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/processor_stackwalker_mips64_unittest-test_assembler.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/processor_stackwalker_mips_unittest-test_assembler.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/processor_stackwalker_riscv64_unittest-test_assembler.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/processor_stackwalker_riscv_unittest-test_assembler.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/processor_stackwalker_x86_unittest-test_assembler.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/processor_synth_minidump_unittest-test_assembler.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/safe_math_unittest-safe_math_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/string_conversion.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/test_assembler_unittest-test_assembler.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/test_assembler_unittest-test_assembler_unittest.Po@am__quote@ # am--include-marker @@ -5446,6 +5432,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-elf_core_dump.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_pipe.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_tmpfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/dumper_unittest-crc32.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/dumper_unittest-dump_symbols.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/dumper_unittest-dump_symbols_unittest.Po@am__quote@ # am--include-marker @@ -5475,6 +5463,10 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/linux_libc_support.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/memory_mapped_file.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/safe_readlink.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/scoped_pipe.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/scoped_pipe_unittest-scoped_pipe_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/scoped_tmpfile.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/scoped_tmpfile_unittest-scoped_tmpfile_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/symbol_collector_client.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/symbol_upload.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/tools_linux_dump_syms_dump_syms-crc32.Po@am__quote@ # am--include-marker @@ -5521,6 +5513,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/client_linux_linux_client_unittest_shlib-proc_maps_linux.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/contained_range_map_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/convert_old_arm64_context.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/disassembler_objdump.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/disassembler_objdump_unittest-disassembler_objdump_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/disassembler_x86.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/disassembler_x86_unittest-disassembler_x86_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/dump_context.Po@am__quote@ # am--include-marker @@ -5575,6 +5569,10 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_mips_unittest-stackwalker_mips_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_ppc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_ppc64.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_riscv.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_riscv64.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_riscv_unittest-stackwalker_riscv_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_selftest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_sparc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_x86.Po@am__quote@ # am--include-marker @@ -5909,6 +5907,20 @@ src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_uni @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_unittest_utils.obj `if test -f 'src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc'; fi` +src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.o: src/client/linux/minidump_writer/pe_file.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Tpo -c -o src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.o `test -f 'src/client/linux/minidump_writer/pe_file.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/pe_file.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Tpo src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/pe_file.cc' object='src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.o `test -f 'src/client/linux/minidump_writer/pe_file.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/pe_file.cc + +src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.obj: src/client/linux/minidump_writer/pe_file.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Tpo -c -o src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.obj `if test -f 'src/client/linux/minidump_writer/pe_file.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/pe_file.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/pe_file.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Tpo src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/pe_file.cc' object='src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.obj `if test -f 'src/client/linux/minidump_writer/pe_file.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/pe_file.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/pe_file.cc'; fi` + src/client/linux/minidump_writer/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.o: src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Tpo -c -o src/client/linux/minidump_writer/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.o `test -f 'src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po @@ -5951,6 +5963,34 @@ src/common/linux/client_linux_linux_client_unittest_shlib-linux_libc_support_uni @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.obj `if test -f 'src/common/linux/linux_libc_support_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/linux_libc_support_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/linux_libc_support_unittest.cc'; fi` +src/common/linux/client_linux_linux_client_unittest_shlib-scoped_pipe.o: src/common/linux/scoped_pipe.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/client_linux_linux_client_unittest_shlib-scoped_pipe.o -MD -MP -MF src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_pipe.Tpo -c -o src/common/linux/client_linux_linux_client_unittest_shlib-scoped_pipe.o `test -f 'src/common/linux/scoped_pipe.cc' || echo '$(srcdir)/'`src/common/linux/scoped_pipe.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_pipe.Tpo src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_pipe.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/scoped_pipe.cc' object='src/common/linux/client_linux_linux_client_unittest_shlib-scoped_pipe.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/client_linux_linux_client_unittest_shlib-scoped_pipe.o `test -f 'src/common/linux/scoped_pipe.cc' || echo '$(srcdir)/'`src/common/linux/scoped_pipe.cc + +src/common/linux/client_linux_linux_client_unittest_shlib-scoped_pipe.obj: src/common/linux/scoped_pipe.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/client_linux_linux_client_unittest_shlib-scoped_pipe.obj -MD -MP -MF src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_pipe.Tpo -c -o src/common/linux/client_linux_linux_client_unittest_shlib-scoped_pipe.obj `if test -f 'src/common/linux/scoped_pipe.cc'; then $(CYGPATH_W) 'src/common/linux/scoped_pipe.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/scoped_pipe.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_pipe.Tpo src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_pipe.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/scoped_pipe.cc' object='src/common/linux/client_linux_linux_client_unittest_shlib-scoped_pipe.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/client_linux_linux_client_unittest_shlib-scoped_pipe.obj `if test -f 'src/common/linux/scoped_pipe.cc'; then $(CYGPATH_W) 'src/common/linux/scoped_pipe.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/scoped_pipe.cc'; fi` + +src/common/linux/client_linux_linux_client_unittest_shlib-scoped_tmpfile.o: src/common/linux/scoped_tmpfile.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/client_linux_linux_client_unittest_shlib-scoped_tmpfile.o -MD -MP -MF src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_tmpfile.Tpo -c -o src/common/linux/client_linux_linux_client_unittest_shlib-scoped_tmpfile.o `test -f 'src/common/linux/scoped_tmpfile.cc' || echo '$(srcdir)/'`src/common/linux/scoped_tmpfile.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_tmpfile.Tpo src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_tmpfile.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/scoped_tmpfile.cc' object='src/common/linux/client_linux_linux_client_unittest_shlib-scoped_tmpfile.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/client_linux_linux_client_unittest_shlib-scoped_tmpfile.o `test -f 'src/common/linux/scoped_tmpfile.cc' || echo '$(srcdir)/'`src/common/linux/scoped_tmpfile.cc + +src/common/linux/client_linux_linux_client_unittest_shlib-scoped_tmpfile.obj: src/common/linux/scoped_tmpfile.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/client_linux_linux_client_unittest_shlib-scoped_tmpfile.obj -MD -MP -MF src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_tmpfile.Tpo -c -o src/common/linux/client_linux_linux_client_unittest_shlib-scoped_tmpfile.obj `if test -f 'src/common/linux/scoped_tmpfile.cc'; then $(CYGPATH_W) 'src/common/linux/scoped_tmpfile.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/scoped_tmpfile.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_tmpfile.Tpo src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_tmpfile.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/scoped_tmpfile.cc' object='src/common/linux/client_linux_linux_client_unittest_shlib-scoped_tmpfile.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/client_linux_linux_client_unittest_shlib-scoped_tmpfile.obj `if test -f 'src/common/linux/scoped_tmpfile.cc'; then $(CYGPATH_W) 'src/common/linux/scoped_tmpfile.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/scoped_tmpfile.cc'; fi` + src/common/linux/tests/client_linux_linux_client_unittest_shlib-crash_generator.o: src/common/linux/tests/crash_generator.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/tests/client_linux_linux_client_unittest_shlib-crash_generator.o -MD -MP -MF src/common/linux/tests/$(DEPDIR)/client_linux_linux_client_unittest_shlib-crash_generator.Tpo -c -o src/common/linux/tests/client_linux_linux_client_unittest_shlib-crash_generator.o `test -f 'src/common/linux/tests/crash_generator.cc' || echo '$(srcdir)/'`src/common/linux/tests/crash_generator.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/tests/$(DEPDIR)/client_linux_linux_client_unittest_shlib-crash_generator.Tpo src/common/linux/tests/$(DEPDIR)/client_linux_linux_client_unittest_shlib-crash_generator.Po @@ -6889,6 +6929,34 @@ src/common/linux/google_crashdump_uploader_test-libcurl_wrapper.obj: src/common/ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_linux_google_crashdump_uploader_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/google_crashdump_uploader_test-libcurl_wrapper.obj `if test -f 'src/common/linux/libcurl_wrapper.cc'; then $(CYGPATH_W) 'src/common/linux/libcurl_wrapper.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/libcurl_wrapper.cc'; fi` +src/common/linux/scoped_pipe_unittest-scoped_pipe_unittest.o: src/common/linux/scoped_pipe_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_linux_scoped_pipe_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/scoped_pipe_unittest-scoped_pipe_unittest.o -MD -MP -MF src/common/linux/$(DEPDIR)/scoped_pipe_unittest-scoped_pipe_unittest.Tpo -c -o src/common/linux/scoped_pipe_unittest-scoped_pipe_unittest.o `test -f 'src/common/linux/scoped_pipe_unittest.cc' || echo '$(srcdir)/'`src/common/linux/scoped_pipe_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/scoped_pipe_unittest-scoped_pipe_unittest.Tpo src/common/linux/$(DEPDIR)/scoped_pipe_unittest-scoped_pipe_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/scoped_pipe_unittest.cc' object='src/common/linux/scoped_pipe_unittest-scoped_pipe_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_linux_scoped_pipe_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/scoped_pipe_unittest-scoped_pipe_unittest.o `test -f 'src/common/linux/scoped_pipe_unittest.cc' || echo '$(srcdir)/'`src/common/linux/scoped_pipe_unittest.cc + +src/common/linux/scoped_pipe_unittest-scoped_pipe_unittest.obj: src/common/linux/scoped_pipe_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_linux_scoped_pipe_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/scoped_pipe_unittest-scoped_pipe_unittest.obj -MD -MP -MF src/common/linux/$(DEPDIR)/scoped_pipe_unittest-scoped_pipe_unittest.Tpo -c -o src/common/linux/scoped_pipe_unittest-scoped_pipe_unittest.obj `if test -f 'src/common/linux/scoped_pipe_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/scoped_pipe_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/scoped_pipe_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/scoped_pipe_unittest-scoped_pipe_unittest.Tpo src/common/linux/$(DEPDIR)/scoped_pipe_unittest-scoped_pipe_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/scoped_pipe_unittest.cc' object='src/common/linux/scoped_pipe_unittest-scoped_pipe_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_linux_scoped_pipe_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/scoped_pipe_unittest-scoped_pipe_unittest.obj `if test -f 'src/common/linux/scoped_pipe_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/scoped_pipe_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/scoped_pipe_unittest.cc'; fi` + +src/common/linux/scoped_tmpfile_unittest-scoped_tmpfile_unittest.o: src/common/linux/scoped_tmpfile_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_linux_scoped_tmpfile_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/scoped_tmpfile_unittest-scoped_tmpfile_unittest.o -MD -MP -MF src/common/linux/$(DEPDIR)/scoped_tmpfile_unittest-scoped_tmpfile_unittest.Tpo -c -o src/common/linux/scoped_tmpfile_unittest-scoped_tmpfile_unittest.o `test -f 'src/common/linux/scoped_tmpfile_unittest.cc' || echo '$(srcdir)/'`src/common/linux/scoped_tmpfile_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/scoped_tmpfile_unittest-scoped_tmpfile_unittest.Tpo src/common/linux/$(DEPDIR)/scoped_tmpfile_unittest-scoped_tmpfile_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/scoped_tmpfile_unittest.cc' object='src/common/linux/scoped_tmpfile_unittest-scoped_tmpfile_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_linux_scoped_tmpfile_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/scoped_tmpfile_unittest-scoped_tmpfile_unittest.o `test -f 'src/common/linux/scoped_tmpfile_unittest.cc' || echo '$(srcdir)/'`src/common/linux/scoped_tmpfile_unittest.cc + +src/common/linux/scoped_tmpfile_unittest-scoped_tmpfile_unittest.obj: src/common/linux/scoped_tmpfile_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_linux_scoped_tmpfile_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/scoped_tmpfile_unittest-scoped_tmpfile_unittest.obj -MD -MP -MF src/common/linux/$(DEPDIR)/scoped_tmpfile_unittest-scoped_tmpfile_unittest.Tpo -c -o src/common/linux/scoped_tmpfile_unittest-scoped_tmpfile_unittest.obj `if test -f 'src/common/linux/scoped_tmpfile_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/scoped_tmpfile_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/scoped_tmpfile_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/scoped_tmpfile_unittest-scoped_tmpfile_unittest.Tpo src/common/linux/$(DEPDIR)/scoped_tmpfile_unittest-scoped_tmpfile_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/scoped_tmpfile_unittest.cc' object='src/common/linux/scoped_tmpfile_unittest-scoped_tmpfile_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_linux_scoped_tmpfile_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/scoped_tmpfile_unittest-scoped_tmpfile_unittest.obj `if test -f 'src/common/linux/scoped_tmpfile_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/scoped_tmpfile_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/scoped_tmpfile_unittest.cc'; fi` + src/common/mac_macho_reader_unittest-dwarf_cfi_to_module.o: src/common/dwarf_cfi_to_module.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac_macho_reader_unittest-dwarf_cfi_to_module.o -MD -MP -MF src/common/$(DEPDIR)/mac_macho_reader_unittest-dwarf_cfi_to_module.Tpo -c -o src/common/mac_macho_reader_unittest-dwarf_cfi_to_module.o `test -f 'src/common/dwarf_cfi_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cfi_to_module.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/mac_macho_reader_unittest-dwarf_cfi_to_module.Tpo src/common/$(DEPDIR)/mac_macho_reader_unittest-dwarf_cfi_to_module.Po @@ -7211,6 +7279,20 @@ src/common/tests/mac_macho_reader_unittest-file_utils.obj: src/common/tests/file @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/tests/mac_macho_reader_unittest-file_utils.obj `if test -f 'src/common/tests/file_utils.cc'; then $(CYGPATH_W) 'src/common/tests/file_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/tests/file_utils.cc'; fi` +src/common/safe_math_unittest-safe_math_unittest.o: src/common/safe_math_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_safe_math_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/safe_math_unittest-safe_math_unittest.o -MD -MP -MF src/common/$(DEPDIR)/safe_math_unittest-safe_math_unittest.Tpo -c -o src/common/safe_math_unittest-safe_math_unittest.o `test -f 'src/common/safe_math_unittest.cc' || echo '$(srcdir)/'`src/common/safe_math_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/safe_math_unittest-safe_math_unittest.Tpo src/common/$(DEPDIR)/safe_math_unittest-safe_math_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/safe_math_unittest.cc' object='src/common/safe_math_unittest-safe_math_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_safe_math_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/safe_math_unittest-safe_math_unittest.o `test -f 'src/common/safe_math_unittest.cc' || echo '$(srcdir)/'`src/common/safe_math_unittest.cc + +src/common/safe_math_unittest-safe_math_unittest.obj: src/common/safe_math_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_safe_math_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/safe_math_unittest-safe_math_unittest.obj -MD -MP -MF src/common/$(DEPDIR)/safe_math_unittest-safe_math_unittest.Tpo -c -o src/common/safe_math_unittest-safe_math_unittest.obj `if test -f 'src/common/safe_math_unittest.cc'; then $(CYGPATH_W) 'src/common/safe_math_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/safe_math_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/safe_math_unittest-safe_math_unittest.Tpo src/common/$(DEPDIR)/safe_math_unittest-safe_math_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/safe_math_unittest.cc' object='src/common/safe_math_unittest-safe_math_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_safe_math_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/safe_math_unittest-safe_math_unittest.obj `if test -f 'src/common/safe_math_unittest.cc'; then $(CYGPATH_W) 'src/common/safe_math_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/safe_math_unittest.cc'; fi` + src/common/test_assembler_unittest-test_assembler.o: src/common/test_assembler.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_test_assembler_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/test_assembler_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/test_assembler_unittest-test_assembler.Tpo -c -o src/common/test_assembler_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/test_assembler_unittest-test_assembler.Tpo src/common/$(DEPDIR)/test_assembler_unittest-test_assembler.Po @@ -7267,6 +7349,20 @@ src/processor/cfi_frame_info_unittest-cfi_frame_info_unittest.obj: src/processor @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_cfi_frame_info_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/cfi_frame_info_unittest-cfi_frame_info_unittest.obj `if test -f 'src/processor/cfi_frame_info_unittest.cc'; then $(CYGPATH_W) 'src/processor/cfi_frame_info_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/cfi_frame_info_unittest.cc'; fi` +src/processor/disassembler_objdump_unittest-disassembler_objdump_unittest.o: src/processor/disassembler_objdump_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_disassembler_objdump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/disassembler_objdump_unittest-disassembler_objdump_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/disassembler_objdump_unittest-disassembler_objdump_unittest.Tpo -c -o src/processor/disassembler_objdump_unittest-disassembler_objdump_unittest.o `test -f 'src/processor/disassembler_objdump_unittest.cc' || echo '$(srcdir)/'`src/processor/disassembler_objdump_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/disassembler_objdump_unittest-disassembler_objdump_unittest.Tpo src/processor/$(DEPDIR)/disassembler_objdump_unittest-disassembler_objdump_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/disassembler_objdump_unittest.cc' object='src/processor/disassembler_objdump_unittest-disassembler_objdump_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_disassembler_objdump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/disassembler_objdump_unittest-disassembler_objdump_unittest.o `test -f 'src/processor/disassembler_objdump_unittest.cc' || echo '$(srcdir)/'`src/processor/disassembler_objdump_unittest.cc + +src/processor/disassembler_objdump_unittest-disassembler_objdump_unittest.obj: src/processor/disassembler_objdump_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_disassembler_objdump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/disassembler_objdump_unittest-disassembler_objdump_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/disassembler_objdump_unittest-disassembler_objdump_unittest.Tpo -c -o src/processor/disassembler_objdump_unittest-disassembler_objdump_unittest.obj `if test -f 'src/processor/disassembler_objdump_unittest.cc'; then $(CYGPATH_W) 'src/processor/disassembler_objdump_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/disassembler_objdump_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/disassembler_objdump_unittest-disassembler_objdump_unittest.Tpo src/processor/$(DEPDIR)/disassembler_objdump_unittest-disassembler_objdump_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/disassembler_objdump_unittest.cc' object='src/processor/disassembler_objdump_unittest-disassembler_objdump_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_disassembler_objdump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/disassembler_objdump_unittest-disassembler_objdump_unittest.obj `if test -f 'src/processor/disassembler_objdump_unittest.cc'; then $(CYGPATH_W) 'src/processor/disassembler_objdump_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/disassembler_objdump_unittest.cc'; fi` + src/processor/disassembler_x86_unittest-disassembler_x86_unittest.o: src/processor/disassembler_x86_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_disassembler_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/disassembler_x86_unittest-disassembler_x86_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/disassembler_x86_unittest-disassembler_x86_unittest.Tpo -c -o src/processor/disassembler_x86_unittest-disassembler_x86_unittest.o `test -f 'src/processor/disassembler_x86_unittest.cc' || echo '$(srcdir)/'`src/processor/disassembler_x86_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/disassembler_x86_unittest-disassembler_x86_unittest.Tpo src/processor/$(DEPDIR)/disassembler_x86_unittest-disassembler_x86_unittest.Po @@ -7617,6 +7713,62 @@ src/processor/stackwalker_mips_unittest-stackwalker_mips_unittest.obj: src/proce @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/stackwalker_mips_unittest-stackwalker_mips_unittest.obj `if test -f 'src/processor/stackwalker_mips_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_mips_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_mips_unittest.cc'; fi` +src/common/processor_stackwalker_riscv64_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/processor_stackwalker_riscv64_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/processor_stackwalker_riscv64_unittest-test_assembler.Tpo -c -o src/common/processor_stackwalker_riscv64_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/processor_stackwalker_riscv64_unittest-test_assembler.Tpo src/common/$(DEPDIR)/processor_stackwalker_riscv64_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/processor_stackwalker_riscv64_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/processor_stackwalker_riscv64_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/processor_stackwalker_riscv64_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/processor_stackwalker_riscv64_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/processor_stackwalker_riscv64_unittest-test_assembler.Tpo -c -o src/common/processor_stackwalker_riscv64_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/processor_stackwalker_riscv64_unittest-test_assembler.Tpo src/common/$(DEPDIR)/processor_stackwalker_riscv64_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/processor_stackwalker_riscv64_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/processor_stackwalker_riscv64_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/processor/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.o: src/processor/stackwalker_riscv64_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.Tpo -c -o src/processor/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.o `test -f 'src/processor/stackwalker_riscv64_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_riscv64_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.Tpo src/processor/$(DEPDIR)/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_riscv64_unittest.cc' object='src/processor/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.o `test -f 'src/processor/stackwalker_riscv64_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_riscv64_unittest.cc + +src/processor/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.obj: src/processor/stackwalker_riscv64_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.Tpo -c -o src/processor/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.obj `if test -f 'src/processor/stackwalker_riscv64_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_riscv64_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_riscv64_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.Tpo src/processor/$(DEPDIR)/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_riscv64_unittest.cc' object='src/processor/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.obj `if test -f 'src/processor/stackwalker_riscv64_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_riscv64_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_riscv64_unittest.cc'; fi` + +src/common/processor_stackwalker_riscv_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/processor_stackwalker_riscv_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/processor_stackwalker_riscv_unittest-test_assembler.Tpo -c -o src/common/processor_stackwalker_riscv_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/processor_stackwalker_riscv_unittest-test_assembler.Tpo src/common/$(DEPDIR)/processor_stackwalker_riscv_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/processor_stackwalker_riscv_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/processor_stackwalker_riscv_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/processor_stackwalker_riscv_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/processor_stackwalker_riscv_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/processor_stackwalker_riscv_unittest-test_assembler.Tpo -c -o src/common/processor_stackwalker_riscv_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/processor_stackwalker_riscv_unittest-test_assembler.Tpo src/common/$(DEPDIR)/processor_stackwalker_riscv_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/processor_stackwalker_riscv_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/processor_stackwalker_riscv_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/processor/stackwalker_riscv_unittest-stackwalker_riscv_unittest.o: src/processor/stackwalker_riscv_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/stackwalker_riscv_unittest-stackwalker_riscv_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/stackwalker_riscv_unittest-stackwalker_riscv_unittest.Tpo -c -o src/processor/stackwalker_riscv_unittest-stackwalker_riscv_unittest.o `test -f 'src/processor/stackwalker_riscv_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_riscv_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/stackwalker_riscv_unittest-stackwalker_riscv_unittest.Tpo src/processor/$(DEPDIR)/stackwalker_riscv_unittest-stackwalker_riscv_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_riscv_unittest.cc' object='src/processor/stackwalker_riscv_unittest-stackwalker_riscv_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/stackwalker_riscv_unittest-stackwalker_riscv_unittest.o `test -f 'src/processor/stackwalker_riscv_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_riscv_unittest.cc + +src/processor/stackwalker_riscv_unittest-stackwalker_riscv_unittest.obj: src/processor/stackwalker_riscv_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/stackwalker_riscv_unittest-stackwalker_riscv_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/stackwalker_riscv_unittest-stackwalker_riscv_unittest.Tpo -c -o src/processor/stackwalker_riscv_unittest-stackwalker_riscv_unittest.obj `if test -f 'src/processor/stackwalker_riscv_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_riscv_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_riscv_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/stackwalker_riscv_unittest-stackwalker_riscv_unittest.Tpo src/processor/$(DEPDIR)/stackwalker_riscv_unittest-stackwalker_riscv_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_riscv_unittest.cc' object='src/processor/stackwalker_riscv_unittest-stackwalker_riscv_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_riscv_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/stackwalker_riscv_unittest-stackwalker_riscv_unittest.obj `if test -f 'src/processor/stackwalker_riscv_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_riscv_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_riscv_unittest.cc'; fi` + src/common/processor_stackwalker_x86_unittest-test_assembler.o: src/common/test_assembler.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/processor_stackwalker_x86_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/processor_stackwalker_x86_unittest-test_assembler.Tpo -c -o src/common/processor_stackwalker_x86_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/processor_stackwalker_x86_unittest-test_assembler.Tpo src/common/$(DEPDIR)/processor_stackwalker_x86_unittest-test_assembler.Po @@ -8804,6 +8956,13 @@ recheck: all $(check_PROGRAMS) $(check_LIBRARIES) $(check_SCRIPTS) am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? +src/common/safe_math_unittest.log: src/common/safe_math_unittest$(EXEEXT) + @p='src/common/safe_math_unittest$(EXEEXT)'; \ + b='src/common/safe_math_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) src/common/test_assembler_unittest.log: src/common/test_assembler_unittest$(EXEEXT) @p='src/common/test_assembler_unittest$(EXEEXT)'; \ b='src/common/test_assembler_unittest'; \ @@ -9014,6 +9173,20 @@ src/processor/stackwalker_mips64_unittest.log: src/processor/stackwalker_mips64_ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/stackwalker_riscv_unittest.log: src/processor/stackwalker_riscv_unittest$(EXEEXT) + @p='src/processor/stackwalker_riscv_unittest$(EXEEXT)'; \ + b='src/processor/stackwalker_riscv_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/stackwalker_riscv64_unittest.log: src/processor/stackwalker_riscv64_unittest$(EXEEXT) + @p='src/processor/stackwalker_riscv64_unittest$(EXEEXT)'; \ + b='src/processor/stackwalker_riscv64_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) src/processor/stackwalker_x86_unittest.log: src/processor/stackwalker_x86_unittest$(EXEEXT) @p='src/processor/stackwalker_x86_unittest$(EXEEXT)'; \ b='src/processor/stackwalker_x86_unittest'; \ @@ -9028,6 +9201,34 @@ src/processor/synth_minidump_unittest.log: src/processor/synth_minidump_unittest --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/disassembler_objdump_unittest.log: src/processor/disassembler_objdump_unittest$(EXEEXT) + @p='src/processor/disassembler_objdump_unittest$(EXEEXT)'; \ + b='src/processor/disassembler_objdump_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/common/linux/scoped_pipe_unittest.log: src/common/linux/scoped_pipe_unittest$(EXEEXT) + @p='src/common/linux/scoped_pipe_unittest$(EXEEXT)'; \ + b='src/common/linux/scoped_pipe_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/common/linux/scoped_tmpfile_unittest.log: src/common/linux/scoped_tmpfile_unittest$(EXEEXT) + @p='src/common/linux/scoped_tmpfile_unittest$(EXEEXT)'; \ + b='src/common/linux/scoped_tmpfile_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/stackwalker_selftest.log: src/processor/stackwalker_selftest$(EXEEXT) + @p='src/processor/stackwalker_selftest$(EXEEXT)'; \ + b='src/processor/stackwalker_selftest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) src/client/linux/linux_client_unittest.log: src/client/linux/linux_client_unittest$(EXEEXT) @p='src/client/linux/linux_client_unittest$(EXEEXT)'; \ b='src/client/linux/linux_client_unittest'; \ @@ -9063,13 +9264,6 @@ src/common/mac/macho_reader_unittest.log: src/common/mac/macho_reader_unittest$( --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) -src/processor/stackwalker_selftest.log: src/processor/stackwalker_selftest$(EXEEXT) - @p='src/processor/stackwalker_selftest$(EXEEXT)'; \ - b='src/processor/stackwalker_selftest'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) src/processor/microdump_stackwalk_test.log: src/processor/microdump_stackwalk_test @p='src/processor/microdump_stackwalk_test'; \ b='src/processor/microdump_stackwalk_test'; \ @@ -9119,7 +9313,6 @@ src/processor/minidump_stackwalk_machine_readable_test.log: src/processor/minidu @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) - distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am @@ -9415,12 +9608,14 @@ distclean: distclean-am -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest_utils.Po + -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_core_dumper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper_unittest_helper-linux_dumper_unittest_helper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_ptrace_dumper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/minidump_writer.Po + -rm -f src/client/linux/minidump_writer/$(DEPDIR)/pe_file.Po -rm -f src/common/$(DEPDIR)/client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Po -rm -f src/common/$(DEPDIR)/convert_UTF.Po -rm -f src/common/$(DEPDIR)/dumper_unittest-byte_cursor_unittest.Po @@ -9463,8 +9658,11 @@ distclean: distclean-am -rm -f src/common/$(DEPDIR)/processor_stackwalker_arm_unittest-test_assembler.Po -rm -f src/common/$(DEPDIR)/processor_stackwalker_mips64_unittest-test_assembler.Po -rm -f src/common/$(DEPDIR)/processor_stackwalker_mips_unittest-test_assembler.Po + -rm -f src/common/$(DEPDIR)/processor_stackwalker_riscv64_unittest-test_assembler.Po + -rm -f src/common/$(DEPDIR)/processor_stackwalker_riscv_unittest-test_assembler.Po -rm -f src/common/$(DEPDIR)/processor_stackwalker_x86_unittest-test_assembler.Po -rm -f src/common/$(DEPDIR)/processor_synth_minidump_unittest-test_assembler.Po + -rm -f src/common/$(DEPDIR)/safe_math_unittest-safe_math_unittest.Po -rm -f src/common/$(DEPDIR)/string_conversion.Po -rm -f src/common/$(DEPDIR)/test_assembler_unittest-test_assembler.Po -rm -f src/common/$(DEPDIR)/test_assembler_unittest-test_assembler_unittest.Po @@ -9516,6 +9714,8 @@ distclean: distclean-am -rm -f src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Po -rm -f src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-elf_core_dump.Po -rm -f src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.Po + -rm -f src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_pipe.Po + -rm -f src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_tmpfile.Po -rm -f src/common/linux/$(DEPDIR)/dumper_unittest-crc32.Po -rm -f src/common/linux/$(DEPDIR)/dumper_unittest-dump_symbols.Po -rm -f src/common/linux/$(DEPDIR)/dumper_unittest-dump_symbols_unittest.Po @@ -9545,6 +9745,10 @@ distclean: distclean-am -rm -f src/common/linux/$(DEPDIR)/linux_libc_support.Po -rm -f src/common/linux/$(DEPDIR)/memory_mapped_file.Po -rm -f src/common/linux/$(DEPDIR)/safe_readlink.Po + -rm -f src/common/linux/$(DEPDIR)/scoped_pipe.Po + -rm -f src/common/linux/$(DEPDIR)/scoped_pipe_unittest-scoped_pipe_unittest.Po + -rm -f src/common/linux/$(DEPDIR)/scoped_tmpfile.Po + -rm -f src/common/linux/$(DEPDIR)/scoped_tmpfile_unittest-scoped_tmpfile_unittest.Po -rm -f src/common/linux/$(DEPDIR)/symbol_collector_client.Po -rm -f src/common/linux/$(DEPDIR)/symbol_upload.Po -rm -f src/common/linux/$(DEPDIR)/tools_linux_dump_syms_dump_syms-crc32.Po @@ -9591,6 +9795,8 @@ distclean: distclean-am -rm -f src/processor/$(DEPDIR)/client_linux_linux_client_unittest_shlib-proc_maps_linux.Po -rm -f src/processor/$(DEPDIR)/contained_range_map_unittest.Po -rm -f src/processor/$(DEPDIR)/convert_old_arm64_context.Po + -rm -f src/processor/$(DEPDIR)/disassembler_objdump.Po + -rm -f src/processor/$(DEPDIR)/disassembler_objdump_unittest-disassembler_objdump_unittest.Po -rm -f src/processor/$(DEPDIR)/disassembler_x86.Po -rm -f src/processor/$(DEPDIR)/disassembler_x86_unittest-disassembler_x86_unittest.Po -rm -f src/processor/$(DEPDIR)/dump_context.Po @@ -9645,6 +9851,10 @@ distclean: distclean-am -rm -f src/processor/$(DEPDIR)/stackwalker_mips_unittest-stackwalker_mips_unittest.Po -rm -f src/processor/$(DEPDIR)/stackwalker_ppc.Po -rm -f src/processor/$(DEPDIR)/stackwalker_ppc64.Po + -rm -f src/processor/$(DEPDIR)/stackwalker_riscv.Po + -rm -f src/processor/$(DEPDIR)/stackwalker_riscv64.Po + -rm -f src/processor/$(DEPDIR)/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.Po + -rm -f src/processor/$(DEPDIR)/stackwalker_riscv_unittest-stackwalker_riscv_unittest.Po -rm -f src/processor/$(DEPDIR)/stackwalker_selftest.Po -rm -f src/processor/$(DEPDIR)/stackwalker_sparc.Po -rm -f src/processor/$(DEPDIR)/stackwalker_x86.Po @@ -9758,12 +9968,14 @@ maintainer-clean: maintainer-clean-am -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest_utils.Po + -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_core_dumper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper_unittest_helper-linux_dumper_unittest_helper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_ptrace_dumper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/minidump_writer.Po + -rm -f src/client/linux/minidump_writer/$(DEPDIR)/pe_file.Po -rm -f src/common/$(DEPDIR)/client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Po -rm -f src/common/$(DEPDIR)/convert_UTF.Po -rm -f src/common/$(DEPDIR)/dumper_unittest-byte_cursor_unittest.Po @@ -9806,8 +10018,11 @@ maintainer-clean: maintainer-clean-am -rm -f src/common/$(DEPDIR)/processor_stackwalker_arm_unittest-test_assembler.Po -rm -f src/common/$(DEPDIR)/processor_stackwalker_mips64_unittest-test_assembler.Po -rm -f src/common/$(DEPDIR)/processor_stackwalker_mips_unittest-test_assembler.Po + -rm -f src/common/$(DEPDIR)/processor_stackwalker_riscv64_unittest-test_assembler.Po + -rm -f src/common/$(DEPDIR)/processor_stackwalker_riscv_unittest-test_assembler.Po -rm -f src/common/$(DEPDIR)/processor_stackwalker_x86_unittest-test_assembler.Po -rm -f src/common/$(DEPDIR)/processor_synth_minidump_unittest-test_assembler.Po + -rm -f src/common/$(DEPDIR)/safe_math_unittest-safe_math_unittest.Po -rm -f src/common/$(DEPDIR)/string_conversion.Po -rm -f src/common/$(DEPDIR)/test_assembler_unittest-test_assembler.Po -rm -f src/common/$(DEPDIR)/test_assembler_unittest-test_assembler_unittest.Po @@ -9859,6 +10074,8 @@ maintainer-clean: maintainer-clean-am -rm -f src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Po -rm -f src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-elf_core_dump.Po -rm -f src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.Po + -rm -f src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_pipe.Po + -rm -f src/common/linux/$(DEPDIR)/client_linux_linux_client_unittest_shlib-scoped_tmpfile.Po -rm -f src/common/linux/$(DEPDIR)/dumper_unittest-crc32.Po -rm -f src/common/linux/$(DEPDIR)/dumper_unittest-dump_symbols.Po -rm -f src/common/linux/$(DEPDIR)/dumper_unittest-dump_symbols_unittest.Po @@ -9888,6 +10105,10 @@ maintainer-clean: maintainer-clean-am -rm -f src/common/linux/$(DEPDIR)/linux_libc_support.Po -rm -f src/common/linux/$(DEPDIR)/memory_mapped_file.Po -rm -f src/common/linux/$(DEPDIR)/safe_readlink.Po + -rm -f src/common/linux/$(DEPDIR)/scoped_pipe.Po + -rm -f src/common/linux/$(DEPDIR)/scoped_pipe_unittest-scoped_pipe_unittest.Po + -rm -f src/common/linux/$(DEPDIR)/scoped_tmpfile.Po + -rm -f src/common/linux/$(DEPDIR)/scoped_tmpfile_unittest-scoped_tmpfile_unittest.Po -rm -f src/common/linux/$(DEPDIR)/symbol_collector_client.Po -rm -f src/common/linux/$(DEPDIR)/symbol_upload.Po -rm -f src/common/linux/$(DEPDIR)/tools_linux_dump_syms_dump_syms-crc32.Po @@ -9934,6 +10155,8 @@ maintainer-clean: maintainer-clean-am -rm -f src/processor/$(DEPDIR)/client_linux_linux_client_unittest_shlib-proc_maps_linux.Po -rm -f src/processor/$(DEPDIR)/contained_range_map_unittest.Po -rm -f src/processor/$(DEPDIR)/convert_old_arm64_context.Po + -rm -f src/processor/$(DEPDIR)/disassembler_objdump.Po + -rm -f src/processor/$(DEPDIR)/disassembler_objdump_unittest-disassembler_objdump_unittest.Po -rm -f src/processor/$(DEPDIR)/disassembler_x86.Po -rm -f src/processor/$(DEPDIR)/disassembler_x86_unittest-disassembler_x86_unittest.Po -rm -f src/processor/$(DEPDIR)/dump_context.Po @@ -9988,6 +10211,10 @@ maintainer-clean: maintainer-clean-am -rm -f src/processor/$(DEPDIR)/stackwalker_mips_unittest-stackwalker_mips_unittest.Po -rm -f src/processor/$(DEPDIR)/stackwalker_ppc.Po -rm -f src/processor/$(DEPDIR)/stackwalker_ppc64.Po + -rm -f src/processor/$(DEPDIR)/stackwalker_riscv.Po + -rm -f src/processor/$(DEPDIR)/stackwalker_riscv64.Po + -rm -f src/processor/$(DEPDIR)/stackwalker_riscv64_unittest-stackwalker_riscv64_unittest.Po + -rm -f src/processor/$(DEPDIR)/stackwalker_riscv_unittest-stackwalker_riscv_unittest.Po -rm -f src/processor/$(DEPDIR)/stackwalker_selftest.Po -rm -f src/processor/$(DEPDIR)/stackwalker_sparc.Po -rm -f src/processor/$(DEPDIR)/stackwalker_x86.Po diff --git a/OWNERS b/OWNERS new file mode 100644 index 000000000..ca36bef10 --- /dev/null +++ b/OWNERS @@ -0,0 +1,16 @@ +# Sorted alphabetically. +# Please see README.md for contact info. + +ivanpe@chromium.org +jperaza@chromium.org +mark@chromium.org +nbilling@google.com +primiano@chromium.org +saugustine@google.com +rsesek@chromium.org +ted@mielczarek.org +thestig@chromium.org +vapier@chromium.org + +# Allow autoroller to update our DEPS file automatically. +per-file DEPS=* diff --git a/README.getsentry.md b/README.getsentry.md new file mode 100644 index 000000000..cb499b1ae --- /dev/null +++ b/README.getsentry.md @@ -0,0 +1,20 @@ +# Sentry Modifications + +This is a fork of [Google Breakpad](https://chromium.googlesource.com/breakpad/breakpad/) maintained by Sentry for use in `sentry-native`. + +## Modifications + +- **Windows**: Dynamically size minidump paths instead of using `MAX_PATH` constant. +- **Windows**: Xbox One build support. +- **Linux**: Cast `SIGSTKSZ` to int for compatibility with glibc 2.34+ (where it's no longer a compile-time constant). +- **Build System**: CMake integration (see below). +- **macOS**: Extend the handler callback with a user-context (containing register state of the crash site) for x86_64 and arm64. +- **C++17 standard requirement**: upstream uses C++20 (or newer). + +## Build System Changes + +To minimize external dependencies and better integrate with `sentry-native`, this fork uses CMake instead of Breakpad's native Autotools/`configure` build system. + +The CMake build files are maintained in the parent [`sentry-native` repository](https://github.com/getsentry/sentry-native): + +- [`../../CMakeLists.txt`](https://github.com/getsentry/sentry-native/blob/master/CMakeLists.txt) - Defines the `breakpad_client` target and lists all source files diff --git a/README.md b/README.md index edc285733..d8ee553ef 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ crash-reporting system. * [Bugs](https://bugs.chromium.org/p/google-breakpad/) * Discussion/Questions: [google-breakpad-discuss@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-discuss) * Developer/Reviews: [google-breakpad-dev@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-dev) -* Tests: [![Build Status](https://travis-ci.org/google/breakpad.svg?branch=main)](https://travis-ci.org/google/breakpad) [![Build status](https://ci.appveyor.com/api/projects/status/eguv4emv2rhq68u2?svg=true)](https://ci.appveyor.com/project/vapier/breakpad) +* Tests: [![Build+Test CI](https://github.com/google/breakpad/actions/workflows/build-test-ci.yml/badge.svg)](https://github.com/google/breakpad/actions/workflows/build-test-ci.yml) [![Build status](https://ci.appveyor.com/api/projects/status/eguv4emv2rhq68u2?svg=true)](https://ci.appveyor.com/project/vapier/breakpad) * Coverage [![Coverity Status](https://scan.coverity.com/projects/9215/badge.svg)](https://scan.coverity.com/projects/google-breakpad) ## Getting started (from main) @@ -80,3 +80,8 @@ dependent repos are up-to-date. click on it, then “Add reviewer”, and enter in the code reviewer. Depending on your settings, you may not see an email, but the reviewer has been notified with google-breakpad-dev@googlegroups.com always CC’d. + +## Sentry modifications + +See [README.getsentry.md](README.getsentry.md) for more information on the +changes, and on maintaining the fork. diff --git a/aclocal.m4 b/aclocal.m4 index be219b421..31be0bad8 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.16.3 -*- Autoconf -*- +# generated automatically by aclocal 1.16.5 -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -14,13 +14,13 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, -[m4_warning([this file was generated for autoconf 2.69. +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],, +[m4_warning([this file was generated for autoconf 2.71. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -# Copyright (C) 2002-2020 Free Software Foundation, Inc. +# Copyright (C) 2002-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -35,7 +35,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.16.3], [], +m4_if([$1], [1.16.5], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -51,12 +51,12 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.16.3])dnl +[AM_AUTOMAKE_VERSION([1.16.5])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) -# Copyright (C) 2011-2020 Free Software Foundation, Inc. +# Copyright (C) 2011-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -118,7 +118,7 @@ AC_SUBST([AR])dnl # Figure out how to run the assembler. -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -138,7 +138,7 @@ _AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -190,7 +190,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd` # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2020 Free Software Foundation, Inc. +# Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -221,7 +221,7 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2020 Free Software Foundation, Inc. +# Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -412,7 +412,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2020 Free Software Foundation, Inc. +# Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -480,7 +480,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -508,6 +508,10 @@ m4_defn([AC_PROG_CC]) # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl +m4_ifdef([_$0_ALREADY_INIT], + [m4_fatal([$0 expanded multiple times +]m4_defn([_$0_ALREADY_INIT]))], + [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl @@ -544,7 +548,7 @@ m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( - m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl @@ -596,6 +600,20 @@ AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) +# Variables for tags utilities; see am/tags.am +if test -z "$CTAGS"; then + CTAGS=ctags +fi +AC_SUBST([CTAGS]) +if test -z "$ETAGS"; then + ETAGS=etags +fi +AC_SUBST([ETAGS]) +if test -z "$CSCOPE"; then + CSCOPE=cscope +fi +AC_SUBST([CSCOPE]) + AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This @@ -677,7 +695,7 @@ for _am_header in $config_headers :; do done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -698,7 +716,7 @@ if test x"${install_sh+set}" != xset; then fi AC_SUBST([install_sh])]) -# Copyright (C) 2003-2020 Free Software Foundation, Inc. +# Copyright (C) 2003-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -720,7 +738,7 @@ AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -755,7 +773,7 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -798,7 +816,7 @@ AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2020 Free Software Foundation, Inc. +# Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -830,38 +848,9 @@ else fi ]) -# -*- Autoconf -*- -# Obsolete and "removed" macros, that must however still report explicit -# error messages when used, to smooth transition. -# -# Copyright (C) 1996-2020 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -AC_DEFUN([AM_CONFIG_HEADER], -[AC_DIAGNOSE([obsolete], -['$0': this macro is obsolete. -You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl -AC_CONFIG_HEADERS($@)]) - -AC_DEFUN([AM_PROG_CC_STDC], -[AC_PROG_CC -am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc -AC_DIAGNOSE([obsolete], -['$0': this macro is obsolete. -You should simply use the 'AC][_PROG_CC' macro instead. -Also, your code should no longer depend upon 'am_cv_prog_cc_stdc', -but upon 'ac_cv_prog_cc_stdc'.])]) - -AC_DEFUN([AM_C_PROTOTYPES], - [AC_FATAL([automatic de-ANSI-fication support has been removed])]) -AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES]) - # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -890,7 +879,7 @@ AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2020 Free Software Foundation, Inc. +# Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -937,7 +926,7 @@ AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -956,7 +945,7 @@ AC_DEFUN([AM_RUN_LOG], # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1037,7 +1026,7 @@ AC_CONFIG_COMMANDS_PRE( rm -f conftest.file ]) -# Copyright (C) 2009-2020 Free Software Foundation, Inc. +# Copyright (C) 2009-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1097,7 +1086,7 @@ AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1125,7 +1114,7 @@ fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2020 Free Software Foundation, Inc. +# Copyright (C) 2006-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1144,7 +1133,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2020 Free Software Foundation, Inc. +# Copyright (C) 2004-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/android/common-functions.sh b/android/common-functions.sh index c00e34f99..8a017178f 100755 --- a/android/common-functions.sh +++ b/android/common-functions.sh @@ -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/android/google_breakpad/Android.mk b/android/google_breakpad/Android.mk index 861849277..63243655f 100644 --- a/android/google_breakpad/Android.mk +++ b/android/google_breakpad/Android.mk @@ -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,6 +79,7 @@ LOCAL_SRC_FILES := \ src/client/linux/minidump_writer/linux_dumper.cc \ src/client/linux/minidump_writer/linux_ptrace_dumper.cc \ src/client/linux/minidump_writer/minidump_writer.cc \ + src/client/linux/minidump_writer/pe_file.cc \ src/client/minidump_file_writer.cc \ src/common/convert_UTF.cc \ src/common/md5.cc \ diff --git a/android/run-checks.sh b/android/run-checks.sh index 51d2d5023..0a41a655c 100755 --- a/android/run-checks.sh +++ b/android/run-checks.sh @@ -1,6 +1,5 @@ #!/bin/sh -# 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/android/sample_app/jni/Android.mk b/android/sample_app/jni/Android.mk index 61487b52c..419352751 100644 --- a/android/sample_app/jni/Android.mk +++ b/android/sample_app/jni/Android.mk @@ -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/android/sample_app/jni/Application.mk b/android/sample_app/jni/Application.mk index 9728017d3..29e4a4aad 100644 --- a/android/sample_app/jni/Application.mk +++ b/android/sample_app/jni/Application.mk @@ -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/android/sample_app/jni/test_breakpad.cpp b/android/sample_app/jni/test_breakpad.cpp index 9c4ebbb14..64ed4a2c8 100644 --- a/android/sample_app/jni/test_breakpad.cpp +++ b/android/sample_app/jni/test_breakpad.cpp @@ -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. // @@ -42,7 +41,7 @@ bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, } void Crash() { - volatile int* a = reinterpret_cast(NULL); + volatile int* a = static_cast(nullptr); *a = 1; } @@ -50,8 +49,8 @@ void Crash() { int main(int argc, char* argv[]) { google_breakpad::MinidumpDescriptor descriptor("."); - google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback, - NULL, true, -1); + google_breakpad::ExceptionHandler eh(descriptor, nullptr, DumpCallback, + nullptr, true, -1); Crash(); return 0; } diff --git a/android/test-shell.sh b/android/test-shell.sh index 3677d8755..abdf36ab7 100755 --- a/android/test-shell.sh +++ b/android/test-shell.sh @@ -1,7 +1,6 @@ #!/bin/sh # -# 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. # diff --git a/autotools/ar-lib b/autotools/ar-lib index 463b9ec02..c349042c3 100755 --- a/autotools/ar-lib +++ b/autotools/ar-lib @@ -2,9 +2,9 @@ # Wrapper for Microsoft lib.exe me=ar-lib -scriptversion=2012-03-01.08; # UTC +scriptversion=2019-07-04.01; # UTC -# Copyright (C) 2010-2014 Free Software Foundation, Inc. +# Copyright (C) 2010-2021 Free Software Foundation, Inc. # Written by Peter Rosin . # # This program is free software; you can redistribute it and/or modify @@ -18,7 +18,7 @@ scriptversion=2012-03-01.08; # UTC # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -53,7 +53,7 @@ func_file_conv () MINGW*) file_conv=mingw ;; - CYGWIN*) + CYGWIN* | MSYS*) file_conv=cygwin ;; *) @@ -65,7 +65,7 @@ func_file_conv () mingw) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; - cygwin) + cygwin | msys) file=`cygpath -m "$file" || echo "$file"` ;; wine) @@ -224,10 +224,11 @@ elif test -n "$extract"; then esac done else - $AR -NOLOGO -LIST "$archive" | sed -e 's/\\/\\\\/g' | while read member - do - $AR -NOLOGO -EXTRACT:"$member" "$archive" || exit $? - done + $AR -NOLOGO -LIST "$archive" | tr -d '\r' | sed -e 's/\\/\\\\/g' \ + | while read member + do + $AR -NOLOGO -EXTRACT:"$member" "$archive" || exit $? + done fi elif test -n "$quick$replace"; then diff --git a/autotools/compile b/autotools/compile index a85b723c7..df363c8fb 100755 --- a/autotools/compile +++ b/autotools/compile @@ -1,9 +1,9 @@ #! /bin/sh # Wrapper for compilers which do not understand '-c -o'. -scriptversion=2012-10-14.11; # UTC +scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# Copyright (C) 1999-2021 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify @@ -17,7 +17,7 @@ scriptversion=2012-10-14.11; # UTC # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -53,7 +53,7 @@ func_file_conv () MINGW*) file_conv=mingw ;; - CYGWIN*) + CYGWIN* | MSYS*) file_conv=cygwin ;; *) @@ -67,7 +67,7 @@ func_file_conv () mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; - cygwin/*) + cygwin/* | msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) @@ -255,7 +255,8 @@ EOF echo "compile $scriptversion" exit $? ;; - cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ + icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac @@ -339,9 +340,9 @@ exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" +# time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: diff --git a/autotools/config.guess b/autotools/config.guess index 1000e2bd9..f7727026b 100755 --- a/autotools/config.guess +++ b/autotools/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2017 Free Software Foundation, Inc. +# Copyright 1992-2021 Free Software Foundation, Inc. -timestamp='2017-02-07' +timestamp='2021-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ timestamp='2017-02-07' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -27,19 +27,19 @@ timestamp='2017-02-07' # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . -me=`echo "$0" | sed -e 's,.*/,,'` +me=$(echo "$0" | sed -e 's,.*/,,') usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. -Operation modes: +Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2017 Free Software Foundation, Inc. +Copyright 1992-2021 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -84,8 +84,6 @@ if test $# != 0; then exit 1 fi -trap 'exit 1' 1 2 15 - # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a @@ -96,66 +94,89 @@ trap 'exit 1' 1 2 15 # Portable tmp directory creation inspired by the Autoconf team. -set_cc_for_build=' -trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; -trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; -: ${TMPDIR=/tmp} ; - { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; -dummy=$tmp/dummy ; -tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > $dummy.c ; - for c in cc gcc c89 c99 ; do - if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then - CC_FOR_BUILD="$c"; break ; - fi ; - done ; - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found ; - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; -esac ; set_cc_for_build= ;' +tmp= +# shellcheck disable=SC2172 +trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 + +set_cc_for_build() { + # prevent multiple calls if $tmp is already set + test "$tmp" && return 0 + : "${TMPDIR=/tmp}" + # shellcheck disable=SC2039 + { tmp=$( (umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null) && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } + dummy=$tmp/dummy + case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" + for driver in cc gcc c89 c99 ; do + if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD="$driver" + break + fi + done + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; + esac +} # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) -if (test -f /.attbin/uname) >/dev/null 2>&1 ; then +if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi -UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown +UNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown +UNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown +UNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown +UNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown -case "${UNAME_SYSTEM}" in +case "$UNAME_SYSTEM" in Linux|GNU|GNU/*) - # If the system lacks a compiler, then just pick glibc. - # We could probably try harder. - LIBC=gnu + LIBC=unknown - eval $set_cc_for_build - cat <<-EOF > $dummy.c + set_cc_for_build + cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc - #else + #elif defined(__GLIBC__) LIBC=gnu + #else + #include + /* First heuristic to detect musl libc. */ + #ifdef __DEFINED_va_list + LIBC=musl + #endif #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')" + + # Second heuristic to detect musl libc. + if [ "$LIBC" = unknown ] && + command -v ldd >/dev/null && + ldd --version 2>&1 | grep -q ^musl; then + LIBC=musl + fi + + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + if [ "$LIBC" = unknown ]; then + LIBC=gnu + fi ;; esac # Note: order is significant - the case branches are not exclusive. -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in +case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, @@ -168,31 +189,32 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ - /sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || \ - echo unknown)` - case "${UNAME_MACHINE_ARCH}" in + UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \ + "/sbin/$sysctl" 2>/dev/null || \ + "/usr/sbin/$sysctl" 2>/dev/null || \ + echo unknown)) + case "$UNAME_MACHINE_ARCH" in + aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) - arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` - endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` - machine=${arch}${endian}-unknown + arch=$(echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,') + endian=$(echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p') + machine="${arch}${endian}"-unknown ;; - *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + *) machine="$UNAME_MACHINE_ARCH"-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. - case "${UNAME_MACHINE_ARCH}" in + case "$UNAME_MACHINE_ARCH" in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval $set_cc_for_build + set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then @@ -208,10 +230,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ;; esac # Determine ABI tags. - case "${UNAME_MACHINE_ARCH}" in + case "$UNAME_MACHINE_ARCH" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + abi=$(echo "$UNAME_MACHINE_ARCH" | sed -e "$expr") ;; esac # The OS release @@ -219,60 +241,75 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. - case "${UNAME_VERSION}" in + case "$UNAME_VERSION" in Debian*) release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + release=$(echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2) ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}${abi}" + echo "$machine-${os}${release}${abi-}" exit ;; *:Bitrig:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//') + echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" exit ;; *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//') + echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" exit ;; *:LibertyBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//') + echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" + exit ;; + *:MidnightBSD:*:*) + echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" exit ;; *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" exit ;; *:SolidBSD:*:*) - echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" + exit ;; + *:OS108:*:*) + echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE" exit ;; macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd${UNAME_RELEASE} + echo powerpc-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:Sortix:*:*) - echo ${UNAME_MACHINE}-unknown-sortix + echo "$UNAME_MACHINE"-unknown-sortix + exit ;; + *:Twizzler:*:*) + echo "$UNAME_MACHINE"-unknown-twizzler + exit ;; + *:Redox:*:*) + echo "$UNAME_MACHINE"-unknown-redox + exit ;; + mips:OSF1:*.*) + echo mips-dec-osf1 exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}') ;; *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}') ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1) case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE=alpha ;; @@ -310,28 +347,19 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)" # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos + echo "$UNAME_MACHINE"-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-morphos + echo "$UNAME_MACHINE"-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition @@ -343,7 +371,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} + echo arm-acorn-riscix"$UNAME_RELEASE" exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos @@ -353,7 +381,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "`(/bin/universe) 2>/dev/null`" = att ; then + if test "$( (/bin/universe) 2>/dev/null)" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd @@ -366,28 +394,28 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case `/usr/bin/uname -p` in + case $(/usr/bin/uname -p) in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) - echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')" exit ;; sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')" exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux${UNAME_RELEASE} + echo i386-pc-auroraux"$UNAME_RELEASE" exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - eval $set_cc_for_build + set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. - if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null @@ -395,40 +423,40 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in SUN_ARCH=x86_64 fi fi - echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" exit ;; sun4*:SunOS:*:*) - case "`/usr/bin/arch -k`" in + case "$(/usr/bin/arch -k)" in Series*|S4*) - UNAME_RELEASE=`uname -v` + UNAME_RELEASE=$(uname -v) ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')" exit ;; sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} + echo m68k-sun-sunos"$UNAME_RELEASE" exit ;; sun*:*:4.2BSD:*) - UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 - case "`/bin/arch`" in + UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null) + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 + case "$(/bin/arch)" in sun3) - echo m68k-sun-sunos${UNAME_RELEASE} + echo m68k-sun-sunos"$UNAME_RELEASE" ;; sun4) - echo sparc-sun-sunos${UNAME_RELEASE} + echo sparc-sun-sunos"$UNAME_RELEASE" ;; esac exit ;; aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} + echo sparc-auspex-sunos"$UNAME_RELEASE" exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not @@ -439,44 +467,44 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint"$UNAME_RELEASE" exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint"$UNAME_RELEASE" exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint"$UNAME_RELEASE" exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} + echo m68k-milan-mint"$UNAME_RELEASE" exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} + echo m68k-hades-mint"$UNAME_RELEASE" exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} + echo m68k-unknown-mint"$UNAME_RELEASE" exit ;; m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} + echo m68k-apple-machten"$UNAME_RELEASE" exit ;; powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} + echo powerpc-apple-machten"$UNAME_RELEASE" exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} + echo mips-dec-ultrix"$UNAME_RELEASE" exit ;; VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} + echo vax-dec-ultrix"$UNAME_RELEASE" exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} + echo clipper-intergraph-clix"$UNAME_RELEASE" exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { @@ -485,23 +513,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && - dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`$dummy $dummyarg` && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=$(echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p') && + SYSTEM_NAME=$("$dummy" "$dummyarg") && { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos${UNAME_RELEASE} + echo mips-mips-riscos"$UNAME_RELEASE" exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax @@ -526,18 +554,18 @@ EOF exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + UNAME_PROCESSOR=$(/usr/bin/uname -p) + if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ - [ ${TARGET_BINARY_INTERFACE}x = x ] + if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ + test "$TARGET_BINARY_INTERFACE"x = x then - echo m88k-dg-dgux${UNAME_RELEASE} + echo m88k-dg-dgux"$UNAME_RELEASE" else - echo m88k-dg-dguxbcs${UNAME_RELEASE} + echo m88k-dg-dguxbcs"$UNAME_RELEASE" fi else - echo i586-dg-dgux${UNAME_RELEASE} + echo i586-dg-dgux"$UNAME_RELEASE" fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) @@ -554,26 +582,26 @@ EOF echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')" exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + exit ;; # Note that: echo "'$(uname -s)'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` + if test -x /usr/bin/oslevel ; then + IBM_REV=$(/usr/bin/oslevel) else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi - echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" #include main() @@ -584,7 +612,7 @@ EOF exit(0); } EOF - if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") then echo "$SYSTEM_NAME" else @@ -597,28 +625,28 @@ EOF fi exit ;; *:AIX:*:[4567]) - IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }') + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi - if [ -x /usr/bin/lslpp ] ; then - IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | - awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + if test -x /usr/bin/lslpp ; then + IBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/) else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} + echo "$IBM_ARCH"-ibm-aix"$IBM_REV" exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx @@ -633,28 +661,28 @@ EOF echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; + HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//') + case "$UNAME_MACHINE" in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) - if [ -x /usr/bin/getconf ]; then - sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in + if test -x /usr/bin/getconf; then + sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 2>/dev/null) + sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null) + case "$sc_cpu_version" in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in + case "$sc_kernel_bits" in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi - if [ "${HP_ARCH}" = "" ]; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + if test "$HP_ARCH" = ""; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include @@ -687,13 +715,13 @@ EOF exit (0); } EOF - (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=$("$dummy") test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = hppa2.0w ] + if test "$HP_ARCH" = hppa2.0w then - eval $set_cc_for_build + set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler @@ -712,15 +740,15 @@ EOF HP_ARCH=hppa64 fi fi - echo ${HP_ARCH}-hp-hpux${HPUX_REV} + echo "$HP_ARCH"-hp-hpux"$HPUX_REV" exit ;; ia64:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux${HPUX_REV} + HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//') + echo ia64-hp-hpux"$HPUX_REV" exit ;; 3050*:HI-UX:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" #include int main () @@ -745,11 +773,11 @@ EOF exit (0); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) @@ -758,17 +786,17 @@ EOF *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) - if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk + if test -x /usr/sbin/sysversion ; then + echo "$UNAME_MACHINE"-unknown-osf1mk else - echo ${UNAME_MACHINE}-unknown-osf1 + echo "$UNAME_MACHINE"-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) @@ -793,130 +821,123 @@ EOF echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) - echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` - FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz) + FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///') + FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/') echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///') + FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/') echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" exit ;; sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} + echo sparc-unknown-bsdi"$UNAME_RELEASE" exit ;; *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" + exit ;; + arm:FreeBSD:*:*) + UNAME_PROCESSOR=$(uname -p) + set_cc_for_build + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi + else + echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf + fi exit ;; *:FreeBSD:*:*) - UNAME_PROCESSOR=`/usr/bin/uname -p` - case ${UNAME_PROCESSOR} in + UNAME_PROCESSOR=$(/usr/bin/uname -p) + case "$UNAME_PROCESSOR" in amd64) - echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - *) - echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; esac + echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')" exit ;; i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin + echo "$UNAME_MACHINE"-pc-cygwin exit ;; *:MINGW64*:*) - echo ${UNAME_MACHINE}-pc-mingw64 + echo "$UNAME_MACHINE"-pc-mingw64 exit ;; *:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 + echo "$UNAME_MACHINE"-pc-mingw32 exit ;; *:MSYS*:*) - echo ${UNAME_MACHINE}-pc-msys - exit ;; - i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 + echo "$UNAME_MACHINE"-pc-msys exit ;; i*:PW*:*) - echo ${UNAME_MACHINE}-pc-pw32 + echo "$UNAME_MACHINE"-pc-pw32 exit ;; *:Interix*:*) - case ${UNAME_MACHINE} in + case "$UNAME_MACHINE" in x86) - echo i586-pc-interix${UNAME_RELEASE} + echo i586-pc-interix"$UNAME_RELEASE" exit ;; authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix${UNAME_RELEASE} + echo x86_64-unknown-interix"$UNAME_RELEASE" exit ;; IA64) - echo ia64-unknown-interix${UNAME_RELEASE} + echo ia64-unknown-interix"$UNAME_RELEASE" exit ;; esac ;; - [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) - echo i${UNAME_MACHINE}-pc-mks - exit ;; - 8664:Windows_NT:*) - echo x86_64-pc-mks - exit ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i586-pc-interix - exit ;; i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin + echo "$UNAME_MACHINE"-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-unknown-cygwin - exit ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin + echo x86_64-pc-cygwin exit ;; prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" exit ;; *:GNU:*:*) # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo "$UNAME_RELEASE"|sed -e 's,/.*$,,')" exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC" exit ;; - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix + *:Minix:*:*) + echo "$UNAME_MACHINE"-unknown-minix exit ;; aarch64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + case $(sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null) in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; @@ -927,140 +948,181 @@ EOF esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arc:Linux:*:* | arceb:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arm*:Linux:*:*) - eval $set_cc_for_build + set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi else - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf fi fi exit ;; avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; cris:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; crisv32:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; e2k:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; frv:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; hexagon:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; k1om:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; mips:Linux:*:* | mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + set_cc_for_build + IS_GLIBC=0 + test x"${LIBC}" = xgnu && IS_GLIBC=1 + sed 's/^ //' << EOF > "$dummy.c" #undef CPU - #undef ${UNAME_MACHINE} - #undef ${UNAME_MACHINE}el + #undef mips + #undef mipsel + #undef mips64 + #undef mips64el + #if ${IS_GLIBC} && defined(_ABI64) + LIBCABI=gnuabi64 + #else + #if ${IS_GLIBC} && defined(_ABIN32) + LIBCABI=gnuabin32 + #else + LIBCABI=${LIBC} + #endif + #endif + + #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa64r6 + #else + #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa32r6 + #else + #if defined(__mips64) + CPU=mips64 + #else + CPU=mips + #endif + #endif + #endif + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=${UNAME_MACHINE}el + MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=${UNAME_MACHINE} + MIPS_ENDIAN= #else - CPU= + MIPS_ENDIAN= #endif #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI')" + test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; openrisc*:Linux:*:*) - echo or1k-unknown-linux-${LIBC} + echo or1k-unknown-linux-"$LIBC" exit ;; or32:Linux:*:* | or1k*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; padre:Linux:*:*) - echo sparc-unknown-linux-${LIBC} + echo sparc-unknown-linux-"$LIBC" exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-${LIBC} + echo hppa64-unknown-linux-"$LIBC" exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level - case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; - PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; - *) echo hppa-unknown-linux-${LIBC} ;; + case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in + PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; + PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; + *) echo hppa-unknown-linux-"$LIBC" ;; esac exit ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-${LIBC} + echo powerpc64-unknown-linux-"$LIBC" exit ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-${LIBC} + echo powerpc-unknown-linux-"$LIBC" exit ;; ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-${LIBC} + echo powerpc64le-unknown-linux-"$LIBC" exit ;; ppcle:Linux:*:*) - echo powerpcle-unknown-linux-${LIBC} + echo powerpcle-unknown-linux-"$LIBC" exit ;; - riscv32:Linux:*:* | riscv64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" exit ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; tile*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-${LIBC} + echo "$UNAME_MACHINE"-dec-linux-"$LIBC" exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} + set_cc_for_build + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_X32 >/dev/null + then + LIBCABI="$LIBC"x32 + fi + fi + echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI" exit ;; xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. @@ -1074,51 +1136,51 @@ EOF # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. - echo ${UNAME_MACHINE}-pc-os2-emx + echo "$UNAME_MACHINE"-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop + echo "$UNAME_MACHINE"-unknown-stop exit ;; i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos + echo "$UNAME_MACHINE"-unknown-atheos exit ;; i*86:syllable:*:*) - echo ${UNAME_MACHINE}-pc-syllable + echo "$UNAME_MACHINE"-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} + echo i386-unknown-lynxos"$UNAME_RELEASE" exit ;; i*86:*DOS:*:*) - echo ${UNAME_MACHINE}-pc-msdosdjgpp + echo "$UNAME_MACHINE"-pc-msdosdjgpp exit ;; - i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) - UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + i*86:*:4.*:*) + UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//') if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. - case `/bin/uname -X | grep "^Machine"` in + case $(/bin/uname -X | grep "^Machine") in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}" exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then - UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then - UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //')) (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 @@ -1126,9 +1188,9 @@ EOF && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" else - echo ${UNAME_MACHINE}-pc-sysv32 + echo "$UNAME_MACHINE"-pc-sysv32 fi exit ;; pc:*:*:*) @@ -1148,9 +1210,9 @@ EOF exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) @@ -1168,41 +1230,41 @@ EOF 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} + echo m68k-unknown-lynxos"$UNAME_RELEASE" exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} + echo sparc-unknown-lynxos"$UNAME_RELEASE" exit ;; rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} + echo rs6000-unknown-lynxos"$UNAME_RELEASE" exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos${UNAME_RELEASE} + echo powerpc-unknown-lynxos"$UNAME_RELEASE" exit ;; SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} + echo mips-dde-sysv"$UNAME_RELEASE" exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 @@ -1212,8 +1274,8 @@ EOF exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 + UNAME_MACHINE=$( (uname -p) 2>/dev/null) + echo "$UNAME_MACHINE"-sni-sysv4 else echo ns32k-sni-sysv fi @@ -1233,23 +1295,23 @@ EOF exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. - echo ${UNAME_MACHINE}-stratus-vos + echo "$UNAME_MACHINE"-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} + echo m68k-apple-aux"$UNAME_RELEASE" exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + if test -d /usr/nec; then + echo mips-nec-sysv"$UNAME_RELEASE" else - echo mips-unknown-sysv${UNAME_RELEASE} + echo mips-unknown-sysv"$UNAME_RELEASE" fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. @@ -1268,83 +1330,97 @@ EOF echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} + echo sx4-nec-superux"$UNAME_RELEASE" exit ;; SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} + echo sx5-nec-superux"$UNAME_RELEASE" exit ;; SX-6:SUPER-UX:*:*) - echo sx6-nec-superux${UNAME_RELEASE} + echo sx6-nec-superux"$UNAME_RELEASE" exit ;; SX-7:SUPER-UX:*:*) - echo sx7-nec-superux${UNAME_RELEASE} + echo sx7-nec-superux"$UNAME_RELEASE" exit ;; SX-8:SUPER-UX:*:*) - echo sx8-nec-superux${UNAME_RELEASE} + echo sx8-nec-superux"$UNAME_RELEASE" exit ;; SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux${UNAME_RELEASE} + echo sx8r-nec-superux"$UNAME_RELEASE" exit ;; SX-ACE:SUPER-UX:*:*) - echo sxace-nec-superux${UNAME_RELEASE} + echo sxace-nec-superux"$UNAME_RELEASE" exit ;; Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} + echo powerpc-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" + exit ;; + arm64:Darwin:*:*) + echo aarch64-apple-darwin"$UNAME_RELEASE" exit ;; *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - eval $set_cc_for_build - if test "$UNAME_PROCESSOR" = unknown ; then - UNAME_PROCESSOR=powerpc + UNAME_PROCESSOR=$(uname -p) + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + if command -v xcode-select > /dev/null 2> /dev/null && \ + ! xcode-select --print-path > /dev/null 2> /dev/null ; then + # Avoid executing cc if there is no toolchain installed as + # cc will be a stub that puts up a graphical alert + # prompting the user to install developer tools. + CC_FOR_BUILD=no_compiler_found + else + set_cc_for_build fi - if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then - if [ "$CC_FOR_BUILD" != no_compiler_found ]; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - case $UNAME_PROCESSOR in - i386) UNAME_PROCESSOR=x86_64 ;; - powerpc) UNAME_PROCESSOR=powerpc64 ;; - esac - fi + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then - # Avoid executing cc on OS X 10.9, as it ships with a stub - # that puts up a graphical alert prompting to install - # developer tools. Any system running Mac OS X 10.7 or - # later (Darwin 11 and later) is required to have a 64-bit - # processor. This is not true of the ARM version of Darwin - # that Apple uses in portable devices. - UNAME_PROCESSOR=x86_64 + # uname -m returns i386 or x86_64 + UNAME_PROCESSOR=$UNAME_MACHINE fi - echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=`uname -p` + UNAME_PROCESSOR=$(uname -p) if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi - echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; - NEO-?:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk${UNAME_RELEASE} + NEO-*:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk"$UNAME_RELEASE" exit ;; NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} + echo nse-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSR-*:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk"$UNAME_RELEASE" exit ;; - NSR-?:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk${UNAME_RELEASE} + NSV-*:NONSTOP_KERNEL:*:*) + echo nsv-tandem-nsk"$UNAME_RELEASE" exit ;; - NSX-?:NONSTOP_KERNEL:*:*) - echo nsx-tandem-nsk${UNAME_RELEASE} + NSX-*:NONSTOP_KERNEL:*:*) + echo nsx-tandem-nsk"$UNAME_RELEASE" exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux @@ -1353,18 +1429,19 @@ EOF echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. + # shellcheck disable=SC2154 if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi - echo ${UNAME_MACHINE}-unknown-plan9 + echo "$UNAME_MACHINE"-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 @@ -1385,14 +1462,14 @@ EOF echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} + echo mips-sei-seiux"$UNAME_RELEASE" exit ;; *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')" exit ;; *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in + UNAME_MACHINE=$( (uname -p) 2>/dev/null) + case "$UNAME_MACHINE" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; @@ -1401,32 +1478,190 @@ EOF echo i386-pc-xenix exit ;; i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` + echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ .*$//')" exit ;; i*86:rdos:*:*) - echo ${UNAME_MACHINE}-pc-rdos + echo "$UNAME_MACHINE"-pc-rdos exit ;; i*86:AROS:*:*) - echo ${UNAME_MACHINE}-pc-aros + echo "$UNAME_MACHINE"-pc-aros exit ;; x86_64:VMkernel:*:*) - echo ${UNAME_MACHINE}-unknown-esx + echo "$UNAME_MACHINE"-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; + *:Unleashed:*:*) + echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE" + exit ;; +esac + +# No uname command or uname output not recognized. +set_cc_for_build +cat > "$dummy.c" < +#include +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#include +#if defined(_SIZE_T_) || defined(SIGLOST) +#include +#endif +#endif +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=$( (hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null); + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); +#endif + +#if defined (vax) +#if !defined (ultrix) +#include +#if defined (BSD) +#if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +#else +#if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#endif +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#else +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname un; + uname (&un); + printf ("vax-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname *un; + uname (&un); + printf ("mips-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("mips-dec-ultrix\n"); exit (0); +#endif +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=$($dummy) && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. +test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } + +echo "$0: unable to guess system type" >&2 + +case "$UNAME_MACHINE:$UNAME_SYSTEM" in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 <&2 </dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` +uname -m = $( (uname -m) 2>/dev/null || echo unknown) +uname -r = $( (uname -r) 2>/dev/null || echo unknown) +uname -s = $( (uname -s) 2>/dev/null || echo unknown) +uname -v = $( (uname -v) 2>/dev/null || echo unknown) -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null` +/usr/bin/uname -p = $( (/usr/bin/uname -p) 2>/dev/null) +/bin/uname -X = $( (/bin/uname -X) 2>/dev/null) -hostinfo = `(hostinfo) 2>/dev/null` -/bin/universe = `(/bin/universe) 2>/dev/null` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` -/bin/arch = `(/bin/arch) 2>/dev/null` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` +hostinfo = $( (hostinfo) 2>/dev/null) +/bin/universe = $( (/bin/universe) 2>/dev/null) +/usr/bin/arch -k = $( (/usr/bin/arch -k) 2>/dev/null) +/bin/arch = $( (/bin/arch) 2>/dev/null) +/usr/bin/oslevel = $( (/usr/bin/oslevel) 2>/dev/null) +/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null) -UNAME_MACHINE = ${UNAME_MACHINE} -UNAME_RELEASE = ${UNAME_RELEASE} -UNAME_SYSTEM = ${UNAME_SYSTEM} -UNAME_VERSION = ${UNAME_VERSION} +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" EOF +fi exit 1 # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" diff --git a/autotools/config.sub b/autotools/config.sub index 87abeab6c..4d89efe3b 100755 --- a/autotools/config.sub +++ b/autotools/config.sub @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2017 Free Software Foundation, Inc. +# Copyright 1992-2021 Free Software Foundation, Inc. -timestamp='2017-02-07' +timestamp='2021-01-07' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ timestamp='2017-02-07' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -33,7 +33,7 @@ timestamp='2017-02-07' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub +# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -50,14 +50,14 @@ timestamp='2017-02-07' # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. -me=`echo "$0" | sed -e 's,.*/,,'` +me=$(echo "$0" | sed -e 's,.*/,,') usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. -Operation modes: +Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -67,7 +67,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2017 Free Software Foundation, Inc. +Copyright 1992-2021 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -89,12 +89,12 @@ while test $# -gt 0 ; do - ) # Use stdin as input. break ;; -* ) - echo "$me: invalid option $1$help" + echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. - echo $1 + echo "$1" exit ;; * ) @@ -110,1247 +110,1190 @@ case $# in exit 1;; esac -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ - kopensolaris*-gnu* | cloudabi*-eabi* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - android-linux) - os=-linux-android - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac +# Split fields of configuration type +# shellcheck disable=SC2162 +IFS="-" read field1 field2 field3 field4 <&2 + exit 1 ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + *-*-*-*) + basic_machine=$field1-$field2 + basic_os=$field3-$field4 ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + basic_os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + basic_os=linux-android + ;; + *) + basic_machine=$field1-$field2 + basic_os=$field3 + ;; + esac ;; - -psos*) - os=-psos + *-*) + # A lone config we happen to match not fitting any pattern + case $field1-$field2 in + decstation-3100) + basic_machine=mips-dec + basic_os= + ;; + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + basic_os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* \ + | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ + | ultra | tti* | harris | dolphin | highlevel | gould \ + | cbm | ns | masscomp | apple | axis | knuth | cray \ + | microblaze* | sim | cisco \ + | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + basic_os= + ;; + *) + basic_machine=$field1 + basic_os=$field2 + ;; + esac + ;; + esac ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + basic_os=bsd + ;; + a29khif) + basic_machine=a29k-amd + basic_os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + basic_os=scout + ;; + alliant) + basic_machine=fx80-alliant + basic_os= + ;; + altos | altos3068) + basic_machine=m68k-altos + basic_os= + ;; + am29k) + basic_machine=a29k-none + basic_os=bsd + ;; + amdahl) + basic_machine=580-amdahl + basic_os=sysv + ;; + amiga) + basic_machine=m68k-unknown + basic_os= + ;; + amigaos | amigados) + basic_machine=m68k-unknown + basic_os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + basic_os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + basic_os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + basic_os=bsd + ;; + aros) + basic_machine=i386-pc + basic_os=aros + ;; + aux) + basic_machine=m68k-apple + basic_os=aux + ;; + balance) + basic_machine=ns32k-sequent + basic_os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + basic_os=linux + ;; + cegcc) + basic_machine=arm-unknown + basic_os=cegcc + ;; + convex-c1) + basic_machine=c1-convex + basic_os=bsd + ;; + convex-c2) + basic_machine=c2-convex + basic_os=bsd + ;; + convex-c32) + basic_machine=c32-convex + basic_os=bsd + ;; + convex-c34) + basic_machine=c34-convex + basic_os=bsd + ;; + convex-c38) + basic_machine=c38-convex + basic_os=bsd + ;; + cray) + basic_machine=j90-cray + basic_os=unicos + ;; + crds | unos) + basic_machine=m68k-crds + basic_os= + ;; + da30) + basic_machine=m68k-da30 + basic_os= + ;; + decstation | pmax | pmin | dec3100 | decstatn) + basic_machine=mips-dec + basic_os= + ;; + delta88) + basic_machine=m88k-motorola + basic_os=sysv3 + ;; + dicos) + basic_machine=i686-pc + basic_os=dicos + ;; + djgpp) + basic_machine=i586-pc + basic_os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + basic_os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + basic_os=ose + ;; + gmicro) + basic_machine=tron-gmicro + basic_os=sysv + ;; + go32) + basic_machine=i386-pc + basic_os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + basic_os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + basic_os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + basic_os=hms + ;; + harris) + basic_machine=m88k-harris + basic_os=sysv3 + ;; + hp300 | hp300hpux) + basic_machine=m68k-hp + basic_os=hpux + ;; + hp300bsd) + basic_machine=m68k-hp + basic_os=bsd + ;; + hppaosf) + basic_machine=hppa1.1-hp + basic_os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + basic_os=proelf + ;; + i386mach) + basic_machine=i386-mach + basic_os=mach + ;; + isi68 | isi) + basic_machine=m68k-isi + basic_os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + basic_os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + basic_os=sysv + ;; + merlin) + basic_machine=ns32k-utek + basic_os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + basic_os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + basic_os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + basic_os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + basic_os=coff + ;; + morphos) + basic_machine=powerpc-unknown + basic_os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + basic_os=moxiebox + ;; + msdos) + basic_machine=i386-pc + basic_os=msdos + ;; + msys) + basic_machine=i686-pc + basic_os=msys + ;; + mvs) + basic_machine=i370-ibm + basic_os=mvs + ;; + nacl) + basic_machine=le32-unknown + basic_os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + basic_os=sysv4 + ;; + netbsd386) + basic_machine=i386-pc + basic_os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + basic_os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + basic_os=newsos + ;; + news1000) + basic_machine=m68030-sony + basic_os=newsos + ;; + necv70) + basic_machine=v70-nec + basic_os=sysv + ;; + nh3000) + basic_machine=m68k-harris + basic_os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + basic_os=cxux + ;; + nindy960) + basic_machine=i960-intel + basic_os=nindy + ;; + mon960) + basic_machine=i960-intel + basic_os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + basic_os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + basic_os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + basic_os=ose + ;; + os68k) + basic_machine=m68k-none + basic_os=os68k + ;; + paragon) + basic_machine=i860-intel + basic_os=osf + ;; + parisc) + basic_machine=hppa-unknown + basic_os=linux + ;; + psp) + basic_machine=mipsallegrexel-sony + basic_os=psp + ;; + pw32) + basic_machine=i586-unknown + basic_os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + basic_os=rdos + ;; + rdos32) + basic_machine=i386-pc + basic_os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + basic_os=coff + ;; + sa29200) + basic_machine=a29k-amd + basic_os=udi + ;; + sei) + basic_machine=mips-sei + basic_os=seiux + ;; + sequent) + basic_machine=i386-sequent + basic_os= + ;; + sps7) + basic_machine=m68k-bull + basic_os=sysv2 + ;; + st2000) + basic_machine=m68k-tandem + basic_os= + ;; + stratus) + basic_machine=i860-stratus + basic_os=sysv4 + ;; + sun2) + basic_machine=m68000-sun + basic_os= + ;; + sun2os3) + basic_machine=m68000-sun + basic_os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + basic_os=sunos4 + ;; + sun3) + basic_machine=m68k-sun + basic_os= + ;; + sun3os3) + basic_machine=m68k-sun + basic_os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + basic_os=sunos4 + ;; + sun4) + basic_machine=sparc-sun + basic_os= + ;; + sun4os3) + basic_machine=sparc-sun + basic_os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + basic_os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + basic_os=solaris2 + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + basic_os= + ;; + sv1) + basic_machine=sv1-cray + basic_os=unicos + ;; + symmetry) + basic_machine=i386-sequent + basic_os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + basic_os=unicos + ;; + t90) + basic_machine=t90-cray + basic_os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + basic_os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + basic_os=tpf + ;; + udi29k) + basic_machine=a29k-amd + basic_os=udi + ;; + ultra3) + basic_machine=a29k-nyu + basic_os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + basic_os=none + ;; + vaxv) + basic_machine=vax-dec + basic_os=sysv + ;; + vms) + basic_machine=vax-dec + basic_os=vms + ;; + vsta) + basic_machine=i386-pc + basic_os=vsta + ;; + vxworks960) + basic_machine=i960-wrs + basic_os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + basic_os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + basic_os=vxworks + ;; + xbox) + basic_machine=i686-pc + basic_os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + basic_os=unicos + ;; + *) + basic_machine=$1 + basic_os= + ;; + esac ;; esac -# Decode aliases for certain CPU-COMPANY combinations. +# Decode 1-component or ad-hoc basic machines case $basic_machine in - # Recognize the basic CPU types without company name. - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ - | aarch64 | aarch64_be \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ - | arc | arceb \ - | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ - | avr | avr32 \ - | ba \ - | be32 | be64 \ - | bfin \ - | c4x | c8051 | clipper \ - | d10v | d30v | dlx | dsp16xx \ - | e2k | epiphany \ - | fido | fr30 | frv | ft32 \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | hexagon \ - | i370 | i860 | i960 | ia64 \ - | ip2k | iq2000 \ - | k1om \ - | le32 | le64 \ - | lm32 \ - | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64el \ - | mips64octeon | mips64octeonel \ - | mips64orion | mips64orionel \ - | mips64r5900 | mips64r5900el \ - | mips64vr | mips64vrel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa32r6 | mipsisa32r6el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64r6 | mipsisa64r6el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ - | mipstx39 | mipstx39el \ - | mn10200 | mn10300 \ - | moxie \ - | mt \ - | msp430 \ - | nds32 | nds32le | nds32be \ - | nios | nios2 | nios2eb | nios2el \ - | ns16k | ns32k \ - | open8 | or1k | or1knd | or32 \ - | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle \ - | pru \ - | pyramid \ - | riscv32 | riscv64 \ - | rl78 | rx \ - | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ - | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu \ - | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ - | ubicom32 \ - | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ - | visium \ - | we32k \ - | x86 | xc16x | xstormy16 | xtensa \ - | z8k | z80) - basic_machine=$basic_machine-unknown - ;; - c54x) - basic_machine=tic54x-unknown - ;; - c55x) - basic_machine=tic55x-unknown - ;; - c6x) - basic_machine=tic6x-unknown - ;; - leon|leon[3-9]) - basic_machine=sparc-$basic_machine - ;; - m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) - basic_machine=$basic_machine-unknown - os=-none + # Here we handle the default manufacturer of certain CPU types. It is in + # some cases the only manufacturer, in others, it is the most popular. + w89k) + cpu=hppa1.1 + vendor=winbond ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + op50n) + cpu=hppa1.1 + vendor=oki ;; - ms1) - basic_machine=mt-unknown + op60c) + cpu=hppa1.1 + vendor=oki ;; - - strongarm | thumb | xscale) - basic_machine=arm-unknown + ibm*) + cpu=i370 + vendor=ibm ;; - xgate) - basic_machine=$basic_machine-unknown - os=-none + orion105) + cpu=clipper + vendor=highlevel ;; - xscaleeb) - basic_machine=armeb-unknown + mac | mpw | mac-mpw) + cpu=m68k + vendor=apple ;; - - xscaleel) - basic_machine=armel-unknown + pmac | pmac-mpw) + cpu=powerpc + vendor=apple ;; - # We use `pc' rather than `unknown' - # because (1) that's what they normally are, and - # (2) the word "unknown" tends to confuse beginning users. - i*86 | x86_64) - basic_machine=$basic_machine-pc - ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ - | aarch64-* | aarch64_be-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | avr-* | avr32-* \ - | ba-* \ - | be32-* | be64-* \ - | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | c8051-* | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ - | e2k-* | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ - | hexagon-* \ - | i*86-* | i860-* | i960-* | ia64-* \ - | ip2k-* | iq2000-* \ - | k1om-* \ - | le32-* | le64-* \ - | lm32-* \ - | m32c-* | m32r-* | m32rle-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ - | microblaze-* | microblazeel-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | mips16-* \ - | mips64-* | mips64el-* \ - | mips64octeon-* | mips64octeonel-* \ - | mips64orion-* | mips64orionel-* \ - | mips64r5900-* | mips64r5900el-* \ - | mips64vr-* | mips64vrel-* \ - | mips64vr4100-* | mips64vr4100el-* \ - | mips64vr4300-* | mips64vr4300el-* \ - | mips64vr5000-* | mips64vr5000el-* \ - | mips64vr5900-* | mips64vr5900el-* \ - | mipsisa32-* | mipsisa32el-* \ - | mipsisa32r2-* | mipsisa32r2el-* \ - | mipsisa32r6-* | mipsisa32r6el-* \ - | mipsisa64-* | mipsisa64el-* \ - | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64r6-* | mipsisa64r6el-* \ - | mipsisa64sb1-* | mipsisa64sb1el-* \ - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipsr5900-* | mipsr5900el-* \ - | mipstx39-* | mipstx39el-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ - | nds32-* | nds32le-* | nds32be-* \ - | nios-* | nios2-* | nios2eb-* | nios2el-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ - | open8-* \ - | or1k*-* \ - | orion-* \ - | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ - | pru-* \ - | pyramid-* \ - | riscv32-* | riscv64-* \ - | rl78-* | romp-* | rs6000-* | rx-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ - | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ - | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ - | tahoe-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ - | tile*-* \ - | tron-* \ - | ubicom32-* \ - | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ - | vax-* \ - | visium-* \ - | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* \ - | xstormy16-* | xtensa*-* \ - | ymp-* \ - | z8k-* | z80-*) - ;; - # Recognize the basic CPU types without company name, with glob match. - xtensa*) - basic_machine=$basic_machine-unknown - ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - basic_machine=m68000-att + cpu=m68000 + vendor=att ;; 3b*) - basic_machine=we32k-att - ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; - abacus) - basic_machine=abacus-unknown - ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; - alliant | fx80) - basic_machine=fx80-alliant - ;; - altos | altos3068) - basic_machine=m68k-altos - ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; - amd64) - basic_machine=x86_64-pc - ;; - amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv - ;; - amiga | amiga-*) - basic_machine=m68k-unknown - ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aros) - basic_machine=i386-pc - os=-aros - ;; - asmjs) - basic_machine=asmjs-unknown - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - blackfin) - basic_machine=bfin-unknown - os=-linux - ;; - blackfin-*) - basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux + cpu=we32k + vendor=att ;; bluegene*) - basic_machine=powerpc-ibm - os=-cnk - ;; - c54x-*) - basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c55x-*) - basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c6x-*) - basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c90) - basic_machine=c90-cray - os=-unicos - ;; - cegcc) - basic_machine=arm-unknown - os=-cegcc - ;; - convex-c1) - basic_machine=c1-convex - os=-bsd - ;; - convex-c2) - basic_machine=c2-convex - os=-bsd - ;; - convex-c32) - basic_machine=c32-convex - os=-bsd - ;; - convex-c34) - basic_machine=c34-convex - os=-bsd - ;; - convex-c38) - basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp - ;; - cr16 | cr16-*) - basic_machine=cr16-unknown - os=-elf - ;; - crds | unos) - basic_machine=m68k-crds - ;; - crisv32 | crisv32-* | etraxfs*) - basic_machine=crisv32-axis - ;; - cris | cris-* | etrax*) - basic_machine=cris-axis - ;; - crx) - basic_machine=crx-unknown - os=-elf - ;; - da30 | da30-*) - basic_machine=m68k-da30 - ;; - decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) - basic_machine=mips-dec + cpu=powerpc + vendor=ibm + basic_os=cnk ;; decsystem10* | dec10*) - basic_machine=pdp10-dec - os=-tops10 + cpu=pdp10 + vendor=dec + basic_os=tops10 ;; decsystem20* | dec20*) - basic_machine=pdp10-dec - os=-tops20 + cpu=pdp10 + vendor=dec + basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) - basic_machine=m68k-motorola + cpu=m68k + vendor=motorola ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - dicos) - basic_machine=i686-pc - os=-dicos - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; - dpx20 | dpx20-*) - basic_machine=rs6000-bull - os=-bosx - ;; - dpx2* | dpx2*-bull) - basic_machine=m68k-bull - os=-sysv3 - ;; - e500v[12]) - basic_machine=powerpc-unknown - os=$os"spe" - ;; - e500v[12]-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - os=$os"spe" - ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd + dpx2*) + cpu=m68k + vendor=bull + basic_os=sysv3 ;; encore | umax | mmax) - basic_machine=ns32k-encore + cpu=ns32k + vendor=encore ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose + elxsi) + cpu=elxsi + vendor=elxsi + basic_os=${basic_os:-bsd} ;; fx2800) - basic_machine=i860-alliant + cpu=i860 + vendor=alliant ;; genix) - basic_machine=ns32k-ns - ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 + cpu=ns32k + vendor=ns ;; h3050r* | hiux*) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 - ;; - hp300-*) - basic_machine=m68k-hp - ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) - basic_machine=hppa1.0-hp + cpu=hppa1.0 + vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) - basic_machine=m68000-hp + cpu=m68000 + vendor=hp ;; hp9k3[2-9][0-9]) - basic_machine=m68k-hp + cpu=m68k + vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) - basic_machine=hppa1.0-hp + cpu=hppa1.0 + vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) - basic_machine=hppa1.1-hp + cpu=hppa1.1 + vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp + cpu=hppa1.1 + vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp + cpu=hppa1.1 + vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) - basic_machine=hppa1.1-hp + cpu=hppa1.1 + vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; - i370-ibm* | ibm*) - basic_machine=i370-ibm + cpu=hppa1.0 + vendor=hp ;; i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 + cpu=$(echo "$1" | sed -e 's/86.*/86/') + vendor=pc + basic_os=sysv32 ;; i*86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 + cpu=$(echo "$1" | sed -e 's/86.*/86/') + vendor=pc + basic_os=sysv4 ;; i*86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv + cpu=$(echo "$1" | sed -e 's/86.*/86/') + vendor=pc + basic_os=sysv ;; i*86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 + cpu=$(echo "$1" | sed -e 's/86.*/86/') + vendor=pc + basic_os=solaris2 ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta + j90 | j90-cray) + cpu=j90 + vendor=cray + basic_os=${basic_os:-unicos} ;; iris | iris4d) - basic_machine=mips-sgi - case $os in - -irix*) + cpu=mips + vendor=sgi + case $basic_os in + irix*) ;; *) - os=-irix4 + basic_os=irix4 ;; esac ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; - leon-*|leon[3-9]-*) - basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` - ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux - ;; - m68knommu-*) - basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv - ;; - microblaze*) - basic_machine=microblaze-xilinx - ;; - mingw64) - basic_machine=x86_64-pc - os=-mingw64 - ;; - mingw32) - basic_machine=i686-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; miniframe) - basic_machine=m68000-convergent - ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; - mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + cpu=m68000 + vendor=convergent ;; - mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) + cpu=m68k + vendor=atari + basic_os=mint ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - moxiebox) - basic_machine=moxie-unknown - os=-moxiebox - ;; - msdos) - basic_machine=i386-pc - os=-msdos - ;; - ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; - msys) - basic_machine=i686-pc - os=-msys - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - nacl) - basic_machine=le32-unknown - os=-nacl - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux + mipsEE* | ee) + cpu=mips64r5900el + vendor=scei + case $os in + linux*) + ;; + *) + os=elf + ;; + esac ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos + iop) + cpu=mipsel + vendor=scei + os=irx ;; - news1000) - basic_machine=m68030-sony - os=-newsos + dvp) + cpu=dvp + vendor=scei + os=elf ;; news-3600 | risc-news) - basic_machine=mips-sony - os=-newsos - ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) - basic_machine=m68k-next - case $os in - -nextstep* ) + cpu=mips + vendor=sony + basic_os=newsos + ;; + next | m*-next) + cpu=m68k + vendor=next + case $basic_os in + openstep*) + ;; + nextstep*) ;; - -ns2*) - os=-nextstep2 + ns2*) + basic_os=nextstep2 ;; *) - os=-nextstep3 + basic_os=nextstep3 ;; esac ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; np1) - basic_machine=np1-gould - ;; - neo-tandem) - basic_machine=neo-tandem - ;; - nse-tandem) - basic_machine=nse-tandem - ;; - nsr-tandem) - basic_machine=nsr-tandem - ;; - nsx-tandem) - basic_machine=nsx-tandem + cpu=np1 + vendor=gould ;; op50n-* | op60c-*) - basic_machine=hppa1.1-oki - os=-proelf - ;; - openrisc | openrisc-*) - basic_machine=or32-unknown - ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k + cpu=hppa1.1 + vendor=oki + basic_os=proelf ;; pa-hitachi) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - parisc) - basic_machine=hppa-unknown - os=-linux - ;; - parisc-*) - basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 ;; pbd) - basic_machine=sparc-tti + cpu=sparc + vendor=tti ;; pbb) - basic_machine=m68k-tti + cpu=m68k + vendor=tti ;; - pc532 | pc532-*) - basic_machine=ns32k-pc532 - ;; - pc98) - basic_machine=i386-pc - ;; - pc98-*) - basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium | p5 | k5 | k6 | nexgen | viac3) - basic_machine=i586-pc - ;; - pentiumpro | p6 | 6x86 | athlon | athlon_*) - basic_machine=i686-pc - ;; - pentiumii | pentium2 | pentiumiii | pentium3) - basic_machine=i686-pc - ;; - pentium4) - basic_machine=i786-pc - ;; - pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium4-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + pc532) + cpu=ns32k + vendor=pc532 ;; pn) - basic_machine=pn-gould - ;; - power) basic_machine=power-ibm + cpu=pn + vendor=gould ;; - ppc | ppcbe) basic_machine=powerpc-unknown - ;; - ppc-* | ppcbe-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppcle | powerpclittle) - basic_machine=powerpcle-unknown - ;; - ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64) basic_machine=powerpc64-unknown - ;; - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64le | powerpc64little) - basic_machine=powerpc64le-unknown - ;; - ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + power) + cpu=power + vendor=ibm ;; ps2) - basic_machine=i386-ibm - ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - os=-rdos - ;; - rdos32) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff + cpu=i386 + vendor=ibm ;; rm[46]00) - basic_machine=mips-siemens + cpu=mips + vendor=siemens ;; rtpc | rtpc-*) - basic_machine=romp-ibm - ;; - s390 | s390-*) - basic_machine=s390-ibm + cpu=romp + vendor=ibm ;; - s390x | s390x-*) - basic_machine=s390x-ibm - ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; - sb1) - basic_machine=mipsisa64sb1-unknown + sde) + cpu=mipsisa32 + vendor=sde + basic_os=${basic_os:-elf} ;; - sb1el) - basic_machine=mipsisa64sb1el-unknown + simso-wrs) + cpu=sparclite + vendor=wrs + basic_os=vxworks ;; - sde) - basic_machine=mipsisa32-sde - os=-elf + tower | tower-32) + cpu=m68k + vendor=ncr ;; - sei) - basic_machine=mips-sei - os=-seiux + vpp*|vx|vx-*) + cpu=f301 + vendor=fujitsu ;; - sequent) - basic_machine=i386-sequent + w65) + cpu=w65 + vendor=wdc ;; - sh) - basic_machine=sh-hitachi - os=-hms + w89k-*) + cpu=hppa1.1 + vendor=winbond + basic_os=proelf ;; - sh5el) - basic_machine=sh5le-unknown + none) + cpu=none + vendor=none ;; - sh64) - basic_machine=sh64-unknown + leon|leon[3-9]) + cpu=sparc + vendor=$basic_machine ;; - sparclite-wrs | simso-wrs) - basic_machine=sparclite-wrs - os=-vxworks + leon-*|leon[3-9]-*) + cpu=sparc + vendor=$(echo "$basic_machine" | sed 's/-.*//') ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 + + *-*) + # shellcheck disable=SC2162 + IFS="-" read cpu vendor <&2 - exit 1 + # Recognize the canonical CPU types that are allowed with any + # company name. + case $cpu in + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | abacus \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ + | alphapca5[67] | alpha64pca5[67] \ + | am33_2.0 \ + | amdgcn \ + | arc | arceb \ + | arm | arm[lb]e | arme[lb] | armv* \ + | avr | avr32 \ + | asmjs \ + | ba \ + | be32 | be64 \ + | bfin | bpf | bs2000 \ + | c[123]* | c30 | [cjt]90 | c4x \ + | c8051 | clipper | craynv | csky | cydra \ + | d10v | d30v | dlx | dsp16xx | dvp \ + | e2k | elxsi | epiphany \ + | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \ + | h8300 | h8500 \ + | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i*86 | i860 | i960 | ia16 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | loongarch32 | loongarch64 | loongarchx32 \ + | m32c | m32r | m32rle \ + | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ + | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ + | m88110 | m88k | maxq | mb | mcore | mep | metag \ + | microblaze | microblazeel \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64eb | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mmix \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nfp \ + | nios | nios2 | nios2eb | nios2el \ + | none | np1 | ns16k | ns32k | nvptx \ + | open8 \ + | or1k* \ + | or32 \ + | orion \ + | picochip \ + | pdp10 | pdp11 | pj | pjl | pn | power \ + | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \ + | pru \ + | pyramid \ + | riscv | riscv32 | riscv32be | riscv64 | riscv64be \ + | rl78 | romp | rs6000 | rx \ + | s390 | s390x \ + | score \ + | sh | shl \ + | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \ + | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \ + | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \ + | spu \ + | tahoe \ + | thumbv7* \ + | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \ + | tron \ + | ubicom32 \ + | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \ + | vax \ + | visium \ + | w65 \ + | wasm32 | wasm64 \ + | we32k \ + | x86 | x86_64 | xc16x | xgate | xps100 \ + | xstormy16 | xtensa* \ + | ymp \ + | z8k | z80) + ;; + + *) + echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2 + exit 1 + ;; + esac ;; esac # Here we canonicalize certain aliases for manufacturers. -case $basic_machine in - *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` +case $vendor in + digital*) + vendor=dec ;; - *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + commodore*) + vendor=cbm ;; *) ;; @@ -1358,203 +1301,213 @@ esac # Decode manufacturer-specific aliases for certain operating systems. -if [ x"$os" != x"" ] +if test x$basic_os != x then -case $os in - # First match some system type aliases - # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. - -auroraux) - os=-auroraux + +# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just +# set os. +case $basic_os in + gnu/linux*) + kernel=linux + os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|') + ;; + os2-emx) + kernel=os2 + os=$(echo $basic_os | sed -e 's|os2-emx|emx|') + ;; + nto-qnx*) + kernel=nto + os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|') + ;; + *-*) + # shellcheck disable=SC2162 + IFS="-" read kernel os <&2 - exit 1 + # No normalization, but not necessarily accepted, that comes below. ;; esac + else # Here we handle the default operating systems that come with various machines. @@ -1567,264 +1520,356 @@ else # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. -case $basic_machine in +kernel= +case $cpu-$vendor in score-*) - os=-elf + os=elf ;; spu-*) - os=-elf + os=elf ;; *-acorn) - os=-riscix1.2 + os=riscix1.2 ;; arm*-rebel) - os=-linux + kernel=linux + os=gnu ;; arm*-semi) - os=-aout + os=aout ;; c4x-* | tic4x-*) - os=-coff + os=coff ;; c8051-*) - os=-elf + os=elf + ;; + clipper-intergraph) + os=clix ;; hexagon-*) - os=-elf + os=elf ;; tic54x-*) - os=-coff + os=coff ;; tic55x-*) - os=-coff + os=coff ;; tic6x-*) - os=-coff + os=coff ;; # This must come before the *-dec entry. pdp10-*) - os=-tops20 + os=tops20 ;; pdp11-*) - os=-none + os=none ;; *-dec | vax-*) - os=-ultrix4.2 + os=ultrix4.2 ;; m68*-apollo) - os=-domain + os=domain ;; i386-sun) - os=-sunos4.0.2 + os=sunos4.0.2 ;; m68000-sun) - os=-sunos3 + os=sunos3 ;; m68*-cisco) - os=-aout + os=aout ;; mep-*) - os=-elf + os=elf ;; mips*-cisco) - os=-elf + os=elf ;; mips*-*) - os=-elf + os=elf ;; or32-*) - os=-coff + os=coff ;; *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 + os=sysv3 ;; sparc-* | *-sun) - os=-sunos4.1.1 + os=sunos4.1.1 ;; pru-*) - os=-elf + os=elf ;; *-be) - os=-beos - ;; - *-haiku) - os=-haiku + os=beos ;; *-ibm) - os=-aix + os=aix ;; *-knuth) - os=-mmixware + os=mmixware ;; *-wec) - os=-proelf + os=proelf ;; *-winbond) - os=-proelf + os=proelf ;; *-oki) - os=-proelf + os=proelf ;; *-hp) - os=-hpux + os=hpux ;; *-hitachi) - os=-hiux + os=hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv + os=sysv ;; *-cbm) - os=-amigaos + os=amigaos ;; *-dg) - os=-dgux + os=dgux ;; *-dolphin) - os=-sysv3 + os=sysv3 ;; m68k-ccur) - os=-rtu + os=rtu ;; m88k-omron*) - os=-luna + os=luna ;; - *-next ) - os=-nextstep + *-next) + os=nextstep ;; *-sequent) - os=-ptx + os=ptx ;; *-crds) - os=-unos + os=unos ;; *-ns) - os=-genix + os=genix ;; i370-*) - os=-mvs - ;; - *-next) - os=-nextstep3 + os=mvs ;; *-gould) - os=-sysv + os=sysv ;; *-highlevel) - os=-bsd + os=bsd ;; *-encore) - os=-bsd + os=bsd ;; *-sgi) - os=-irix + os=irix ;; *-siemens) - os=-sysv4 + os=sysv4 ;; *-masscomp) - os=-rtu + os=rtu ;; f30[01]-fujitsu | f700-fujitsu) - os=-uxpv + os=uxpv ;; *-rom68k) - os=-coff + os=coff ;; *-*bug) - os=-coff + os=coff ;; *-apple) - os=-macos + os=macos ;; *-atari*) - os=-mint + os=mint + ;; + *-wrs) + os=vxworks ;; *) - os=-none + os=none ;; esac + fi +# Now, validate our (potentially fixed-up) OS. +case $os in + # Sometimes we do "kernel-abi", so those need to count as OSes. + musl* | newlib* | uclibc*) + ;; + # Likewise for "kernel-libc" + eabi* | gnueabi*) + ;; + # Now accept the basic system types. + # The portable systems comes first. + # Each alternative MUST end in a * to match a version number. + gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ + | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \ + | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ + | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ + | hiux* | abug | nacl* | netware* | windows* \ + | os9* | macos* | osx* | ios* \ + | mpw* | magic* | mmixware* | mon960* | lnews* \ + | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ + | aos* | aros* | cloudabi* | sortix* | twizzler* \ + | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ + | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \ + | mirbsd* | netbsd* | dicos* | openedition* | ose* \ + | bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \ + | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \ + | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ + | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | udi* | lites* | ieee* | go32* | aux* | hcos* \ + | chorusrdb* | cegcc* | glidix* \ + | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | midipix* | mingw32* | mingw64* | mint* \ + | uxpv* | beos* | mpeix* | udk* | moxiebox* \ + | interix* | uwin* | mks* | rhapsody* | darwin* \ + | openstep* | oskit* | conix* | pw32* | nonstopux* \ + | storm-chaos* | tops10* | tenex* | tops20* | its* | irx* \ + | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \ + | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \ + | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ + | skyos* | haiku* | rdos* | toppers* | drops* | es* \ + | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ + | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ + | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*) + ;; + # This one is extra strict with allowed versions + sco3.2v2 | sco3.2v[4-9]* | sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + ;; + none) + ;; + *) + echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2 + exit 1 + ;; +esac + +# As a final step for OS-related things, validate the OS-kernel combination +# (given a valid OS), if there is a kernel. +case $kernel-$os in + linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* ) + ;; + uclinux-uclibc* ) + ;; + -dietlibc* | -newlib* | -musl* | -uclibc* ) + # These are just libc implementations, not actual OSes, and thus + # require a kernel. + echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + exit 1 + ;; + kfreebsd*-gnu* | kopensolaris*-gnu*) + ;; + nto-qnx*) + ;; + os2-emx) + ;; + *-eabi* | *-gnueabi*) + ;; + -*) + # Blank kernel with real OS is always fine. + ;; + *-*) + echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + exit 1 + ;; +esac + # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. -vendor=unknown -case $basic_machine in - *-unknown) - case $os in - -riscix*) +case $vendor in + unknown) + case $cpu-$os in + *-riscix*) vendor=acorn ;; - -sunos*) + *-sunos*) vendor=sun ;; - -cnk*|-aix*) + *-cnk* | *-aix*) vendor=ibm ;; - -beos*) + *-beos*) vendor=be ;; - -hpux*) + *-hpux*) vendor=hp ;; - -mpeix*) + *-mpeix*) vendor=hp ;; - -hiux*) + *-hiux*) vendor=hitachi ;; - -unos*) + *-unos*) vendor=crds ;; - -dgux*) + *-dgux*) vendor=dg ;; - -luna*) + *-luna*) vendor=omron ;; - -genix*) + *-genix*) vendor=ns ;; - -mvs* | -opened*) + *-clix*) + vendor=intergraph + ;; + *-mvs* | *-opened*) + vendor=ibm + ;; + *-os400*) vendor=ibm ;; - -os400*) + s390-* | s390x-*) vendor=ibm ;; - -ptx*) + *-ptx*) vendor=sequent ;; - -tpf*) + *-tpf*) vendor=ibm ;; - -vxsim* | -vxworks* | -windiss*) + *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; - -aux*) + *-aux*) vendor=apple ;; - -hms*) + *-hms*) vendor=hitachi ;; - -mpw* | -macos*) + *-mpw* | *-macos*) vendor=apple ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; - -vos*) + *-vos*) vendor=stratus ;; esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac -echo $basic_machine$os +echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" diff --git a/autotools/depcomp b/autotools/depcomp index fc98710e2..715e34311 100755 --- a/autotools/depcomp +++ b/autotools/depcomp @@ -1,9 +1,9 @@ #! /bin/sh # depcomp - compile a program generating dependencies as side-effects -scriptversion=2013-05-30.07; # UTC +scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# Copyright (C) 1999-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,7 +16,7 @@ scriptversion=2013-05-30.07; # UTC # GNU General Public License for more details. # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -783,9 +783,9 @@ exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" +# time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: diff --git a/autotools/install-sh b/autotools/install-sh index 0b0fdcbba..ec298b537 100755 --- a/autotools/install-sh +++ b/autotools/install-sh @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2013-12-25.23; # UTC +scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -69,6 +69,11 @@ posix_mkdir= # Desired mode of installed file. mode=0755 +# Create dirs (including intermediate dirs) using mode 755. +# This is like GNU 'install' as of coreutils 8.32 (2020). +mkdir_umask=22 + +backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= @@ -99,18 +104,28 @@ Options: --version display version info and exit. -c (ignored) - -C install only if different (preserve the last data modification time) + -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. + -p pass -p to $cpprog. -s $stripprog installed files. + -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG + +By default, rm is invoked with -f; when overridden with RMPROG, +it's up to you to specify -f if you want it. + +If -S is not specified, no backups are attempted. + +Email bug reports to bug-automake@gnu.org. +Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do @@ -137,8 +152,13 @@ while test $# -ne 0; do -o) chowncmd="$chownprog $2" shift;; + -p) cpprog="$cpprog -p";; + -s) stripcmd=$stripprog;; + -S) backupsuffix="$2" + shift;; + -t) is_target_a_directory=always dst_arg=$2 @@ -255,6 +275,10 @@ do dstdir=$dst test -d "$dstdir" dstdir_status=$? + # Don't chown directories that already exist. + if test $dstdir_status = 0; then + chowncmd="" + fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command @@ -271,15 +295,18 @@ do fi dst=$dst_arg - # If destination is a directory, append the input filename; won't work - # if double slashes aren't ignored. + # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst - dst=$dstdir/`basename "$src"` + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac dstdir_status=0 else dstdir=`dirname "$dst"` @@ -288,27 +315,16 @@ do fi fi + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then @@ -318,43 +334,49 @@ do fi posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 - - if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/d" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null - fi - trap '' 0;; - esac;; + # The $RANDOM variable is not portable (e.g., dash). Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap ' + ret=$? + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null + exit $ret + ' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p'. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; esac if @@ -365,7 +387,7 @@ do then : else - # The umask is ridiculous, or mkdir does not conform to POSIX, + # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. @@ -394,7 +416,7 @@ do prefixes= else if $posix_mkdir; then - (umask=$mkdir_umask && + (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 @@ -427,14 +449,25 @@ do else # Make a couple of temp file names in the proper directory. - dsttmp=$dstdir/_inst.$$_ - rmtmp=$dstdir/_rm.$$_ + dsttmp=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. - (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + (umask $cp_umask && + { test -z "$stripcmd" || { + # Create $dsttmp read-write so that cp doesn't create it read-only, + # which would cause strip to fail. + if test -z "$doit"; then + : >"$dsttmp" # No need to fork-exec 'touch'. + else + $doit touch "$dsttmp" + fi + } + } && + $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # @@ -460,6 +493,13 @@ do then rm -f "$dsttmp" else + # If $backupsuffix is set, and the file being installed + # already exists, attempt a backup. Don't worry if it fails, + # e.g., if mv doesn't support -f. + if test -n "$backupsuffix" && test -f "$dst"; then + $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null + fi + # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || @@ -474,9 +514,9 @@ do # file should still install successfully. { test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || + $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 @@ -493,9 +533,9 @@ do done # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" +# time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: diff --git a/autotools/missing b/autotools/missing index f62bbae30..1fe1611f1 100755 --- a/autotools/missing +++ b/autotools/missing @@ -1,9 +1,9 @@ #! /bin/sh # Common wrapper for a few potentially missing GNU programs. -scriptversion=2013-10-28.13; # UTC +scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify @@ -17,7 +17,7 @@ scriptversion=2013-10-28.13; # UTC # GNU General Public License for more details. # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -101,9 +101,9 @@ else exit $st fi -perl_URL=http://www.perl.org/ -flex_URL=http://flex.sourceforge.net/ -gnu_software_URL=http://www.gnu.org/software +perl_URL=https://www.perl.org/ +flex_URL=https://github.com/westes/flex +gnu_software_URL=https://www.gnu.org/software program_details () { @@ -207,9 +207,9 @@ give_advice "$1" | sed -e '1s/^/WARNING: /' \ exit $st # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" +# time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: diff --git a/autotools/test-driver b/autotools/test-driver index 8e575b017..be73b80ad 100755 --- a/autotools/test-driver +++ b/autotools/test-driver @@ -1,9 +1,9 @@ #! /bin/sh # test-driver - basic testsuite driver script. -scriptversion=2013-07-13.22; # UTC +scriptversion=2018-03-07.03; # UTC -# Copyright (C) 2011-2014 Free Software Foundation, Inc. +# Copyright (C) 2011-2021 Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,7 +16,7 @@ scriptversion=2013-07-13.22; # UTC # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -42,11 +42,13 @@ print_usage () { cat <$log_file 2>&1 +# Test script is run here. We create the file first, then append to it, +# to ameliorate tests themselves also writing to the log file. Our tests +# don't, but others can (automake bug#35762). +: >"$log_file" +"$@" >>"$log_file" 2>&1 estatus=$? if test $enable_hard_errors = no && test $estatus -eq 99; then @@ -126,7 +131,7 @@ esac # know whether the test passed or failed simply by looking at the '.log' # file, without the need of also peaking into the corresponding '.trs' # file (automake bug#11814). -echo "$res $test_name (exit status: $estatus)" >>$log_file +echo "$res $test_name (exit status: $estatus)" >>"$log_file" # Report outcome to console. echo "${col}${res}${std}: $test_name" @@ -140,9 +145,9 @@ echo ":copy-in-global-log: $gcopy" >> $trs_file # Local Variables: # mode: shell-script # sh-indentation: 2 -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" +# time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: diff --git a/configure b/configure index 64fea8151..37f3ac3ef 100755 --- a/configure +++ b/configure @@ -1,11 +1,12 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for breakpad 0.1. +# Generated by GNU Autoconf 2.71 for breakpad 0.1. # # Report bugs to . # # -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Inc. # # # This configure script is free software; the Free Software Foundation @@ -16,14 +17,16 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -33,46 +36,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -81,13 +84,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -96,8 +92,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -109,30 +109,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. @@ -154,20 +134,22 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else +else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( @@ -187,42 +169,52 @@ as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : -else +else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + if (eval "$as_required") 2>/dev/null +then : as_have_required=yes -else +else $as_nop as_have_required=no fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : -else +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base + as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : break 2 fi fi @@ -230,14 +222,21 @@ fi esac as_found=false done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi +fi - if test "x$CONFIG_SHELL" != x; then : + if test "x$CONFIG_SHELL" != x +then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also @@ -255,18 +254,19 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else - $as_echo "$0: Please tell bug-autoconf@gnu.org and + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and $0: google-breakpad-dev@googlegroups.com about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run @@ -294,6 +294,7 @@ as_fn_unset () } as_unset=as_fn_unset + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -311,6 +312,14 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -325,7 +334,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -334,7 +343,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -373,12 +382,13 @@ as_fn_executable_p () # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -390,18 +400,27 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -413,9 +432,9 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -442,7 +461,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -486,7 +505,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall @@ -500,6 +519,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits exit } + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -513,6 +536,13 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -588,48 +618,44 @@ PACKAGE_URL='' ac_unique_file="README.md" # Factoring default headers for most tests. ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include +#include +#ifdef HAVE_STDIO_H +# include #endif -#ifdef STDC_HEADERS +#ifdef HAVE_STDLIB_H # include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif #endif #ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif # include #endif -#ifdef HAVE_STRINGS_H -# include -#endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif" +ac_header_c_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS TESTS_AS_ROOT_FALSE TESTS_AS_ROOT_TRUE -RUST_DEMANGLE_LIBS -RUST_DEMANGLE_CFLAGS +RUSTC_DEMANGLE_LIBS +RUSTC_DEMANGLE_CFLAGS SELFTEST_FALSE SELFTEST_TRUE GTEST_LIBS @@ -649,7 +675,7 @@ ANDROID_HOST_TRUE LINUX_HOST_FALSE LINUX_HOST_TRUE WARN_CXXFLAGS -HAVE_CXX11 +HAVE_CXX20 HAVE_MEMFD_CREATE_FALSE HAVE_MEMFD_CREATE_TRUE HAVE_GETCONTEXT_FALSE @@ -658,8 +684,6 @@ PTHREAD_CFLAGS PTHREAD_LIBS PTHREAD_CC ax_pthread_config -EGREP -GREP RANLIB am__fastdepCXX_FALSE am__fastdepCXX_TRUE @@ -698,6 +722,9 @@ AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V +CSCOPE +ETAGS +CTAGS am__untar am__tar AMTAR @@ -781,7 +808,9 @@ enable_processor enable_tools enable_system_test_libs enable_selftest -with_rust_demangle +with_rustc_demangle +enable_system_rustc_demangle +enable_zstd with_tests_as_root ' ac_precious_vars='build_alias @@ -802,8 +831,8 @@ GMOCK_CFLAGS GMOCK_LIBS GTEST_CFLAGS GTEST_LIBS -RUST_DEMANGLE_CFLAGS -RUST_DEMANGLE_LIBS' +RUSTC_DEMANGLE_CFLAGS +RUSTC_DEMANGLE_LIBS' # Initialize some variables set by options. @@ -872,8 +901,6 @@ do *) ac_optarg=yes ;; esac - # Accept the important Cygnus configure options, so we can diagnose typos. - case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; @@ -914,9 +941,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -940,9 +967,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -1153,9 +1180,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1169,9 +1196,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1215,9 +1242,9 @@ Try \`$0 --help' for more information" *) # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; @@ -1233,7 +1260,7 @@ if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1297,7 +1324,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | +printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -1451,12 +1478,19 @@ Optional Features: the local copies (default is local) --enable-selftest Run extra tests with "make check" (may conflict with optimizations) (default is no) + --enable-system-rustc-demangle + Link against the rustc-demangle library to demangle + Rust language symbols during symbol dumping (default + is no). This assumes that rustc-demangle is + installed in your sysroot, and all headers from it + are available in your standard include path + --enable-zstd Enable decompression of ELF sections with zstd Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-rust-demangle=/path/to/rust-demangle-capi - Link against the rust-demangle library to demangle + --with-rustc-demangle=/path/to/rustc-demangle + Link against the rustc-demangle library to demangle Rust language symbols during symbol dumping (default is no) Pass the path to the crate root. --with-tests-as-root Run the tests as root. Use this on platforms like @@ -1482,10 +1516,10 @@ Some influential environment variables: GTEST_CFLAGS Compiler flags for gtest GTEST_LIBS Linker flags for gtest - RUST_DEMANGLE_CFLAGS - Compiler flags for rust-demangle - RUST_DEMANGLE_LIBS - Linker flags for rust-demangle + RUSTC_DEMANGLE_CFLAGS + Compiler flags for rustc-demangle + RUSTC_DEMANGLE_LIBS + Linker flags for rustc-demangle Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -1506,9 +1540,9 @@ if test "$ac_init_help" = "recursive"; then case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -1536,7 +1570,8 @@ esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. + # Check for configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive @@ -1544,7 +1579,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix echo && $SHELL "$ac_srcdir/configure" --help=recursive else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done @@ -1554,9 +1589,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF breakpad configure 0.1 -generated by GNU Autoconf 2.69 +generated by GNU Autoconf 2.71 -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1573,14 +1608,14 @@ fi ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1588,14 +1623,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err - } && test -s conftest.$ac_objext; then : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1617,7 +1653,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1625,14 +1661,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1648,14 +1685,14 @@ fi ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1663,14 +1700,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err - } && test -s conftest.$ac_objext; then : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1680,62 +1718,20 @@ fi } # ac_fn_cxx_try_compile -# ac_fn_c_try_run LINENO -# ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. -ac_fn_c_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_run - # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext + rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1743,17 +1739,18 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1768,97 +1765,6 @@ fi } # ac_fn_c_try_link -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} -( $as_echo "## --------------------------------------------------- ## -## Report this to google-breakpad-dev@googlegroups.com ## -## --------------------------------------------------- ##" - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_mongrel - # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in @@ -1866,26 +1772,28 @@ fi ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile @@ -1896,11 +1804,12 @@ $as_echo "$ac_res" >&6; } ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. @@ -1908,16 +1817,9 @@ else #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif + which can conflict with char $2 (); below. */ +#include #undef $2 /* Override any GCC internal prototype to avoid an error. @@ -1935,35 +1837,56 @@ choke me #endif int -main () +main (void) { return $2 (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func +ac_configure_args_raw= +for ac_arg +do + case $ac_arg in + *\'*) + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_configure_args_raw " '$ac_arg'" +done + +case $ac_configure_args_raw in + *$as_nl*) + ac_safe_unquote= ;; + *) + ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. + ac_unsafe_a="$ac_unsafe_z#~" + ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" + ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; +esac + cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by breakpad $as_me 0.1, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was - $ $0 $@ + $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log @@ -1996,8 +1919,12 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS @@ -2032,7 +1959,7 @@ do | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; @@ -2067,11 +1994,13 @@ done # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? + # Sanitize IFS. + IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo - $as_echo "## ---------------- ## + printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo @@ -2082,8 +2011,8 @@ trap 'exit_status=$? case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -2107,7 +2036,7 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ) echo - $as_echo "## ----------------- ## + printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo @@ -2115,14 +2044,14 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## + printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo @@ -2130,15 +2059,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then - $as_echo "## ----------- ## + printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo @@ -2146,8 +2075,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; echo fi test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && @@ -2161,63 +2090,48 @@ ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h -$as_echo "/* confdefs.h */" > confdefs.h +printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac + ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" + +for ac_site_file in $ac_site_files do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi @@ -2227,138 +2141,746 @@ if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## +# Test code for whether the C compiler supports C89 (global declarations) +ac_c_conftest_c89_globals=' +/* Does the compiler advertise C89 conformance? + Do not test the value of __STDC__, because some compilers set it to 0 + while being otherwise adequately conformant. */ +#if !defined __STDC__ +# error "Compiler does not advertise C89 conformance" +#endif -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ +struct buf { int x; }; +struct buf * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not \xHH hex character constants. + These do not provoke an error unfortunately, instead are silently treated + as an "x". The following induces an error, until -std is added to get + proper ANSI mode. Curiously \x00 != x always comes out true, for an + array size at least. It is necessary to write \x00 == 0 to get something + that is true only with -std. */ +int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) '\''x'\'' +int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; -ac_aux_dir= -for ac_dir in autotools "$srcdir"/autotools; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in autotools \"$srcdir\"/autotools" "$LINENO" 5 -fi +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), + int, int);' -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. +# Test code for whether the C compiler supports C89 (body of main). +ac_c_conftest_c89_main=' +ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); +' +# Test code for whether the C compiler supports C99 (global declarations) +ac_c_conftest_c99_globals=' +// Does the compiler advertise C99 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# error "Compiler does not advertise C99 conformance" +#endif +#include +extern int puts (const char *); +extern int printf (const char *, ...); +extern int dprintf (int, const char *, ...); +extern void *malloc (size_t); + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +// dprintf is used instead of fprintf to avoid needing to declare +// FILE and stderr. +#define debug(...) dprintf (2, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} -# Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + #error "your preprocessor is broken" +#endif +#if BIG_OK +#else + #error "your preprocessor is broken" +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static bool +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str = ""; + int number = 0; + float fnumber = 0; + + while (*format) + { + switch (*format++) + { + case '\''s'\'': // string + str = va_arg (args_copy, const char *); + break; + case '\''d'\'': // int + number = va_arg (args_copy, int); + break; + case '\''f'\'': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); + + return *str && number && fnumber; +} +' + +# Test code for whether the C compiler supports C99 (body of main). +ac_c_conftest_c99_main=' + // Check bool. + _Bool success = false; + success |= (argc != 0); + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[0] = argv[0][0]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' + || dynamic_array[ni.number - 1] != 543); +' + +# Test code for whether the C compiler supports C11 (global declarations) +ac_c_conftest_c11_globals=' +// Does the compiler advertise C11 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L +# error "Compiler does not advertise C11 conformance" +#endif + +// Check _Alignas. +char _Alignas (double) aligned_as_double; +char _Alignas (0) no_special_alignment; +extern char aligned_as_int; +char _Alignas (0) _Alignas (int) aligned_as_int; + +// Check _Alignof. +enum +{ + int_alignment = _Alignof (int), + int_array_alignment = _Alignof (int[100]), + char_alignment = _Alignof (char) +}; +_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); + +// Check _Noreturn. +int _Noreturn does_not_return (void) { for (;;) continue; } + +// Check _Static_assert. +struct test_static_assert +{ + int x; + _Static_assert (sizeof (int) <= sizeof (long int), + "_Static_assert does not work in struct"); + long int y; +}; + +// Check UTF-8 literals. +#define u8 syntax error! +char const utf8_literal[] = u8"happens to be ASCII" "another string"; + +// Check duplicate typedefs. +typedef long *long_ptr; +typedef long int *long_ptr; +typedef long_ptr long_ptr; + +// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. +struct anonymous +{ + union { + struct { int i; int j; }; + struct { int k; long int l; } w; + }; + int m; +} v1; +' + +# Test code for whether the C compiler supports C11 (body of main). +ac_c_conftest_c11_main=' + _Static_assert ((offsetof (struct anonymous, i) + == offsetof (struct anonymous, w.k)), + "Anonymous union alignment botch"); + v1.i = 2; + v1.w.k = 5; + ok |= v1.i != 5; +' + +# Test code for whether the C compiler supports C11 (complete). +ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} +${ac_c_conftest_c11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + ${ac_c_conftest_c11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C99 (complete). +ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + return ok; +} +" + +# Test code for whether the C compiler supports C89 (complete). +ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + return ok; +} +" + +# Test code for whether the C++ compiler supports C++98 (global declarations) +ac_cxx_conftest_cxx98_globals=' +// Does the compiler advertise C++98 conformance? +#if !defined __cplusplus || __cplusplus < 199711L +# error "Compiler does not advertise C++98 conformance" +#endif + +// These inclusions are to reject old compilers that +// lack the unsuffixed header files. +#include +#include + +// and are *not* freestanding headers in C++98. +extern void assert (int); +namespace std { + extern int strcmp (const char *, const char *); +} + +// Namespaces, exceptions, and templates were all added after "C++ 2.0". +using std::exception; +using std::strcmp; + +namespace { + +void test_exception_syntax() +{ + try { + throw "test"; + } catch (const char *s) { + // Extra parentheses suppress a warning when building autoconf itself, + // due to lint rules shared with more typical C programs. + assert (!(strcmp) (s, "test")); + } +} + +template struct test_template +{ + T const val; + explicit test_template(T t) : val(t) {} + template T add(U u) { return static_cast(u) + val; } +}; + +} // anonymous namespace +' + +# Test code for whether the C++ compiler supports C++98 (body of main) +ac_cxx_conftest_cxx98_main=' + assert (argc); + assert (! argv[0]); +{ + test_exception_syntax (); + test_template tt (2.0); + assert (tt.add (4) == 6.0); + assert (true && !false); +} +' + +# Test code for whether the C++ compiler supports C++11 (global declarations) +ac_cxx_conftest_cxx11_globals=' +// Does the compiler advertise C++ 2011 conformance? +#if !defined __cplusplus || __cplusplus < 201103L +# error "Compiler does not advertise C++11 conformance" +#endif + +namespace cxx11test +{ + constexpr int get_val() { return 20; } + + struct testinit + { + int i; + double d; + }; + + class delegate + { + public: + delegate(int n) : n(n) {} + delegate(): delegate(2354) {} + + virtual int getval() { return this->n; }; + protected: + int n; + }; + + class overridden : public delegate + { + public: + overridden(int n): delegate(n) {} + virtual int getval() override final { return this->n * 2; } + }; + + class nocopy + { + public: + nocopy(int i): i(i) {} + nocopy() = default; + nocopy(const nocopy&) = delete; + nocopy & operator=(const nocopy&) = delete; + private: + int i; + }; + + // for testing lambda expressions + template Ret eval(Fn f, Ret v) + { + return f(v); + } + + // for testing variadic templates and trailing return types + template auto sum(V first) -> V + { + return first; + } + template auto sum(V first, Args... rest) -> V + { + return first + sum(rest...); + } +} +' + +# Test code for whether the C++ compiler supports C++11 (body of main) +ac_cxx_conftest_cxx11_main=' +{ + // Test auto and decltype + auto a1 = 6538; + auto a2 = 48573953.4; + auto a3 = "String literal"; + + int total = 0; + for (auto i = a3; *i; ++i) { total += *i; } + + decltype(a2) a4 = 34895.034; +} +{ + // Test constexpr + short sa[cxx11test::get_val()] = { 0 }; +} +{ + // Test initializer lists + cxx11test::testinit il = { 4323, 435234.23544 }; +} +{ + // Test range-based for + int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, + 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; + for (auto &x : array) { x += 23; } +} +{ + // Test lambda expressions + using cxx11test::eval; + assert (eval ([](int x) { return x*2; }, 21) == 42); + double d = 2.0; + assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); + assert (d == 5.0); + assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); + assert (d == 5.0); +} +{ + // Test use of variadic templates + using cxx11test::sum; + auto a = sum(1); + auto b = sum(1, 2); + auto c = sum(1.0, 2.0, 3.0); +} +{ + // Test constructor delegation + cxx11test::delegate d1; + cxx11test::delegate d2(); + cxx11test::delegate d3(45); +} +{ + // Test override and final + cxx11test::overridden o1(55464); +} +{ + // Test nullptr + char *c = nullptr; +} +{ + // Test template brackets + test_template<::test_template> v(test_template(12)); +} +{ + // Unicode literals + char const *utf8 = u8"UTF-8 string \u2500"; + char16_t const *utf16 = u"UTF-8 string \u2500"; + char32_t const *utf32 = U"UTF-32 string \u2500"; +} +' + +# Test code for whether the C compiler supports C++11 (complete). +ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} +${ac_cxx_conftest_cxx11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_cxx_conftest_cxx98_main} + ${ac_cxx_conftest_cxx11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C++98 (complete). +ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_cxx_conftest_cxx98_main} + return ok; +} +" + +as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" +as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" +as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" +as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" +as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" +as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" +as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" +as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" +as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" + +# Auxiliary files required by this configure script. +ac_aux_files="compile ar-lib missing install-sh config.guess config.sub" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="${srcdir}/autotools" + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" + break + fi + ac_first_candidate=false + + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 +fi + + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + # Make sure we can run config.sub. +$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 +ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; @@ -2377,21 +2899,22 @@ IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; @@ -2413,7 +2936,8 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac am__api_version='1.16' -# Find a good install program. We prefer a C program (faster), + + # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install @@ -2427,20 +2951,25 @@ am__api_version='1.16' # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -$as_echo_n "checking for a BSD-compatible install... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test ${ac_cv_path_install+y} +then : + printf %s "(cached) " >&6 +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in #(( - ./ | .// | /[cC]/* | \ + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + # Account for fact that we put trailing slashes in our PATH walk. +case $as_dir in #(( + ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; @@ -2450,13 +2979,13 @@ case $as_dir/ in #(( # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && - grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && - grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else @@ -2464,12 +2993,12 @@ case $as_dir/ in #(( echo one > conftest.one echo two > conftest.two mkdir conftest.dir - if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi @@ -2485,7 +3014,7 @@ IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi - if test "${ac_cv_path_install+set}" = set; then + if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a @@ -2495,8 +3024,8 @@ fi INSTALL=$ac_install_sh fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -$as_echo "$INSTALL" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. @@ -2506,8 +3035,8 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 -$as_echo_n "checking whether build environment is sane... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +printf %s "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' @@ -2561,8 +3090,8 @@ else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= @@ -2581,26 +3110,23 @@ test "$program_suffix" != NONE && # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' -program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` +program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` + # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` -if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac + + if test x"${MISSING+set}" != xset; then + MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 -$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then @@ -2620,11 +3146,12 @@ if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_STRIP+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else @@ -2632,11 +3159,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2647,11 +3178,11 @@ fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -$as_echo "$STRIP" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +printf "%s\n" "$STRIP" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2660,11 +3191,12 @@ if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_STRIP+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else @@ -2672,11 +3204,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2687,11 +3223,11 @@ fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -$as_echo "$ac_ct_STRIP" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +printf "%s\n" "$ac_ct_STRIP" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then @@ -2699,8 +3235,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP @@ -2712,25 +3248,31 @@ fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 -$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 +printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then - if ${ac_cv_path_mkdir+:} false; then : - $as_echo_n "(cached) " >&6 -else + if test ${ac_cv_path_mkdir+y} +then : + printf %s "(cached) " >&6 +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue - case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir (GNU coreutils) '* | \ - 'mkdir (coreutils) '* | \ + as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue + case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir ('*'coreutils) '* | \ + 'BusyBox '* | \ 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; esac done @@ -2741,7 +3283,7 @@ IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version - if test "${ac_cv_path_mkdir+set}" = set; then + if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a @@ -2751,18 +3293,19 @@ fi MKDIR_P="$ac_install_sh -d" fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -$as_echo "$MKDIR_P" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +printf "%s\n" "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AWK+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_AWK+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else @@ -2770,11 +3313,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2785,24 +3332,25 @@ fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -$as_echo "$AWK" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +printf "%s\n" "$AWK" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} -ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : - $as_echo_n "(cached) " >&6 -else +ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval test \${ac_cv_prog_make_${ac_make}_set+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @@ -2818,12 +3366,12 @@ esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } SET_MAKE= else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi @@ -2837,7 +3385,8 @@ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. -if test "${enable_silent_rules+set}" = set; then : +if test ${enable_silent_rules+y} +then : enableval=$enable_silent_rules; fi @@ -2847,12 +3396,13 @@ case $enable_silent_rules in # ((( *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 -$as_echo_n "checking whether $am_make supports nested variables... " >&6; } -if ${am_cv_make_support_nested_variables+:} false; then : - $as_echo_n "(cached) " >&6 -else - if $as_echo 'TRUE=$(BAR$(V)) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +printf %s "checking whether $am_make supports nested variables... " >&6; } +if test ${am_cv_make_support_nested_variables+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if printf "%s\n" 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 @@ -2864,8 +3414,8 @@ else am_cv_make_support_nested_variables=no fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -$as_echo "$am_cv_make_support_nested_variables" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' @@ -2900,14 +3450,10 @@ fi VERSION='0.1' -cat >>confdefs.h <<_ACEOF -#define PACKAGE "$PACKAGE" -_ACEOF +printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define VERSION "$VERSION" -_ACEOF +printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h # Some tools Automake needs. @@ -2953,29 +3499,29 @@ _am_tools='gnutar plaintar pax cpio none' # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 -$as_echo_n "checking whether UID '$am_uid' is supported by ustar format... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 +printf %s "checking whether UID '$am_uid' is supported by ustar format... " >&6; } if test $am_uid -le $am_max_uid; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } _am_tools=none fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 -$as_echo_n "checking whether GID '$am_gid' is supported by ustar format... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 +printf %s "checking whether GID '$am_gid' is supported by ustar format... " >&6; } if test $am_gid -le $am_max_gid; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } _am_tools=none fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5 -$as_echo_n "checking how to create a ustar tar archive... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5 +printf %s "checking how to create a ustar tar archive... " >&6; } # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. @@ -3050,17 +3596,32 @@ $as_echo_n "checking how to create a ustar tar archive... " >&6; } done rm -rf conftest.dir - if ${am_cv_prog_tar_ustar+:} false; then : - $as_echo_n "(cached) " >&6 -else + if test ${am_cv_prog_tar_ustar+y} +then : + printf %s "(cached) " >&6 +else $as_nop am_cv_prog_tar_ustar=$_am_tool fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 -$as_echo "$am_cv_prog_tar_ustar" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 +printf "%s\n" "$am_cv_prog_tar_ustar" >&6; } + + + +# Variables for tags utilities; see am/tags.am +if test -z "$CTAGS"; then + CTAGS=ctags +fi + +if test -z "$ETAGS"; then + ETAGS=etags +fi +if test -z "$CSCOPE"; then + CSCOPE=cscope +fi @@ -3109,17 +3670,18 @@ fi ac_config_headers="$ac_config_headers src/config.h" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 -$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +printf %s "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } # Check whether --enable-maintainer-mode was given. -if test "${enable_maintainer_mode+set}" = set; then : +if test ${enable_maintainer_mode+y} +then : enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval -else +else $as_nop USE_MAINTAINER_MODE=no fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 -$as_echo "$USE_MAINTAINER_MODE" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +printf "%s\n" "$USE_MAINTAINER_MODE" >&6; } if test $USE_MAINTAINER_MODE = yes; then MAINTAINER_MODE_TRUE= MAINTAINER_MODE_FALSE='#' @@ -3132,13 +3694,22 @@ fi -DEPDIR="${am__leading_dot}deps" -ac_config_commands="$ac_config_commands depfiles" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 -$as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; } -cat > confinc.mk << 'END' + + + + + + + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 +printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } +cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit @@ -3173,11 +3744,12 @@ esac fi done rm -f confinc.* confmf.* -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 -$as_echo "${_am_result}" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 +printf "%s\n" "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. -if test "${enable_dependency_tracking+set}" = set; then : +if test ${enable_dependency_tracking+y} +then : enableval=$enable_dependency_tracking; fi @@ -3203,11 +3775,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -3215,11 +3788,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3230,11 +3807,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3243,11 +3820,12 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -3255,11 +3833,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3270,11 +3852,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -3282,8 +3864,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -3296,11 +3878,12 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -3308,11 +3891,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3323,11 +3910,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3336,11 +3923,12 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -3349,15 +3937,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3373,18 +3965,18 @@ if test $ac_prog_rejected = yes; then # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3395,11 +3987,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -3407,11 +4000,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3422,11 +4019,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3439,11 +4036,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -3451,11 +4049,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3466,11 +4068,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3482,34 +4084,138 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi +else + CC="$ac_cv_prog_CC" fi fi -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 -for ac_option in --version -v -V -qversion; do +for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -3519,7 +4225,7 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done @@ -3527,7 +4233,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3539,9 +4245,9 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +printf %s "checking whether the C compiler works... " >&6; } +ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" @@ -3562,11 +4268,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, @@ -3583,7 +4290,7 @@ do # certainly right. break;; *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi @@ -3599,44 +4306,46 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else +else $as_nop ac_file='' fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 +if test -z "$ac_file" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +printf %s "checking for C compiler default output file name... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with @@ -3650,15 +4359,15 @@ for ac_file in conftest.exe conftest conftest.*; do * ) break;; esac done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext @@ -3667,7 +4376,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; @@ -3679,8 +4388,8 @@ _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in @@ -3688,10 +4397,10 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in @@ -3699,39 +4408,40 @@ $as_echo "$ac_try_echo"; } >&5 *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +printf %s "checking for suffix of object files... " >&6; } +if test ${ac_cv_objext+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3745,11 +4455,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in @@ -3758,31 +4469,32 @@ $as_echo "$ac_try_echo"; } >&5 break;; esac done -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3792,29 +4504,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi -ac_test_CFLAGS=${CFLAGS+set} +ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no @@ -3823,57 +4539,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes -else +else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then @@ -3888,94 +4607,144 @@ else CFLAGS= fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program _ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : + if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_c89=$ac_arg fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC - fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi fi ac_ext=c @@ -3984,21 +4753,23 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -ac_ext=c + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 -$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } -if ${am_cv_prog_cc_c_o+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +printf %s "checking whether $CC understands -c and -o together... " >&6; } +if test ${am_cv_prog_cc_c_o+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -4026,8 +4797,8 @@ _ACEOF rm -f core conftest* unset am_i fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -$as_echo "$am_cv_prog_cc_c_o" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. @@ -4045,11 +4816,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -$as_echo_n "checking dependency style of $depcc... " >&6; } -if ${am_cv_CC_dependencies_compiler_type+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +printf %s "checking dependency style of $depcc... " >&6; } +if test ${am_cv_CC_dependencies_compiler_type+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For @@ -4156,8 +4928,8 @@ else fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 -$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if @@ -4172,16 +4944,18 @@ fi -if test -n "$ac_tool_prefix"; then + + if test -n "$ac_tool_prefix"; then for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else @@ -4189,11 +4963,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4204,11 +4982,11 @@ fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -$as_echo "$AR" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +printf "%s\n" "$AR" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4221,11 +4999,12 @@ if test -z "$AR"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_AR+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else @@ -4233,11 +5012,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4248,11 +5031,11 @@ fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -$as_echo "$ac_ct_AR" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +printf "%s\n" "$ac_ct_AR" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4264,8 +5047,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR @@ -4274,11 +5057,12 @@ fi : ${AR=ar} -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 -$as_echo_n "checking the archiver ($AR) interface... " >&6; } -if ${am_cv_ar_interface+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 +printf %s "checking the archiver ($AR) interface... " >&6; } +if test ${am_cv_ar_interface+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -4290,12 +5074,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu /* end confdefs.h. */ int some_variable = 0; _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=ar @@ -4304,7 +5089,7 @@ if ac_fn_c_try_compile "$LINENO"; then : { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=lib @@ -4315,7 +5100,7 @@ if ac_fn_c_try_compile "$LINENO"; then : rm -f conftest.lib libconftest.a fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -4323,8 +5108,8 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 -$as_echo "$am_cv_ar_interface" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 +printf "%s\n" "$am_cv_ar_interface" >&6; } case $am_cv_ar_interface in ar) @@ -4352,11 +5137,12 @@ test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS depcc="$CCAS" am_compiler_list= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -$as_echo_n "checking dependency style of $depcc... " >&6; } -if ${am_cv_CCAS_dependencies_compiler_type+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +printf %s "checking dependency style of $depcc... " >&6; } +if test ${am_cv_CCAS_dependencies_compiler_type+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For @@ -4461,8 +5247,8 @@ else fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CCAS_dependencies_compiler_type" >&5 -$as_echo "$am_cv_CCAS_dependencies_compiler_type" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CCAS_dependencies_compiler_type" >&5 +printf "%s\n" "$am_cv_CCAS_dependencies_compiler_type" >&6; } CCASDEPMODE=depmode=$am_cv_CCAS_dependencies_compiler_type if @@ -4484,11 +5270,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -4496,11 +5283,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4511,11 +5302,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4524,11 +5315,12 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -4536,11 +5328,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4551,11 +5347,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -4563,8 +5359,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -4577,11 +5373,12 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -4589,11 +5386,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4604,11 +5405,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4617,11 +5418,12 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -4630,15 +5432,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4654,18 +5460,18 @@ if test $ac_prog_rejected = yes; then # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4676,11 +5482,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -4688,11 +5495,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4703,11 +5514,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4720,11 +5531,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -4732,11 +5544,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4747,11 +5563,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4763,34 +5579,138 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + fi -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 -for ac_option in --version -v -V -qversion; do +for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -4800,20 +5720,21 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -4823,29 +5744,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi -ac_test_CFLAGS=${CFLAGS+set} +ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no @@ -4854,57 +5779,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes -else +else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then @@ -4919,94 +5847,144 @@ else CFLAGS= fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program _ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : + if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_c89=$ac_arg fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC - fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi fi ac_ext=c @@ -5015,21 +5993,23 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -ac_ext=c + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 -$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } -if ${am_cv_prog_cc_c_o+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +printf %s "checking whether $CC understands -c and -o together... " >&6; } +if test ${am_cv_prog_cc_c_o+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -5057,8 +6037,8 @@ _ACEOF rm -f core conftest* unset am_i fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -$as_echo "$am_cv_prog_cc_c_o" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. @@ -5076,11 +6056,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -$as_echo_n "checking dependency style of $depcc... " >&6; } -if ${am_cv_CC_dependencies_compiler_type+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +printf %s "checking dependency style of $depcc... " >&6; } +if test ${am_cv_CC_dependencies_compiler_type+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For @@ -5187,8 +6168,8 @@ else fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 -$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if @@ -5208,40 +6189,36 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + if test ${ac_cv_prog_CPP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + # Double quotes because $CC needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif +#include Syntax error _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : -else +else $as_nop # Broken: fails on valid input. continue fi @@ -5253,10 +6230,11 @@ rm -f conftest.err conftest.i conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : # Broken: success on invalid input. continue -else +else $as_nop # Passes both tests. ac_preproc_ok=: break @@ -5266,7 +6244,8 @@ rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : +if $ac_preproc_ok +then : break fi @@ -5278,29 +6257,24 @@ fi else ac_cv_prog_CPP=$CPP fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif +#include Syntax error _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : -else +else $as_nop # Broken: fails on valid input. continue fi @@ -5312,10 +6286,11 @@ rm -f conftest.err conftest.i conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : # Broken: success on invalid input. continue -else +else $as_nop # Passes both tests. ac_preproc_ok=: break @@ -5325,11 +6300,12 @@ rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : +if $ac_preproc_ok +then : -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi @@ -5340,6 +6316,12 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -5350,15 +6332,16 @@ if test -z "$CXX"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else @@ -5366,11 +6349,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5381,11 +6368,11 @@ fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +printf "%s\n" "$CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5394,15 +6381,16 @@ fi fi if test -z "$CXX"; then ac_ct_CXX=$CXX - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else @@ -5410,11 +6398,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5425,11 +6417,11 @@ fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -$as_echo "$ac_ct_CXX" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +printf "%s\n" "$ac_ct_CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5441,8 +6433,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX @@ -5452,7 +6444,7 @@ fi fi fi # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do @@ -5462,7 +6454,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -5472,20 +6464,21 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 -$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } -if ${ac_cv_cxx_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 +printf %s "checking whether the compiler supports GNU C++... " >&6; } +if test ${ac_cv_cxx_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -5495,29 +6488,33 @@ main () return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 -$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi -ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_test_CXXFLAGS=${CXXFLAGS+y} ac_save_CXXFLAGS=$CXXFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 -$as_echo_n "checking whether $CXX accepts -g... " >&6; } -if ${ac_cv_prog_cxx_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +printf %s "checking whether $CXX accepts -g... " >&6; } +if test ${ac_cv_prog_cxx_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no @@ -5526,57 +6523,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : ac_cv_prog_cxx_g=yes -else +else $as_nop CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : -else +else $as_nop ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : ac_cv_prog_cxx_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 -$as_echo "$ac_cv_prog_cxx_g" >&6; } -if test "$ac_test_CXXFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } +if test $ac_test_CXXFLAGS; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then @@ -5591,6 +6591,100 @@ else CXXFLAGS= fi fi +ac_prog_cxx_stdcxx=no +if test x$ac_prog_cxx_stdcxx = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 +printf %s "checking for $CXX option to enable C++11 features... " >&6; } +if test ${ac_cv_prog_cxx_cxx11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cxx_cxx11=no +ac_save_CXX=$CXX +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_cxx_conftest_cxx11_program +_ACEOF +for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA +do + CXX="$ac_save_CXX $ac_arg" + if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_prog_cxx_cxx11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cxx_cxx11" != "xno" && break +done +rm -f conftest.$ac_ext +CXX=$ac_save_CXX +fi + +if test "x$ac_cv_prog_cxx_cxx11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cxx_cxx11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 +printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } + CXX="$CXX $ac_cv_prog_cxx_cxx11" +fi + ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 + ac_prog_cxx_stdcxx=cxx11 +fi +fi +if test x$ac_prog_cxx_stdcxx = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 +printf %s "checking for $CXX option to enable C++98 features... " >&6; } +if test ${ac_cv_prog_cxx_cxx98+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cxx_cxx98=no +ac_save_CXX=$CXX +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_cxx_conftest_cxx98_program +_ACEOF +for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA +do + CXX="$ac_save_CXX $ac_arg" + if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_prog_cxx_cxx98=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cxx_cxx98" != "xno" && break +done +rm -f conftest.$ac_ext +CXX=$ac_save_CXX +fi + +if test "x$ac_cv_prog_cxx_cxx98" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cxx_cxx98" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 +printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } + CXX="$CXX $ac_cv_prog_cxx_cxx98" +fi + ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 + ac_prog_cxx_stdcxx=cxx98 +fi +fi + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -5599,11 +6693,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -$as_echo_n "checking dependency style of $depcc... " >&6; } -if ${am_cv_CXX_dependencies_compiler_type+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +printf %s "checking dependency style of $depcc... " >&6; } +if test ${am_cv_CXX_dependencies_compiler_type+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For @@ -5710,8 +6805,8 @@ else fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 -$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +printf "%s\n" "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if @@ -5728,11 +6823,12 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_RANLIB+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else @@ -5740,11 +6836,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5755,11 +6855,11 @@ fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -$as_echo "$RANLIB" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +printf "%s\n" "$RANLIB" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5768,11 +6868,12 @@ if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_RANLIB+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else @@ -5780,11 +6881,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5795,11 +6900,11 @@ fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -$as_echo "$ac_ct_RANLIB" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +printf "%s\n" "$ac_ct_RANLIB" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then @@ -5807,8 +6912,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB @@ -5819,280 +6924,32 @@ fi # Check whether --enable-m32 was given. -if test "${enable_m32+set}" = set; then : - enableval=$enable_m32; case "${enableval}" in - yes) - CFLAGS="${CFLAGS} -m32" - CXXFLAGS="${CXXFLAGS} -m32" - usem32=true - ;; - no) - usem32=false - ;; - *) - as_fn_error $? "bad value ${enableval} for --enable-m32" "$LINENO" 5 - ;; - esac -else - usem32=false -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - +if test ${enable_m32+y} +then : + enableval=$enable_m32; +else $as_nop + enable_m32=no fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h +if test "x$enable_m32" = xyes; then + CFLAGS="${CFLAGS} -m32" + CXXFLAGS="${CXXFLAGS} -m32" fi # Check whether --enable-largefile was given. -if test "${enable_largefile+set}" = set; then : +if test ${enable_largefile+y} +then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 -$as_echo_n "checking for special C compiler options needed for large files... " >&6; } -if ${ac_cv_sys_largefile_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +printf %s "checking for special C compiler options needed for large files... " >&6; } +if test ${ac_cv_sys_largefile_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC @@ -6106,44 +6963,47 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int -main () +main (void) { ; return 0; } _ACEOF - if ac_fn_c_try_compile "$LINENO"; then : + if ac_fn_c_try_compile "$LINENO" +then : break fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam CC="$CC -n32" - if ac_fn_c_try_compile "$LINENO"; then : + if ac_fn_c_try_compile "$LINENO" +then : ac_cv_sys_largefile_CC=' -n32'; break fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 -$as_echo "$ac_cv_sys_largefile_CC" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +printf "%s\n" "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 -$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } -if ${ac_cv_sys_file_offset_bits+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +printf %s "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if test ${ac_cv_sys_file_offset_bits+y} +then : + printf %s "(cached) " >&6 +else $as_nop while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6152,22 +7012,23 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_sys_file_offset_bits=no; break fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 @@ -6176,43 +7037,43 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_sys_file_offset_bits=64; break fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 -$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +printf "%s\n" "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) -cat >>confdefs.h <<_ACEOF -#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits -_ACEOF +printf "%s\n" "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 -$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } -if ${ac_cv_sys_large_files+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +printf %s "checking for _LARGE_FILES value needed for large files... " >&6; } +if test ${ac_cv_sys_large_files+y} +then : + printf %s "(cached) " >&6 +else $as_nop while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6221,22 +7082,23 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_sys_large_files=no; break fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 @@ -6245,40 +7107,37 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_sys_large_files=1; break fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 -$as_echo "$ac_cv_sys_large_files" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +printf "%s\n" "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) -cat >>confdefs.h <<_ACEOF -#define _LARGE_FILES $ac_cv_sys_large_files -_ACEOF +printf "%s\n" "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h ;; esac rm -rf conftest* fi - - fi @@ -6304,33 +7163,31 @@ if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5 -$as_echo_n "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5 +printf %s "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char pthread_join (); int -main () +main (void) { return pthread_join (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ax_pthread_ok=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 -$as_echo "$ax_pthread_ok" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 +printf "%s\n" "$ax_pthread_ok" >&6; } if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" @@ -6395,24 +7252,25 @@ for flag in $ax_pthread_flags; do case $flag in none) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 -$as_echo_n "checking whether pthreads work without any flags... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 +printf %s "checking whether pthreads work without any flags... " >&6; } ;; -*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5 -$as_echo_n "checking whether pthreads work with $flag... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5 +printf %s "checking whether pthreads work with $flag... " >&6; } PTHREAD_CFLAGS="$flag" ;; pthread-config) # Extract the first word of "pthread-config", so it can be a program name with args. set dummy pthread-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ax_pthread_config+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ax_pthread_config+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ax_pthread_config"; then ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test. else @@ -6420,11 +7278,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ax_pthread_config="yes" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6436,11 +7298,11 @@ fi fi ax_pthread_config=$ac_cv_prog_ax_pthread_config if test -n "$ax_pthread_config"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5 -$as_echo "$ax_pthread_config" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5 +printf "%s\n" "$ax_pthread_config" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -6450,8 +7312,8 @@ fi ;; *) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5 -$as_echo_n "checking for the pthreads library -l$flag... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5 +printf %s "checking for the pthreads library -l$flag... " >&6; } PTHREAD_LIBS="-l$flag" ;; esac @@ -6476,7 +7338,7 @@ $as_echo_n "checking for the pthreads library -l$flag... " >&6; } static void routine(void* a) {a=0;} static void* start_routine(void* a) {return a;} int -main () +main (void) { pthread_t th; pthread_attr_t attr; pthread_join(th, 0); @@ -6488,17 +7350,18 @@ pthread_t th; pthread_attr_t attr; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ax_pthread_ok=yes fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 -$as_echo "$ax_pthread_ok" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 +printf "%s\n" "$ax_pthread_ok" >&6; } if test "x$ax_pthread_ok" = xyes; then break; fi @@ -6516,46 +7379,45 @@ if test "x$ax_pthread_ok" = xyes; then CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 -$as_echo_n "checking for joinable pthread attribute... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 +printf %s "checking for joinable pthread attribute... " >&6; } attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { int attr=$attr; return attr; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : attr_name=$attr; break fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext done - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5 -$as_echo "$attr_name" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5 +printf "%s\n" "$attr_name" >&6; } if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then -cat >>confdefs.h <<_ACEOF -#define PTHREAD_CREATE_JOINABLE $attr_name -_ACEOF +printf "%s\n" "#define PTHREAD_CREATE_JOINABLE $attr_name" >>confdefs.h fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5 -$as_echo_n "checking if more special flags are required for pthreads... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5 +printf %s "checking if more special flags are required for pthreads... " >&6; } flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5 -$as_echo "${flag}" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5 +printf "%s\n" "${flag}" >&6; } if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi @@ -6569,11 +7431,12 @@ $as_echo "${flag}" >&6; } do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_PTHREAD_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_PTHREAD_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$PTHREAD_CC"; then ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test. else @@ -6581,11 +7444,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_PTHREAD_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6596,11 +7463,11 @@ fi fi PTHREAD_CC=$ac_cv_prog_PTHREAD_CC if test -n "$PTHREAD_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5 -$as_echo "$PTHREAD_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5 +printf "%s\n" "$PTHREAD_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -6622,7 +7489,7 @@ fi # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then -$as_echo "#define HAVE_PTHREAD 1" >>confdefs.h +printf "%s\n" "#define HAVE_PTHREAD 1" >>confdefs.h : else @@ -6636,47 +7503,78 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF +ac_header= ac_cache= +for ac_item in $ac_header_c_list +do + if test $ac_cache; then + ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" + if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then + printf "%s\n" "#define $ac_item 1" >> confdefs.h + fi + ac_header= ac_cache= + elif test $ac_header; then + ac_cache=$ac_item + else + ac_header=$ac_item + fi +done + + + -fi -done -for ac_header in a.out.h sys/mman.h sys/random.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF + +if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes +then : + +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "a.out.h" "ac_cv_header_a_out_h" "$ac_includes_default" +if test "x$ac_cv_header_a_out_h" = xyes +then : + printf "%s\n" "#define HAVE_A_OUT_H 1" >>confdefs.h -done +fi +ac_fn_c_check_header_compile "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_mman_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_MMAN_H 1" >>confdefs.h -for ac_func in arc4random getcontext getrandom memfd_create -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +fi +ac_fn_c_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_random_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_RANDOM_H 1" >>confdefs.h + +fi + +ac_fn_c_check_func "$LINENO" "arc4random" "ac_cv_func_arc4random" +if test "x$ac_cv_func_arc4random" = xyes +then : + printf "%s\n" "#define HAVE_ARC4RANDOM 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getcontext" "ac_cv_func_getcontext" +if test "x$ac_cv_func_getcontext" = xyes +then : + printf "%s\n" "#define HAVE_GETCONTEXT 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "getrandom" "ac_cv_func_getrandom" +if test "x$ac_cv_func_getrandom" = xyes +then : + printf "%s\n" "#define HAVE_GETRANDOM 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "memfd_create" "ac_cv_func_memfd_create" +if test "x$ac_cv_func_memfd_create" = xyes +then : + printf "%s\n" "#define HAVE_MEMFD_CREATE 1" >>confdefs.h fi -done if test "x$ac_cv_func_getcontext" = xyes; then HAVE_GETCONTEXT_TRUE= @@ -6696,18 +7594,20 @@ fi - ax_cxx_compile_cxx11_required=true + ax_cxx_compile_alternatives="20" ax_cxx_compile_cxx20_required=true ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_success=no - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5 -$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; } -if ${ax_cv_cxx_compile_cxx11+:} false; then : - $as_echo_n "(cached) " >&6 -else + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++20 features by default" >&5 +printf %s "checking whether $CXX supports C++20 features by default... " >&6; } +if test ${ax_cv_cxx_compile_cxx20+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6719,7 +7619,11 @@ else #error "This is not a C++ compiler" -#elif __cplusplus < 201103L +// MSVC always sets __cplusplus to 199711L in older versions; newer versions +// only set it correctly if /Zc:__cplusplus is specified as well as a +// /std:c++NN switch: +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ +#elif __cplusplus < 201103L && !defined _MSC_VER #error "This is not a C++11 compiler" @@ -6744,11 +7648,13 @@ namespace cxx11 struct Base { + virtual ~Base() {} virtual void f() {} }; struct Derived : public Base { + virtual ~Derived() override {} virtual void f() override {} }; @@ -6996,335 +7902,2252 @@ namespace cxx11 -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ax_cv_cxx_compile_cxx11=yes -else - ax_cv_cxx_compile_cxx11=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5 -$as_echo "$ax_cv_cxx_compile_cxx11" >&6; } - if test x$ax_cv_cxx_compile_cxx11 = xyes; then - ac_success=yes - fi +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. +#ifndef __cplusplus - if test x$ac_success = xno; then - for switch in -std=c++11 -std=c++0x +std=c++11 "-h std=c++11"; do - cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 -$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; } -if eval \${$cachevar+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ +#error "This is not a C++ compiler" +#elif __cplusplus < 201402L && !defined _MSC_VER -// If the compiler admits that it is not ready for C++11, why torture it? +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + + + + +// If the compiler admits that it is not ready for C++17, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" -#elif __cplusplus < 201103L +#elif __cplusplus < 201703L && !defined _MSC_VER -#error "This is not a C++11 compiler" +#error "This is not a C++17 compiler" #else -namespace cxx11 +#include +#include +#include + +namespace cxx17 { - namespace test_static_assert + namespace test_constexpr_lambdas { - template - struct check + constexpr int foo = [](){return 42;}(); + + } + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template + int multiply(Args... args) { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); + return (args * ... * 1); + } + + template + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same, decltype(foo)>::value); + static_assert(std::is_same::value); + } + + namespace test_typename_in_template_template_parameter + { + + template typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; }; + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + } - namespace test_final_override + namespace test_general_range_based_for_loop { - struct Base + struct iter { - virtual void f() {} + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } }; - struct Derived : public Base + struct sentinel { - virtual void f() override {} + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } }; + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + } - namespace test_double_right_angle_brackets + namespace test_lambda_capture_asterisk_this_by_value { - template < typename T > - struct check {}; + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; - typedef check single_type; - typedef check> double_type; - typedef check>> triple_type; - typedef check>>> quadruple_type; + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; } - namespace test_decltype + namespace test_constexpr_if { - int - f() + template + int f () { - int a = 1; - decltype(a) b = 2; - return a + b; + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } } } - namespace test_type_deduction + namespace test_selection_statement_with_initializer { - template < typename T1, typename T2 > - struct is_same + int f() { - static const bool value = false; - }; + return 13; + } - template < typename T > - struct is_same + int f2() { - static const bool value = true; - }; + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } - template < typename T1, typename T2 > - auto - add(T1 a1, T2 a2) -> decltype(a1 + a2) + } + + namespace test_template_argument_deduction_for_class_templates + { + + template + struct pair { - return a1 + a2; - } + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} - int - test(const int c, volatile int v) + T1 m1; + T2 m2; + }; + + void f() { - static_assert(is_same::value == true, ""); - static_assert(is_same::value == false, ""); - static_assert(is_same::value == false, ""); - auto ac = c; - auto av = v; - auto sumi = ac + av + 'x'; - auto sumf = ac + av + 1.0; - static_assert(is_same::value == true, ""); - static_assert(is_same::value == true, ""); - static_assert(is_same::value == true, ""); - static_assert(is_same::value == false, ""); - static_assert(is_same::value == true, ""); - return (sumf > 0.0) ? sumi : add(c, v); + [[maybe_unused]] auto p = pair{13, 42u}; } } - namespace test_noexcept + namespace test_non_type_auto_template_parameters { - int f() { return 0; } - int g() noexcept { return 0; } + template + struct B + {}; - static_assert(noexcept(f()) == false, ""); - static_assert(noexcept(g()) == true, ""); + B<5> b1; + B<'a'> b2; } - namespace test_constexpr + namespace test_structured_bindings { - template < typename CharT > - unsigned long constexpr - strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + int arr[2] = { 1, 2 }; + std::pair pr = { 1, 2 }; + + auto f1() -> int(&)[2] { - return *s ? strlen_c_r(s + 1, acc + 1) : acc; + return arr; } - template < typename CharT > - unsigned long constexpr - strlen_c(const CharT *const s) noexcept + auto f2() -> std::pair& + { + return pr; + } + + struct S + { + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; + } + + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + + } + + namespace test_exception_spec_type_system + { + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template + Bad + f(T*, T*); + + template + Good + f(T1*, T2*); + + static_assert (std::is_same_v); + + } + + namespace test_inline_variables + { + + template void f(T) + {} + + template inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // __cplusplus < 201703L && !defined _MSC_VER + + + + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 202002L && !defined _MSC_VER + +#error "This is not a C++20 compiler" + +#else + +#include + +namespace cxx20 +{ + +// As C++20 supports feature test macros in the standard, there is no +// immediate need to actually test for feature availability on the +// Autoconf side. + +} // namespace cxx20 + +#endif // __cplusplus < 202002L && !defined _MSC_VER + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO" +then : + ax_cv_cxx_compile_cxx20=yes +else $as_nop + ax_cv_cxx_compile_cxx20=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx20" >&5 +printf "%s\n" "$ax_cv_cxx_compile_cxx20" >&6; } + if test x$ax_cv_cxx_compile_cxx20 = xyes; then + ac_success=yes + fi + + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + switch="-std=gnu++${alternative}" + cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx20_$switch" | $as_tr_sh` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++20 features with $switch" >&5 +printf %s "checking whether $CXX supports C++20 features with $switch... " >&6; } +if eval test \${$cachevar+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_save_CXX="$CXX" + CXX="$CXX $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +// MSVC always sets __cplusplus to 199711L in older versions; newer versions +// only set it correctly if /Zc:__cplusplus is specified as well as a +// /std:c++NN switch: +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ +#elif __cplusplus < 201103L && !defined _MSC_VER + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual ~Base() {} + virtual void f() {} + }; + + struct Derived : public Base + { + virtual ~Derived() override {} + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L && !defined _MSC_VER + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + + + + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201703L && !defined _MSC_VER + +#error "This is not a C++17 compiler" + +#else + +#include +#include +#include + +namespace cxx17 +{ + + namespace test_constexpr_lambdas + { + + constexpr int foo = [](){return 42;}(); + + } + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template + int multiply(Args... args) + { + return (args * ... * 1); + } + + template + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same, decltype(foo)>::value); + static_assert(std::is_same::value); + } + + namespace test_typename_in_template_template_parameter + { + + template typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + + namespace test_template_argument_deduction_for_class_templates + { + + template + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } + + namespace test_non_type_auto_template_parameters + { + + template + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + + namespace test_structured_bindings + { + + int arr[2] = { 1, 2 }; + std::pair pr = { 1, 2 }; + + auto f1() -> int(&)[2] + { + return arr; + } + + auto f2() -> std::pair& + { + return pr; + } + + struct S + { + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; + } + + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + + } + + namespace test_exception_spec_type_system + { + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template + Bad + f(T*, T*); + + template + Good + f(T1*, T2*); + + static_assert (std::is_same_v); + + } + + namespace test_inline_variables + { + + template void f(T) + {} + + template inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // __cplusplus < 201703L && !defined _MSC_VER + + + + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 202002L && !defined _MSC_VER + +#error "This is not a C++20 compiler" + +#else + +#include + +namespace cxx20 +{ + +// As C++20 supports feature test macros in the standard, there is no +// immediate need to actually test for feature availability on the +// Autoconf side. + +} // namespace cxx20 + +#endif // __cplusplus < 202002L && !defined _MSC_VER + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO" +then : + eval $cachevar=yes +else $as_nop + eval $cachevar=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CXX="$ac_save_CXX" +fi +eval ac_res=\$$cachevar + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + fi + + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx20_$switch" | $as_tr_sh` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++20 features with $switch" >&5 +printf %s "checking whether $CXX supports C++20 features with $switch... " >&6; } +if eval test \${$cachevar+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_save_CXX="$CXX" + CXX="$CXX $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +// MSVC always sets __cplusplus to 199711L in older versions; newer versions +// only set it correctly if /Zc:__cplusplus is specified as well as a +// /std:c++NN switch: +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ +#elif __cplusplus < 201103L && !defined _MSC_VER + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual ~Base() {} + virtual void f() {} + }; + + struct Derived : public Base + { + virtual ~Derived() override {} + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L && !defined _MSC_VER + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + + + + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201703L && !defined _MSC_VER + +#error "This is not a C++17 compiler" + +#else + +#include +#include +#include + +namespace cxx17 +{ + + namespace test_constexpr_lambdas + { + + constexpr int foo = [](){return 42;}(); + + } + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template + int multiply(Args... args) + { + return (args * ... * 1); + } + + template + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same, decltype(foo)>::value); + static_assert(std::is_same::value); + } + + namespace test_typename_in_template_template_parameter + { + + template typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() { - return strlen_c_r(s, 0UL); + return 13; } - static_assert(strlen_c("") == 0UL, ""); - static_assert(strlen_c("1") == 1UL, ""); - static_assert(strlen_c("example") == 7UL, ""); - static_assert(strlen_c("another\0example") == 7UL, ""); + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } } - namespace test_rvalue_references + namespace test_template_argument_deduction_for_class_templates { - template < int N > - struct answer + template + struct pair { - static constexpr int value = N; - }; + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} - answer<1> f(int&) { return answer<1>(); } - answer<2> f(const int&) { return answer<2>(); } - answer<3> f(int&&) { return answer<3>(); } + T1 m1; + T2 m2; + }; - void - test() + void f() { - int i = 0; - const int c = 0; - static_assert(decltype(f(i))::value == 1, ""); - static_assert(decltype(f(c))::value == 2, ""); - static_assert(decltype(f(0))::value == 3, ""); + [[maybe_unused]] auto p = pair{13, 42u}; } } - namespace test_uniform_initialization + namespace test_non_type_auto_template_parameters { - struct test - { - static const int zero {}; - static const int one {1}; - }; + template + struct B + {}; - static_assert(test::zero == 0, ""); - static_assert(test::one == 1, ""); + B<5> b1; + B<'a'> b2; } - namespace test_lambdas + namespace test_structured_bindings { - void - test1() + int arr[2] = { 1, 2 }; + std::pair pr = { 1, 2 }; + + auto f1() -> int(&)[2] { - auto lambda1 = [](){}; - auto lambda2 = lambda1; - lambda1(); - lambda2(); + return arr; } - int - test2() + auto f2() -> std::pair& { - auto a = [](int i, int j){ return i + j; }(1, 2); - auto b = []() -> int { return '0'; }(); - auto c = [=](){ return a + b; }(); - auto d = [&](){ return c; }(); - auto e = [a, &b](int x) mutable { - const auto identity = [](int y){ return y; }; - for (auto i = 0; i < a; ++i) - a += b--; - return x + identity(a + b); - }(0); - return a + b + c + d + e; + return pr; } - int - test3() + struct S { - const auto nullary = [](){ return 0; }; - const auto unary = [](int x){ return x; }; - using nullary_t = decltype(nullary); - using unary_t = decltype(unary); - const auto higher1st = [](nullary_t f){ return f(); }; - const auto higher2nd = [unary](nullary_t f1){ - return [unary, f1](unary_t f2){ return f2(unary(f1())); }; - }; - return higher1st(nullary) + higher2nd(nullary)(unary); + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; } + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + } - namespace test_variadic_templates + namespace test_exception_spec_type_system { - template - struct sum; + struct Good {}; + struct Bad {}; - template - struct sum - { - static constexpr auto value = N0 + sum::value; - }; + void g1() noexcept; + void g2(); - template <> - struct sum<> - { - static constexpr auto value = 0; - }; + template + Bad + f(T*, T*); - static_assert(sum<>::value == 0, ""); - static_assert(sum<1>::value == 1, ""); - static_assert(sum<23>::value == 23, ""); - static_assert(sum<1, 2>::value == 3, ""); - static_assert(sum<5, 5, 11>::value == 21, ""); - static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + template + Good + f(T1*, T2*); + + static_assert (std::is_same_v); } - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function - // because of this. - namespace test_template_alias_sfinae + namespace test_inline_variables { - struct foo {}; + template void f(T) + {} - template - using member = typename T::member_type; + template inline T g(T) + { + return T{}; + } - template - void func(...) {} + template<> inline void f<>(int) + {} - template - void func(member*) {} + template<> int g<>(int) + { + return 5; + } - void test(); + } - void test() { func(0); } +} // namespace cxx17 - } +#endif // __cplusplus < 201703L && !defined _MSC_VER -} // namespace cxx11 -#endif // __cplusplus >= 201103L + + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 202002L && !defined _MSC_VER + +#error "This is not a C++20 compiler" + +#else + +#include + +namespace cxx20 +{ + +// As C++20 supports feature test macros in the standard, there is no +// immediate need to actually test for feature availability on the +// Autoconf side. + +} // namespace cxx20 + +#endif // __cplusplus < 202002L && !defined _MSC_VER _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : eval $cachevar=yes -else +else $as_nop eval $cachevar=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CXXFLAGS="$ac_save_CXXFLAGS" +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + CXX="$ac_save_CXX" fi eval ac_res=\$$cachevar - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" - ac_success=yes + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then break fi done @@ -7335,26 +10158,24 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu - if test x$ax_cxx_compile_cxx11_required = xtrue; then + if test x$ax_cxx_compile_cxx20_required = xtrue; then if test x$ac_success = xno; then - as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5 + as_fn_error $? "*** A compiler with support for C++20 language features is required." "$LINENO" 5 fi + fi + if test x$ac_success = xno; then + HAVE_CXX20=0 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: No compiler with C++20 support was found" >&5 +printf "%s\n" "$as_me: No compiler with C++20 support was found" >&6;} else - if test x$ac_success = xno; then - HAVE_CXX11=0 - { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5 -$as_echo "$as_me: No compiler with C++11 support was found" >&6;} - else - HAVE_CXX11=1 - -$as_echo "#define HAVE_CXX11 1" >>confdefs.h - - fi + HAVE_CXX20=1 +printf "%s\n" "#define HAVE_CXX20 1" >>confdefs.h fi + WARN_CXXFLAGS= ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' @@ -7362,11 +10183,12 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts -Werror=unknown-warning-option" >&5 -$as_echo_n "checking whether C++ compiler accepts -Werror=unknown-warning-option... " >&6; } -if ${ax_cv_check_cxxflags___Werror_unknown_warning_option+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts -Werror=unknown-warning-option" >&5 +printf %s "checking whether C++ compiler accepts -Werror=unknown-warning-option... " >&6; } +if test ${ax_cv_check_cxxflags___Werror_unknown_warning_option+y} +then : + printf %s "(cached) " >&6 +else $as_nop ax_check_save_flags=$CXXFLAGS CXXFLAGS="$CXXFLAGS -Werror=unknown-warning-option" @@ -7374,28 +10196,30 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : ax_cv_check_cxxflags___Werror_unknown_warning_option=yes -else +else $as_nop ax_cv_check_cxxflags___Werror_unknown_warning_option=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CXXFLAGS=$ax_check_save_flags fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cxxflags___Werror_unknown_warning_option" >&5 -$as_echo "$ax_cv_check_cxxflags___Werror_unknown_warning_option" >&6; } -if test "x$ax_cv_check_cxxflags___Werror_unknown_warning_option" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cxxflags___Werror_unknown_warning_option" >&5 +printf "%s\n" "$ax_cv_check_cxxflags___Werror_unknown_warning_option" >&6; } +if test "x$ax_cv_check_cxxflags___Werror_unknown_warning_option" = xyes +then : ax_compiler_flags_test="-Werror=unknown-warning-option" -else +else $as_nop ax_compiler_flags_test="" @@ -7406,12 +10230,13 @@ fi for flag in -Wmissing-braces -Wnon-virtual-dtor -Woverloaded-virtual -Wreorder -Wsign-compare -Wunused-local-typedefs -Wunused-variable -Wvla ; do - as_CACHEVAR=`$as_echo "ax_cv_check_cxxflags_${ax_compiler_flags_test}_$flag" | $as_tr_sh` -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $flag" >&5 -$as_echo_n "checking whether C++ compiler accepts $flag... " >&6; } -if eval \${$as_CACHEVAR+:} false; then : - $as_echo_n "(cached) " >&6 -else + as_CACHEVAR=`printf "%s\n" "ax_cv_check_cxxflags_${ax_compiler_flags_test}_$flag" | $as_tr_sh` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $flag" >&5 +printf %s "checking whether C++ compiler accepts $flag... " >&6; } +if eval test \${$as_CACHEVAR+y} +then : + printf %s "(cached) " >&6 +else $as_nop ax_check_save_flags=$CXXFLAGS CXXFLAGS="$CXXFLAGS ${ax_compiler_flags_test} $flag" @@ -7419,58 +10244,61 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : eval "$as_CACHEVAR=yes" -else +else $as_nop eval "$as_CACHEVAR=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CXXFLAGS=$ax_check_save_flags fi eval ac_res=\$$as_CACHEVAR - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } +if eval test \"x\$"$as_CACHEVAR"\" = x"yes" +then : -if ${WARN_CXXFLAGS+:} false; then : +if test ${WARN_CXXFLAGS+y} +then : case " $WARN_CXXFLAGS " in #( *" $flag "*) : - { { $as_echo "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS already contains \$flag"; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS already contains \$flag"; } >&5 (: WARN_CXXFLAGS already contains $flag) 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } ;; #( *) : as_fn_append WARN_CXXFLAGS " $flag" - { { $as_echo "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS=\"\$WARN_CXXFLAGS\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS=\"\$WARN_CXXFLAGS\""; } >&5 (: WARN_CXXFLAGS="$WARN_CXXFLAGS") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } ;; esac -else +else $as_nop WARN_CXXFLAGS=$flag - { { $as_echo "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS=\"\$WARN_CXXFLAGS\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS=\"\$WARN_CXXFLAGS\""; } >&5 (: WARN_CXXFLAGS="$WARN_CXXFLAGS") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } fi -else +else $as_nop : fi @@ -7486,16 +10314,17 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for O_CLOEXEC defined in fcntl.h" >&5 -$as_echo_n "checking for O_CLOEXEC defined in fcntl.h... " >&6; } -if ${ac_cv_defined_O_CLOEXEC_fcntl_h+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for O_CLOEXEC defined in fcntl.h" >&5 +printf %s "checking for O_CLOEXEC defined in fcntl.h... " >&6; } +if test ${ac_cv_defined_O_CLOEXEC_fcntl_h+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { #ifdef O_CLOEXEC @@ -7508,20 +10337,22 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_defined_O_CLOEXEC_fcntl_h=yes -else +else $as_nop ac_cv_defined_O_CLOEXEC_fcntl_h=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined_O_CLOEXEC_fcntl_h" >&5 -$as_echo "$ac_cv_defined_O_CLOEXEC_fcntl_h" >&6; } -if test $ac_cv_defined_O_CLOEXEC_fcntl_h != "no"; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined_O_CLOEXEC_fcntl_h" >&5 +printf "%s\n" "$ac_cv_defined_O_CLOEXEC_fcntl_h" >&6; } +if test $ac_cv_defined_O_CLOEXEC_fcntl_h != "no" +then : -else +else $as_nop -$as_echo "#define O_CLOEXEC 0" >>confdefs.h +printf "%s\n" "#define O_CLOEXEC 0" >>confdefs.h fi @@ -7571,23 +10402,14 @@ fi # Check whether --enable-processor was given. -if test "${enable_processor+set}" = set; then : - enableval=$enable_processor; case "${enableval}" in - yes) - disable_processor=false - ;; - no) - disable_processor=true - ;; - *) - as_fn_error $? "bad value ${enableval} for --disable-processor" "$LINENO" 5 - ;; - esac -else - disable_processor=false +if test ${enable_processor+y} +then : + enableval=$enable_processor; +else $as_nop + enable_processor=yes fi - if test x$disable_processor = xtrue; then + if test "x$enable_processor" != xyes; then DISABLE_PROCESSOR_TRUE= DISABLE_PROCESSOR_FALSE='#' else @@ -7597,23 +10419,14 @@ fi # Check whether --enable-tools was given. -if test "${enable_tools+set}" = set; then : - enableval=$enable_tools; case "${enableval}" in - yes) - disable_tools=false - ;; - no) - disable_tools=true - ;; - *) - as_fn_error $? "bad value ${enableval} for --disable-tools" "$LINENO" 5 - ;; - esac -else - disable_tools=false +if test ${enable_tools+y} +then : + enableval=$enable_tools; +else $as_nop + enable_tools=yes fi - if test x$disable_tools = xtrue; then + if test "x$enable_tools" != xyes; then DISABLE_TOOLS_TRUE= DISABLE_TOOLS_FALSE='#' else @@ -7622,28 +10435,19 @@ else fi -if test x$LINUX_HOST = xfalse -a x$disable_processor = xtrue -a x$disable_tools = xtrue; then - as_fn_error $? "--disable-processor and --disable-tools were specified, and not building for Linux. Nothing to build!" "$LINENO" 5 +if test x$LINUX_HOST = xfalse -a "x$enable_processor" != xyes -a "x$enable_tools" != xyes; then + as_fn_error $? "--disable-processor and --disable-tools were specified, and not building for Linux. Nothing to build!" "$LINENO" 5 fi # Check whether --enable-system-test-libs was given. -if test "${enable_system_test_libs+set}" = set; then : - enableval=$enable_system_test_libs; case "${enableval}" in - yes) - system_test_libs=true - ;; - no) - system_test_libs=false - ;; - *) - as_fn_error $? "bad value ${enableval} for --enable-system-test-libs" "$LINENO" 5 - ;; - esac -else - system_test_libs=false +if test ${enable_system_test_libs+y} +then : + enableval=$enable_system_test_libs; +else $as_nop + enable_system_test_libs=no fi - if test x$system_test_libs = xtrue; then + if test "x$enable_system_test_libs" = xyes; then SYSTEM_TEST_LIBS_TRUE= SYSTEM_TEST_LIBS_FALSE='#' else @@ -7656,7 +10460,7 @@ fi -if test x$system_test_libs = xtrue; then +if test "x$enable_system_test_libs" = xyes; then : "${GMOCK_CFLAGS:=-pthread}" : "${GMOCK_LIBS:=-lgmock -lgtest -pthread -lpthread}" : "${GTEST_CFLAGS:=-pthread}" @@ -7664,23 +10468,14 @@ if test x$system_test_libs = xtrue; then fi # Check whether --enable-selftest was given. -if test "${enable_selftest+set}" = set; then : - enableval=$enable_selftest; case "${enableval}" in - yes) - selftest=true - ;; - no) - selftest=false - ;; - *) - as_fn_error $? "bad value ${enableval} for --enable-selftest" "$LINENO" 5 - ;; - esac -else - selftest=false +if test ${enable_selftest+y} +then : + enableval=$enable_selftest; +else $as_nop + enable_selftest=no fi - if test x$selftest = xtrue; then + if test "x$enable_selftest" = xyes; then SELFTEST_TRUE= SELFTEST_FALSE='#' else @@ -7690,49 +10485,179 @@ fi -# Check whether --with-rust-demangle was given. -if test "${with_rust_demangle+set}" = set; then : - withval=$with_rust_demangle; case "${withval}" in - yes) - as_fn_error $? "You must pass the path to the rust-demangle-capi crate for --with-rust-demangle" "$LINENO" 5 - ;; - no) - rust_demangle=false - ;; - *) - if ! test -f "${withval}/Cargo.toml"; then - as_fn_error $? "You must pass the path to the rust-demangle-capi crate for --with-rust-demangle" "$LINENO" 5 - fi - RUST_DEMANGLE_CFLAGS="-DHAVE_RUST_DEMANGLE -I${withval}/target/include" - RUST_DEMANGLE_LIBS="-L${withval}/target/release -lrust_demangle -lpthread -ldl" - ;; - esac -else - rust_demangle=false +# Check whether --with-rustc-demangle was given. +if test ${with_rustc_demangle+y} +then : + withval=$with_rustc_demangle; +else $as_nop + with_rustc_demangle=no +fi + + +RUSTC_DEMANGLE_BASE_CFLAGS="-DHAVE_RUSTC_DEMANGLE" +RUSTC_DEMANGLE_BASE_LIBS="-lrustc_demangle -lpthread -ldl" + +if test "x${with_rustc_demangle}" != xno; then + if ! test -f "${with_rustc_demangle}/Cargo.toml"; then + as_fn_error $? "You must pass the path to the rustc-demangle crate for --with-rustc-demangle" "$LINENO" 5 + fi + RUSTC_DEMANGLE_CFLAGS="-I${with_rustc_demangle}/crates/capi/include ${RUSTC_DEMANGLE_BASE_CFLAGS}" + RUSTC_DEMANGLE_LIBS="-L${with_rustc_demangle}/target/release ${RUSTC_DEMANGLE_BASE_LIBS}" +fi + +# Check whether --enable-system-rustc-demangle was given. +if test ${enable_system_rustc_demangle+y} +then : + enableval=$enable_system_rustc_demangle; +else $as_nop + enable_system_rustc_demangle=no +fi + + +if test "x${enable_system_rustc_demangle}" != xno; then + if test "x${with_rustc_demangle}" != xno; then + as_fn_error $? "--enable-system-rustc-demangle and --with-rustc-demangle are mutually exclusive." "$LINENO" 5 + fi + + RUSTC_DEMANGLE_CFLAGS="${RUSTC_DEMANGLE_BASE_CFLAGS}" + RUSTC_DEMANGLE_LIBS="${RUSTC_DEMANGLE_BASE_LIBS}" + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rustc_demangle in -lrustc_demangle" >&5 +printf %s "checking for rustc_demangle in -lrustc_demangle... " >&6; } +if test ${ac_cv_lib_rustc_demangle_rustc_demangle+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrustc_demangle $RUSTC_DEMANGLE_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char rustc_demangle (); +int +main (void) +{ +return rustc_demangle (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_rustc_demangle_rustc_demangle=yes +else $as_nop + ac_cv_lib_rustc_demangle_rustc_demangle=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rustc_demangle_rustc_demangle" >&5 +printf "%s\n" "$ac_cv_lib_rustc_demangle_rustc_demangle" >&6; } +if test "x$ac_cv_lib_rustc_demangle_rustc_demangle" = xyes +then : + printf "%s\n" "#define HAVE_LIBRUSTC_DEMANGLE 1" >>confdefs.h + + LIBS="-lrustc_demangle $LIBS" + +else $as_nop + as_fn_error $? "librustc_demangle.a must be present when --enable-system-rustc-demangle is specified" "$LINENO" 5 +fi + + for ac_header in rustc_demangle.h +do : + ac_fn_c_check_header_compile "$LINENO" "rustc_demangle.h" "ac_cv_header_rustc_demangle_h" "$ac_includes_default" +if test "x$ac_cv_header_rustc_demangle_h" = xyes +then : + printf "%s\n" "#define HAVE_RUSTC_DEMANGLE_H 1" >>confdefs.h + +else $as_nop + as_fn_error $? "rustc_demangle.h must be present when --enable-system-rustc-demangle is specified" "$LINENO" 5 +fi + +done +fi + + + + +# Check whether --enable-zstd was given. +if test ${enable_zstd+y} +then : + enableval=$enable_zstd; +else $as_nop + enable_zstd=no fi +if test "x${enable_zstd}" != xno; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ZSTD_decompress in -lzstd" >&5 +printf %s "checking for ZSTD_decompress in -lzstd... " >&6; } +if test ${ac_cv_lib_zstd_ZSTD_decompress+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lzstd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char ZSTD_decompress (); +int +main (void) +{ +return ZSTD_decompress (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_zstd_ZSTD_decompress=yes +else $as_nop + ac_cv_lib_zstd_ZSTD_decompress=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_zstd_ZSTD_decompress" >&5 +printf "%s\n" "$ac_cv_lib_zstd_ZSTD_decompress" >&6; } +if test "x$ac_cv_lib_zstd_ZSTD_decompress" = xyes +then : + printf "%s\n" "#define HAVE_LIBZSTD 1" >>confdefs.h + + LIBS="-lzstd $LIBS" +else $as_nop + as_fn_error $? "zstd library not found." "$LINENO" 5 +fi + + ac_fn_c_check_header_compile "$LINENO" "zstd.h" "ac_cv_header_zstd_h" "$ac_includes_default" +if test "x$ac_cv_header_zstd_h" = xyes +then : + +else $as_nop + as_fn_error $? "zstd header not found." "$LINENO" 5 +fi +fi # Check whether --with-tests-as-root was given. -if test "${with_tests_as_root+set}" = set; then : - withval=$with_tests_as_root; case "${withval}" in - yes) - tests_as_root=true - ;; - no) - tests_as_root=false - ;; - *) - as_fn_error $? "--with-tests-as-root can only be \"yes\" or \"no\"" "$LINENO" 5 - ;; - esac -else - tests_as_root=false +if test ${with_tests_as_root+y} +then : + withval=$with_tests_as_root; +else $as_nop + with_tests_as_root=no fi - if test x$tests_as_root = xtrue; then + if test "x$with_tests_as_root" = xyes; then TESTS_AS_ROOT_TRUE= TESTS_AS_ROOT_FALSE='#' else @@ -7771,8 +10696,8 @@ _ACEOF case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -7802,15 +10727,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; /^ac_cv_env_/b end t clear :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else @@ -7824,8 +10749,8 @@ $as_echo "$as_me: updating cache $cache_file" >&6;} fi fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache @@ -7838,10 +10763,11 @@ DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= +U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" @@ -7852,14 +10778,14 @@ LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 -$as_echo_n "checking that generated files are newer than configure... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +printf %s "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 -$as_echo "done" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 +printf "%s\n" "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' @@ -7937,8 +10863,8 @@ fi ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL @@ -7961,14 +10887,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -7978,46 +10906,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -8026,13 +10954,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -8041,8 +10962,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -8054,30 +10979,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] @@ -8090,13 +10995,14 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -8123,18 +11029,20 @@ as_fn_unset () { eval $1=; unset $1;} } as_unset=as_fn_unset + # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -8146,12 +11054,13 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` @@ -8182,7 +11091,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -8204,6 +11113,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -8217,6 +11130,12 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -8258,7 +11177,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -8267,7 +11186,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -8330,7 +11249,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by breakpad $as_me 0.1, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -8392,14 +11311,16 @@ $config_commands Report bugs to ." _ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ breakpad config.status 0.1 -configured by $0, generated by GNU Autoconf 2.69, +configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -8439,15 +11360,15 @@ do -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; + printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; + printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" @@ -8455,7 +11376,7 @@ do --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; @@ -8464,7 +11385,7 @@ do as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; + printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; @@ -8492,7 +11413,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" @@ -8506,7 +11427,7 @@ exec 5>>config.log sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - $as_echo "$ac_log" + printf "%s\n" "$ac_log" } >&5 _ACEOF @@ -8540,9 +11461,9 @@ done # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files - test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers - test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files + test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers + test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree @@ -8878,7 +11799,7 @@ do esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done @@ -8886,17 +11807,17 @@ do # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | + ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac @@ -8913,7 +11834,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | +printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -8937,9 +11858,9 @@ $as_echo X"$ac_file" | case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -9001,8 +11922,8 @@ ac_sed_dataroot=' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' @@ -9046,9 +11967,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" @@ -9064,20 +11985,20 @@ which seems to be undefined. Please make sure it is defined" >&2;} # if test x"$ac_file" != x-; then { - $as_echo "/* $configure_input */" \ + printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -$as_echo "$as_me: $ac_file is unchanged" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else - $as_echo "/* $configure_input */" \ + printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi @@ -9097,7 +12018,7 @@ $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$_am_arg" | +printf "%s\n" X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -9117,8 +12038,8 @@ $as_echo X"$_am_arg" | s/.*/./; q'`/stamp-h$_am_stamp_count ;; - :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -$as_echo "$as_me: executing $ac_file commands" >&6;} + :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +printf "%s\n" "$as_me: executing $ac_file commands" >&6;} ;; esac @@ -9144,7 +12065,7 @@ esac for am_mf do # Strip MF so we end up with the name of the file. - am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'` + am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line @@ -9156,7 +12077,7 @@ $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$am_mf" | +printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -9178,7 +12099,7 @@ $as_echo X"$am_mf" | $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$am_mf" | +printf "%s\n" X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -9203,8 +12124,8 @@ $as_echo X/"$am_mf" | (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is @@ -9254,7 +12175,8 @@ if test "$no_create" != yes; then $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi + diff --git a/configure.ac b/configure.ac index b62b8fe53..0258c116e 100644 --- a/configure.ac +++ b/configure.ac @@ -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,17 +27,17 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -AC_PREREQ(2.64) +AC_PREREQ([2.71]) -AC_INIT(breakpad, 0.1, google-breakpad-dev@googlegroups.com) +AC_INIT([breakpad],[0.1],[google-breakpad-dev@googlegroups.com]) dnl Sanity check: the argument is just a file that should exist. AC_CONFIG_SRCDIR(README.md) AC_CONFIG_AUX_DIR(autotools) AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_HOST -AM_INIT_AUTOMAKE(subdir-objects tar-ustar 1.11.1) -AM_CONFIG_HEADER(src/config.h) +AM_INIT_AUTOMAKE(subdir-objects tar-ustar 1.13) +AC_CONFIG_HEADERS(src/config.h) AM_MAINTAINER_MODE AM_PROG_AR @@ -53,23 +52,13 @@ dnl This must come before all the feature tests below. AC_ARG_ENABLE(m32, AS_HELP_STRING([--enable-m32], [Compile/build with -m32] - [(default is no)]), - [case "${enableval}" in - yes) - CFLAGS="${CFLAGS} -m32" - CXXFLAGS="${CXXFLAGS} -m32" - usem32=true - ;; - no) - usem32=false - ;; - *) - AC_MSG_ERROR(bad value ${enableval} for --enable-m32) - ;; - esac], - [usem32=false]) + [(default is no)]),, + [enable_m32=no]) +if test "x$enable_m32" = xyes; then + CFLAGS="${CFLAGS} -m32" + CXXFLAGS="${CXXFLAGS} -m32" +fi -AC_HEADER_STDC AC_SYS_LARGEFILE AX_PTHREAD AC_CHECK_HEADERS([a.out.h sys/mman.h sys/random.h]) @@ -77,7 +66,7 @@ AC_CHECK_FUNCS([arc4random getcontext getrandom memfd_create]) AM_CONDITIONAL([HAVE_GETCONTEXT], [test "x$ac_cv_func_getcontext" = xyes]) AM_CONDITIONAL([HAVE_MEMFD_CREATE], [test "x$ac_cv_func_memfd_create" = xyes]) -AX_CXX_COMPILE_STDCXX(11, noext, mandatory) +AX_CXX_COMPILE_STDCXX(20, , mandatory) dnl Test supported warning flags. WARN_CXXFLAGS= @@ -134,66 +123,33 @@ AM_CONDITIONAL(X86_HOST, test x$X86_HOST = xtrue) AC_ARG_ENABLE(processor, AS_HELP_STRING([--disable-processor], [Don't build processor library] - [(default is no)]), - [case "${enableval}" in - yes) - disable_processor=false - ;; - no) - disable_processor=true - ;; - *) - AC_MSG_ERROR(bad value ${enableval} for --disable-processor) - ;; - esac], - [disable_processor=false]) -AM_CONDITIONAL(DISABLE_PROCESSOR, test x$disable_processor = xtrue) + [(default is no)]),, + [enable_processor=yes]) +AM_CONDITIONAL(DISABLE_PROCESSOR, test "x$enable_processor" != xyes) AC_ARG_ENABLE(tools, AS_HELP_STRING([--disable-tools], [Don't build tool binaries] - [(default is no)]), - [case "${enableval}" in - yes) - disable_tools=false - ;; - no) - disable_tools=true - ;; - *) - AC_MSG_ERROR(bad value ${enableval} for --disable-tools) - ;; - esac], - [disable_tools=false]) -AM_CONDITIONAL(DISABLE_TOOLS, test x$disable_tools = xtrue) + [(default is no)]),, + [enable_tools=yes]) +AM_CONDITIONAL(DISABLE_TOOLS, test "x$enable_tools" != xyes) -if test x$LINUX_HOST = xfalse -a x$disable_processor = xtrue -a x$disable_tools = xtrue; then - AC_MSG_ERROR([--disable-processor and --disable-tools were specified, and not building for Linux. Nothing to build!]) +if test x$LINUX_HOST = xfalse -a "x$enable_processor" != xyes -a "x$enable_tools" != xyes; then + AC_MSG_ERROR([--disable-processor and --disable-tools were specified, and not building for Linux. Nothing to build!]) fi AC_ARG_ENABLE(system-test-libs, AS_HELP_STRING([--enable-system-test-libs], [Use gtest/gmock/etc... from the system instead ] - [of the local copies (default is local)]), - [case "${enableval}" in - yes) - system_test_libs=true - ;; - no) - system_test_libs=false - ;; - *) - AC_MSG_ERROR(bad value ${enableval} for --enable-system-test-libs) - ;; - esac], - [system_test_libs=false]) -AM_CONDITIONAL(SYSTEM_TEST_LIBS, test x$system_test_libs = xtrue) + [of the local copies (default is local)]),, + [enable_system_test_libs=no]) +AM_CONDITIONAL(SYSTEM_TEST_LIBS, test "x$enable_system_test_libs" = xyes) AC_ARG_VAR([GMOCK_CFLAGS], [Compiler flags for gmock]) AC_ARG_VAR([GMOCK_LIBS], [Linker flags for gmock]) AC_ARG_VAR([GTEST_CFLAGS], [Compiler flags for gtest]) AC_ARG_VAR([GTEST_LIBS], [Linker flags for gtest]) -if test x$system_test_libs = xtrue; then +if test "x$enable_system_test_libs" = xyes; then : "${GMOCK_CFLAGS:=-pthread}" : "${GMOCK_LIBS:=-lgmock -lgtest -pthread -lpthread}" : "${GTEST_CFLAGS:=-pthread}" @@ -204,64 +160,76 @@ AC_ARG_ENABLE(selftest, AS_HELP_STRING([--enable-selftest], [Run extra tests with "make check" ] [(may conflict with optimizations) ] - [(default is no)]), - [case "${enableval}" in - yes) - selftest=true - ;; - no) - selftest=false - ;; - *) - AC_MSG_ERROR(bad value ${enableval} for --enable-selftest) - ;; - esac], - [selftest=false]) -AM_CONDITIONAL(SELFTEST, test x$selftest = xtrue) + [(default is no)]),, + [enable_selftest=no]) +AM_CONDITIONAL(SELFTEST, test "x$enable_selftest" = xyes) -AC_ARG_WITH(rust-demangle, - AS_HELP_STRING([--with-rust-demangle=/path/to/rust-demangle-capi], - [Link against the rust-demangle library] +AC_ARG_WITH(rustc-demangle, + AS_HELP_STRING([--with-rustc-demangle=/path/to/rustc-demangle], + [Link against the rustc-demangle library] [to demangle Rust language symbols during] [symbol dumping (default is no)] - [Pass the path to the crate root.]), - [case "${withval}" in - yes) - AC_MSG_ERROR(You must pass the path to the rust-demangle-capi crate for --with-rust-demangle) - ;; - no) - rust_demangle=false - ;; - *) - if ! test -f "${withval}/Cargo.toml"; then - AC_MSG_ERROR(You must pass the path to the rust-demangle-capi crate for --with-rust-demangle) - fi - RUST_DEMANGLE_CFLAGS="-DHAVE_RUST_DEMANGLE -I${withval}/target/include" - RUST_DEMANGLE_LIBS="-L${withval}/target/release -lrust_demangle -lpthread -ldl" - ;; - esac], - [rust_demangle=false]) -AC_ARG_VAR([RUST_DEMANGLE_CFLAGS], [Compiler flags for rust-demangle]) -AC_ARG_VAR([RUST_DEMANGLE_LIBS], [Linker flags for rust-demangle]) + [Pass the path to the crate root.]),, + [with_rustc_demangle=no]) + +RUSTC_DEMANGLE_BASE_CFLAGS="-DHAVE_RUSTC_DEMANGLE" +RUSTC_DEMANGLE_BASE_LIBS="-lrustc_demangle -lpthread -ldl" + +if test "x${with_rustc_demangle}" != xno; then + if ! test -f "${with_rustc_demangle}/Cargo.toml"; then + AC_MSG_ERROR(You must pass the path to the rustc-demangle crate for --with-rustc-demangle) + fi + RUSTC_DEMANGLE_CFLAGS="-I${with_rustc_demangle}/crates/capi/include ${RUSTC_DEMANGLE_BASE_CFLAGS}" + RUSTC_DEMANGLE_LIBS="-L${with_rustc_demangle}/target/release ${RUSTC_DEMANGLE_BASE_LIBS}" +fi + +AC_ARG_ENABLE(system-rustc-demangle, + AS_HELP_STRING([--enable-system-rustc-demangle], + [Link against the rustc-demangle library] + [to demangle Rust language symbols during] + [symbol dumping (default is no). This assumes] + [that rustc-demangle is installed in your sysroot,] + [and all headers from it are available in your] + [standard include path] + ),, + [enable_system_rustc_demangle=no]) + +if test "x${enable_system_rustc_demangle}" != xno; then + if test "x${with_rustc_demangle}" != xno; then + AC_MSG_ERROR([--enable-system-rustc-demangle and --with-rustc-demangle are mutually exclusive.]) + fi + + RUSTC_DEMANGLE_CFLAGS="${RUSTC_DEMANGLE_BASE_CFLAGS}" + RUSTC_DEMANGLE_LIBS="${RUSTC_DEMANGLE_BASE_LIBS}" + + AC_CHECK_LIB([rustc_demangle], [rustc_demangle], [], + [AC_MSG_ERROR(librustc_demangle.a must be present when --enable-system-rustc-demangle is specified)], + [$RUSTC_DEMANGLE_LIBS]) + AC_CHECK_HEADERS(rustc_demangle.h, [], + [AC_MSG_ERROR(rustc_demangle.h must be present when --enable-system-rustc-demangle is specified)]) +fi + +AC_ARG_VAR([RUSTC_DEMANGLE_CFLAGS], [Compiler flags for rustc-demangle]) +AC_ARG_VAR([RUSTC_DEMANGLE_LIBS], [Linker flags for rustc-demangle]) + +AC_ARG_ENABLE(zstd, + AS_HELP_STRING([--enable-zstd], + [Enable decompression of ELF sections with zstd]),, + [enable_zstd=no]) +if test "x${enable_zstd}" != xno; then + AC_CHECK_LIB(zstd, ZSTD_decompress, [], + [AC_MSG_ERROR([zstd library not found.])]) + AC_CHECK_HEADER(zstd.h, [], + [AC_MSG_ERROR([zstd header not found.])]) +fi AC_ARG_WITH(tests-as-root, AS_HELP_STRING([--with-tests-as-root], [Run the tests as root. Use this on platforms] [like travis-ci.org that require root privileges] - [to use ptrace (default is no)]), - [case "${withval}" in - yes) - tests_as_root=true - ;; - no) - tests_as_root=false - ;; - *) - AC_MSG_ERROR(--with-tests-as-root can only be "yes" or "no") - ;; - esac], - [tests_as_root=false]) -AM_CONDITIONAL(TESTS_AS_ROOT, test x$tests_as_root = xtrue) + [to use ptrace (default is no)]),, + [with_tests_as_root=no]) +AM_CONDITIONAL(TESTS_AS_ROOT, test "x$with_tests_as_root" = xyes) AC_CONFIG_FILES(m4_flatten([ breakpad.pc diff --git a/default.xml b/default.xml index 767415de8..72ff675b4 100644 --- a/default.xml +++ b/default.xml @@ -2,42 +2,37 @@ - - - + + - - - - + + diff --git a/docs/symbol_files.md b/docs/symbol_files.md index 237b6567f..e05b455bb 100644 --- a/docs/symbol_files.md +++ b/docs/symbol_files.md @@ -33,8 +33,15 @@ restrictions, these may appear in any order. * A `FILE` record gives a source file name, and assigns it a number by which other records can refer to it. +* An `INLINE_ORIGIN` record holds an inline function name for `INLINE` records + to refer to. + * A `FUNC` record describes a function present in the source code. +* An `INLINE` record describes the inline function's nest level, call site + line and call site source file to which the given ranges of machine code + should be attributed. + * A line record indicates to which source file and line a given range of machine code should be attributed. The line is attributed to the function defined by the most recent `FUNC` record. @@ -62,16 +69,25 @@ for _name_. * The _operatingsystem_ field names the operating system on which the executable or shared library was intended to run. This field should have one - of the following values: | **Value** | **Meaning** | - |:----------|:--------------------| | Linux | Linux | | mac | Macintosh OSX - | | windows | Microsoft Windows | + of the following values: + + | **Value** | **Meaning** | + |:----------|:--------------------| + | Linux | Linux | + | mac | Macintosh OSX | + | windows | Microsoft Windows | * The _architecture_ field indicates what processor architecture the executable or shared library contains machine code for. This field should - have one of the following values: | **Value** | **Instruction Set - Architecture** | |:----------|:---------------------------------| | x86 | - Intel IA-32 | | x86\_64 | AMD64/Intel 64 | | ppc | 32-bit PowerPC | | ppc64 - | 64-bit PowerPC | | unknown | unknown | + have one of the following values: + + | **Value** | **Instruction Set Architecture** | + |:----------|:---------------------------------| + | x86 | Intel IA-32 | + | x86\_64 | AMD64/Intel 64 | + | ppc | 32-bit PowerPC | + | ppc64 | 64-bit PowerPC | + | unknown | unknown | * The _id_ field is a sequence of hexadecimal digits that identifies the exact executable or library whose contents the symbol file describes. The way in @@ -96,6 +112,22 @@ which other records (line records, in particular) can use to refer to that file name. The _number_ field is a decimal number. The _name_ field is the name of the file; it may contain spaces. +# `INLINE_ORIGIN` records + +An `INLINE_ORIGIN` record holds an inline function name for `INLINE` records to +refer to. It has the form: + +> `INLINE_ORIGIN` _number_ _name_ + +For example: `INLINE_ORIGIN 2 nsQueryInterfaceWithError::operator()(nsID const&, +void**) const +` + +An `INLINE_ORIGIN` record provides the name of an inline function, and assigns +it a number which other records (`INLINE` records, in particular) can use to +refer to that function name. The _number_ field is a decimal number. The _name_ +field is the name of the inline function; it may contain spaces. + # `FUNC` records A `FUNC` record describes a source-language function. It has the form: @@ -127,6 +159,49 @@ The _name_ field is the name of the function. In languages that use linker symbol name mangling like C++, this should be the source language name (the "unmangled" form). This field may contain spaces. +# `INLINE` records + +An `INLINE` record describes the inline function's nest level, call site line +and call site source file to which the given ranges of machine code should be +attributed. It has the form: + +> `INLINE` _inline_nest_level_ _call_site_line_ _call_site_file_num_ +> _origin_num_ [_address_ _size_]+ + +For example: `INLINE 0 10 3 4 d30 2a fa1 b +` + +The _inline_nest_level_ field is a decimal number that means it's inlined at the +function described by a previous `INLINE` record which has _inline_nest_level_ +one less than its. In the example below, first and third `INLINE` records have +_inline_nest_level_ 0, which means they are inlined inside the function +described by the `FUNC` record. The second `INLINE` record has +_inline_nest_level_ 1 means that it's inlined at the inline function described +by first `INLINE` record. +``` +FUNC ... +INLINE 0 ... +INLINE 1 ... +INLINE 0 ... +``` + +The _call_site_line_ and _call_site_file_num_ fields are decimal numbers +indicating where this inline function being called at. + +The _origin_num_ field refers to an `INLINE_ORIGIN` record that has the name +of the inline function. + +The _address_ and _size_ fields are hexadecimal numbers indicating the start +address and length in bytes of the machine code. The address is relative to the +module's load address. There could be more than one [_address_ _size_] range +pair, since inline functions could have discontinuous address ranges. The ranges +of an `INLINE` record are always inside the ranges described by its parent +record (a `FUNC` record or an `INLINE` record). + +The `INLINE` record is assumed to belong to the function described by the last +preceding `FUNC` record. `INLINE` records may not appear before the first `FUNC` +record. + # Line records A line record describes the source file and line number to which a given range @@ -396,14 +471,14 @@ func+22: pc = *sp; sp += 4 ; pop return address and jump to it The following table would describe the function above: -**code address** | **.cfa** | **r0 (on Google Code)** | **r1 (on Google Code)** | ... | **.ra** -:--------------- | :------- | :---------------------- | :---------------------- | :-- | :------- -func+0 | sp | | | | `cfa[0]` -func+1 | sp+16 | | | | `cfa[0]` -func+2 | sp+16 | `cfa[-4]` | | | `cfa[0]` -func+11 | sp+20 | `cfa[-4]` | | | `cfa[0]` -func+21 | sp+20 | | | | `cfa[0]` -func+22 | sp | | | | `cfa[0]` +| **code address** | **.cfa** | **r0 (on Google Code)** | **r1 (on Google Code)** | ... | **.ra** | +|:-----------------|:---------|:------------------------|:------------------------|:----|:---------| +| func+0 | sp | | | | `cfa[0]` | +| func+1 | sp+16 | | | | `cfa[0]` | +| func+2 | sp+16 | `cfa[-4]` | | | `cfa[0]` | +| func+11 | sp+20 | `cfa[-4]` | | | `cfa[0]` | +| func+21 | sp+20 | | | | `cfa[0]` | +| func+22 | sp | | | | `cfa[0]` | Some things to note here: @@ -438,14 +513,14 @@ To save space, the most common type of CFI record only mentions the table entries at which changes take place. So for the above, the CFI data would only actually mention the non-blank entries here: -**insn** | **cfa** | **r0 (on Google Code)** | **r1 (on Google Code)** | ... | **ra** -:------- | :------ | :---------------------- | :---------------------- | :-- | :------- -func+0 | sp | | | | `cfa[0]` -func+1 | sp+16 | | | | -func+2 | | `cfa[-4]` | | | -func+11 | sp+20 | | | | -func+21 | | r0 (on Google Code) | | | -func+22 | sp | | | | +| **insn** | **cfa** | **r0 (on Google Code)** | **r1 (on Google Code)** | ... | **ra** | +|:---------|:--------|:------------------------|:------------------------|:----|:---------| +| func+0 | sp | | | | `cfa[0]` | +| func+1 | sp+16 | | | | | +| func+2 | | `cfa[-4]` | | | | +| func+11 | sp+20 | | | | | +| func+21 | | r0 (on Google Code) | | | | +| func+22 | sp | | | | | A `STACK CFI INIT` record indicates that, at the machine instruction at _address_, belonging to some function, the value that _registern_ had diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4 index 079e17d2a..a3d964c69 100644 --- a/m4/ax_cxx_compile_stdcxx.m4 +++ b/m4/ax_cxx_compile_stdcxx.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html # =========================================================================== # # SYNOPSIS @@ -9,14 +9,14 @@ # DESCRIPTION # # Check for baseline language coverage in the compiler for the specified -# version of the C++ standard. If necessary, add switches to CXXFLAGS to -# enable support. VERSION may be '11' (for the C++11 standard) or '14' -# (for the C++14 standard). +# version of the C++ standard. If necessary, add switches to CXX and +# CXXCPP to enable support. VERSION may be '11', '14', '17', or '20' for +# the respective C++ standard version. # # The second argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with -# preference for an extended mode. +# preference for no added switch, and then for an extended mode. # # The third argument, if specified 'mandatory' or if left unspecified, # indicates that baseline support for the specified C++ standard is @@ -33,21 +33,26 @@ # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov # Copyright (c) 2015 Paul Norman # Copyright (c) 2015 Moritz Klammler +# Copyright (c) 2016, 2018 Krzesimir Nowak +# Copyright (c) 2019 Enji Cooper +# Copyright (c) 2020 Jason Merrill +# Copyright (c) 2021 Jörn Heusipp # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 1 +#serial 15 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl - m4_if([$1], [11], [], - [$1], [14], [], - [$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])], + m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], + [$1], [14], [ax_cxx_compile_alternatives="14 1y"], + [$1], [17], [ax_cxx_compile_alternatives="17 1z"], + [$1], [20], [ax_cxx_compile_alternatives="20"], [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$2], [], [], [$2], [ext], [], @@ -59,29 +64,35 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) AC_LANG_PUSH([C++])dnl ac_success=no - AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, - ax_cv_cxx_compile_cxx$1, - [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [ax_cv_cxx_compile_cxx$1=yes], - [ax_cv_cxx_compile_cxx$1=no])]) - if test x$ax_cv_cxx_compile_cxx$1 = xyes; then - ac_success=yes - fi + + m4_if([$2], [], [dnl + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi]) m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then - for switch in -std=gnu++$1 -std=gnu++0x; do + for alternative in ${ax_cxx_compile_alternatives}; do + switch="-std=gnu++${alternative}" cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, - [ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" + [ac_save_CXX="$CXX" + CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) - CXXFLAGS="$ac_save_CXXFLAGS"]) + CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi ac_success=yes break fi @@ -93,19 +104,27 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl dnl HP's aCC needs +std=c++11 according to: dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf dnl Cray's crayCC needs "-h std=c++11" - for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, - $cachevar, - [ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXXFLAGS="$ac_save_CXXFLAGS"]) - if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" - ac_success=yes + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then break fi done @@ -115,18 +134,16 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) fi + fi + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) else - if test x$ac_success = xno; then - HAVE_CXX$1=0 - AC_MSG_NOTICE([No compiler with C++$1 support was found]) - else - HAVE_CXX$1=1 - AC_DEFINE(HAVE_CXX$1,1, - [define if the compiler supports basic C++$1 syntax]) - fi - - AC_SUBST(HAVE_CXX$1) + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) fi + AC_SUBST(HAVE_CXX$1) ]) @@ -136,7 +153,6 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 ) - dnl Test body for checking C++14 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], @@ -144,6 +160,23 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 ) +dnl Test body for checking C++17 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 +) + +dnl Test body for checking C++20 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_20 +) + dnl Tests for new features in C++11 @@ -156,7 +189,11 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ #error "This is not a C++ compiler" -#elif __cplusplus < 201103L +// MSVC always sets __cplusplus to 199711L in older versions; newer versions +// only set it correctly if /Zc:__cplusplus is specified as well as a +// /std:c++NN switch: +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ +#elif __cplusplus < 201103L && !defined _MSC_VER #error "This is not a C++11 compiler" @@ -181,11 +218,13 @@ namespace cxx11 struct Base { + virtual ~Base() {} virtual void f() {} }; struct Derived : public Base { + virtual ~Derived() override {} virtual void f() override {} }; @@ -445,7 +484,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ #error "This is not a C++ compiler" -#elif __cplusplus < 201402L +#elif __cplusplus < 201402L && !defined _MSC_VER #error "This is not a C++14 compiler" @@ -514,7 +553,7 @@ namespace cxx14 } - namespace test_digit_seperators + namespace test_digit_separators { constexpr auto ten_million = 100'000'000; @@ -556,3 +595,415 @@ namespace cxx14 #endif // __cplusplus >= 201402L ]]) + + +dnl Tests for new features in C++17 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201703L && !defined _MSC_VER + +#error "This is not a C++17 compiler" + +#else + +#include +#include +#include + +namespace cxx17 +{ + + namespace test_constexpr_lambdas + { + + constexpr int foo = [](){return 42;}(); + + } + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template + int multiply(Args... args) + { + return (args * ... * 1); + } + + template + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same, decltype(foo)>::value); + static_assert(std::is_same::value); + } + + namespace test_typename_in_template_template_parameter + { + + template typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + + namespace test_template_argument_deduction_for_class_templates + { + + template + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } + + namespace test_non_type_auto_template_parameters + { + + template + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + + namespace test_structured_bindings + { + + int arr[2] = { 1, 2 }; + std::pair pr = { 1, 2 }; + + auto f1() -> int(&)[2] + { + return arr; + } + + auto f2() -> std::pair& + { + return pr; + } + + struct S + { + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; + } + + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + + } + + namespace test_exception_spec_type_system + { + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template + Bad + f(T*, T*); + + template + Good + f(T1*, T2*); + + static_assert (std::is_same_v); + + } + + namespace test_inline_variables + { + + template void f(T) + {} + + template inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // __cplusplus < 201703L && !defined _MSC_VER + +]]) + + +dnl Tests for new features in C++20 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[ + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 202002L && !defined _MSC_VER + +#error "This is not a C++20 compiler" + +#else + +#include + +namespace cxx20 +{ + +// As C++20 supports feature test macros in the standard, there is no +// immediate need to actually test for feature availability on the +// Autoconf side. + +} // namespace cxx20 + +#endif // __cplusplus < 202002L && !defined _MSC_VER + +]]) diff --git a/scripts/travis-build.sh b/scripts/travis-build.sh deleted file mode 100755 index 1d1beb3d5..000000000 --- a/scripts/travis-build.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash - -set -ex - -setup_env() { - # Travis sets CC/CXX to the system toolchain, so our .travis.yml - # exports USE_{CC,CXX} for this script to use. - if [ -n "$USE_CC" ]; then - export CC=$USE_CC - fi - if [ -n "$USE_CXX" ]; then - export CXX=$USE_CXX - fi - # Use -jN for faster builds. Travis build machines under Docker - # have a lot of cores, but are memory-limited, so the kernel - # will OOM if we try to use them all, so use at most 4. - # See https://github.com/travis-ci/travis-ci/issues/1972 - export NCPUS=$(getconf _NPROCESSORS_ONLN) - export JOBS=$(( $NCPUS < 4 ? $NCPUS : 4 )) -} - -# We have to do this by hand rather than use the coverity addon because of -# matrix explosion: https://github.com/travis-ci/travis-ci/issues/1975 -# We also do it by hand because when we're throttled, the addon will exit -# the build immediately and skip the main script! -coverity_scan() { - if [ "${COVERITY_SCAN}" != "true" ] || \ - [ -n "${TRAVIS_TAG}" ] || \ - [ "${TRAVIS_PULL_REQUEST}" = "true" ] - then - echo "Skipping coverity scan." - return - fi - - export COVERITY_SCAN_PROJECT_NAME="${TRAVIS_REPO_SLUG}" - export COVERITY_SCAN_NOTIFICATION_EMAIL="google-breakpad-dev@googlegroups.com" - export COVERITY_SCAN_BUILD_COMMAND="make -j${JOBS}" - export COVERITY_SCAN_BUILD_COMMAND_PREPEND="git clean -q -x -d -f; git checkout -f; ./configure" - export COVERITY_SCAN_BRANCH_PATTERN="master" - - curl -s "https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh" | bash || : -} - -# Do an in-tree build and make sure tests pass. -build() { - ./configure --with-tests-as-root - make -j${JOBS} check VERBOSE=1 - make distclean -} - -# Do an out-of-tree build and make sure we can create a release tarball. -build_out_of_tree() { - mkdir -p build/native - pushd build/native >/dev/null - ../../configure --with-tests-as-root - make -j${JOBS} distcheck VERBOSE=1 - popd >/dev/null -} - -main() { - setup_env - build - build_out_of_tree - - # Do scans last as they like to dirty the tree and some tests - # expect a clean tree (like code style checks). - coverity_scan -} - -main "$@" diff --git a/scripts/travis-checkout.sh b/scripts/travis-checkout.sh deleted file mode 100755 index e5b33324d..000000000 --- a/scripts/travis-checkout.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -set -ex - -get_depot_tools() { - cd - git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git - PATH="$HOME/depot_tools:$PATH" -} - -gclient_sync() { - # Rename the source dir to match what gclient expects. - srcdir=$(basename "$TRAVIS_BUILD_DIR") - cd "${TRAVIS_BUILD_DIR}"/.. - mv "${srcdir}" src - gclient config --unmanaged https://github.com/google/breakpad.git - gclient sync -} - -main() { - get_depot_tools - gclient_sync -} - -main "$@" diff --git a/src/breakpad_googletest_includes.h b/src/breakpad_googletest_includes.h index 19a3e9807..4bc44a83b 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 4b59d917b..000000000 --- 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 29990c659..000000000 --- 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%': - '. - # 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 78cd1808a..000000000 --- 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 0b8077d2f..000000000 --- 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 6a459a646..000000000 --- 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 410a5a6f3..1946534ec 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 6c9b8bd64..950c03887 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. // diff --git a/src/client/ios/Breakpad.mm b/src/client/ios/Breakpad.mm index 11c517466..e2497461b 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. // diff --git a/src/client/ios/Breakpad.xcodeproj/project.pbxproj b/src/client/ios/Breakpad.xcodeproj/project.pbxproj index 2ed66d538..ca5f1f058 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 = ""; }; + 06D561E52700974500F9F2E8 /* encoding_util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = encoding_util.m; sourceTree = ""; }; 14569320182CE29F0029C465 /* ucontext_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ucontext_compat.h; sourceTree = ""; }; 14569322182CE2C10029C465 /* mach_vm_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_vm_compat.h; sourceTree = ""; }; 16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios_exception_minidump_generator.h; sourceTree = ""; }; @@ -116,6 +122,8 @@ CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = long_string_dictionary.cc; sourceTree = ""; }; CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = long_string_dictionary.h; sourceTree = ""; }; 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 = ""; }; + E69213D7265202570071B04F /* HTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPRequest.m; sourceTree = ""; }; /* 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 6c70c202f..40334592d 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 01fb5f13a..d03833e92 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 cb26449d0..58bec65ef 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. // @@ -27,9 +26,16 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include #include #include +#include + #include "client/mac/handler/minidump_generator.h" #include "client/ios/exception_handler_no_mach.h" @@ -62,7 +68,7 @@ const int kExceptionSignals[] = { }; const int kNumHandledSignals = sizeof(kExceptionSignals) / sizeof(kExceptionSignals[0]); -struct scoped_ptr old_handlers[kNumHandledSignals]; +struct std::unique_ptr old_handlers[kNumHandledSignals]; static union { #if USE_PROTECTED_ALLOCATIONS @@ -194,6 +200,9 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { if (gBreakpadAllocator) gBreakpadAllocator->Protect(); #endif + // uninstall our own crash handler so that when the signal is re-raised, the + // default handler takes over. + gProtectedData.handler->UninstallHandlers(); } bool ExceptionHandler::InstallHandlers() { diff --git a/src/client/ios/exception_handler_no_mach.h b/src/client/ios/exception_handler_no_mach.h index ec598dcf3..4d47b70b6 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. // @@ -36,7 +35,6 @@ #include #include "client/mac/handler/ucontext_compat.h" -#include "common/scoped_ptr.h" namespace google_breakpad { diff --git a/src/client/ios/handler/ios_exception_minidump_generator.h b/src/client/ios/handler/ios_exception_minidump_generator.h index e48444a72..cf72f00bb 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. // diff --git a/src/client/ios/handler/ios_exception_minidump_generator.mm b/src/client/ios/handler/ios_exception_minidump_generator.mm index 2a5d76d7b..053e36711 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. // diff --git a/src/client/linux/crash_generation/client_info.h b/src/client/linux/crash_generation/client_info.h index d0a184a63..6c4ecc3f7 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 d8bfbbad2..23daec819 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/linux/crash_generation/crash_generation_client.h" #include @@ -46,9 +49,11 @@ namespace { class CrashGenerationClientImpl : public CrashGenerationClient { public: explicit CrashGenerationClientImpl(int server_fd) : server_fd_(server_fd) {} - virtual ~CrashGenerationClientImpl() {} + CrashGenerationClientImpl(const CrashGenerationClientImpl&) = delete; + void operator=(const CrashGenerationClientImpl&) = delete; + ~CrashGenerationClientImpl() override = default; - virtual bool RequestDump(const void* blob, size_t blob_size) { + bool RequestDump(const void* blob, size_t blob_size) override { int fds[2]; if (sys_pipe(fds) < 0) return false; @@ -89,8 +94,6 @@ class CrashGenerationClientImpl : public CrashGenerationClient { private: int server_fd_; - - DISALLOW_COPY_AND_ASSIGN(CrashGenerationClientImpl); }; } // namespace @@ -98,7 +101,7 @@ class CrashGenerationClientImpl : public CrashGenerationClient { // static CrashGenerationClient* CrashGenerationClient::TryCreate(int server_fd) { if (server_fd < 0) - return NULL; + return nullptr; return new CrashGenerationClientImpl(server_fd); } diff --git a/src/client/linux/crash_generation/crash_generation_client.h b/src/client/linux/crash_generation/crash_generation_client.h index 4e68424ae..1e4a7a5e5 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. // @@ -30,8 +29,6 @@ #ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ #define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ -#include "common/basictypes.h" - #include namespace google_breakpad { @@ -42,8 +39,10 @@ namespace google_breakpad { // via a remote process. class CrashGenerationClient { public: - CrashGenerationClient() {} - virtual ~CrashGenerationClient() {} + CrashGenerationClient() = default; + CrashGenerationClient(const CrashGenerationClient&) = delete; + void operator=(const CrashGenerationClient&) = delete; + virtual ~CrashGenerationClient() = default; // Request the crash server to generate a dump. |blob| is an opaque // CrashContext pointer from exception_handler.h. @@ -55,9 +54,6 @@ class CrashGenerationClient { // The returned CrashGenerationClient* is owned by the caller of // this function. static CrashGenerationClient* TryCreate(int server_fd); - - private: - DISALLOW_COPY_AND_ASSIGN(CrashGenerationClient); }; } // namespace google_breakpad diff --git a/src/client/linux/crash_generation/crash_generation_server.cc b/src/client/linux/crash_generation/crash_generation_server.cc index 8332f59d4..f5f371a00 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -102,7 +105,7 @@ CrashGenerationServer::Start() control_pipe_in_ = control_pipe[0]; control_pipe_out_ = control_pipe[1]; - if (pthread_create(&thread_, NULL, + if (pthread_create(&thread_, nullptr, ThreadMain, reinterpret_cast(this))) return false; @@ -327,7 +330,7 @@ void* CrashGenerationServer::ThreadMain(void* arg) { reinterpret_cast(arg)->Run(); - return NULL; + return nullptr; } } // namespace google_breakpad diff --git a/src/client/linux/crash_generation/crash_generation_server.h b/src/client/linux/crash_generation/crash_generation_server.h index 483fb709b..5f4cb3a7a 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 c09e48ab0..759e7338e 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 07d9171a0..ea4b6f6a2 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 aae1dc13b..6288a056e 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/linux/dump_writer_common/thread_info.h" #include @@ -270,7 +273,70 @@ 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]; + + // Breakpad only supports RISCV32 with 32 bit floating point. + // Breakpad only supports RISCV64 with 64 bit floating point. +#if __riscv_xlen == 32 + for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++) + out->fpregs[i] = mcontext.__fpregs.__f.__f[i]; + out->fcsr = mcontext.__fpregs.__f.__fcsr; +#elif __riscv_xlen == 64 + for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++) + out->fpregs[i] = mcontext.__fpregs.__d.__f[i]; + out->fcsr = mcontext.__fpregs.__d.__fcsr; +#else +#error "Unexpected __riscv_xlen" +#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 fb216fa6d..af786bcc9 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 struct user_regs_struct regs; struct user_fpsimd_struct fpregs; -#elif defined(__mips__) +#elif defined(__mips__) || defined(__riscv) // Use the structure defined in . 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 6eec1be24..764976835 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/linux/dump_writer_common/ucontext_reader.h" #include "common/linux/linux_libc_support.h" @@ -254,6 +257,73 @@ 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]; + + // Breakpad only supports RISCV32 with 32 bit floating point. + // Breakpad only supports RISCV64 with 64 bit floating point. +#if __riscv_xlen == 32 + for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++) + out->fpregs[i] = uc->uc_mcontext.__fpregs.__f.__f[i]; + out->fcsr = uc->uc_mcontext.__fpregs.__f.__fcsr; +#elif __riscv_xlen == 64 + for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++) + out->fpregs[i] = uc->uc_mcontext.__fpregs.__d.__f[i]; + out->fcsr = uc->uc_mcontext.__fpregs.__d.__fcsr; +#else +#error "Unexpected __riscv_xlen" +#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 7d4100881..60cbf9004 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. // diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc index ca353c409..c65d03932 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. // @@ -63,6 +62,10 @@ // alternative malloc. Each function should have comment above it detailing the // context which it runs in. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/linux/handler/exception_handler.h" #include @@ -138,16 +141,16 @@ 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(16384, SIGSTKSZ); // Only set an alternative stack if there isn't already one, or if the current // one is too small. - if (sys_sigaltstack(NULL, &old_stack) == -1 || !old_stack.ss_sp || + if (sys_sigaltstack(nullptr, &old_stack) == -1 || !old_stack.ss_sp || old_stack.ss_size < kSigStackSize) { new_stack.ss_sp = calloc(1, kSigStackSize); new_stack.ss_size = kSigStackSize; - if (sys_sigaltstack(&new_stack, NULL) == -1) { + if (sys_sigaltstack(&new_stack, nullptr) == -1) { free(new_stack.ss_sp); return; } @@ -161,19 +164,19 @@ void RestoreAlternateStackLocked() { return; stack_t current_stack; - if (sys_sigaltstack(NULL, ¤t_stack) == -1) + if (sys_sigaltstack(nullptr, ¤t_stack) == -1) return; // Only restore the old_stack if the current alternative stack is the one // installed by the call to InstallAlternateStackLocked. if (current_stack.ss_sp == new_stack.ss_sp) { if (old_stack.ss_sp) { - if (sys_sigaltstack(&old_stack, NULL) == -1) + if (sys_sigaltstack(&old_stack, nullptr) == -1) return; } else { stack_t disable_stack; disable_stack.ss_flags = SS_DISABLE; - if (sys_sigaltstack(&disable_stack, NULL) == -1) + if (sys_sigaltstack(&disable_stack, nullptr) == -1) return; } } @@ -194,7 +197,7 @@ void InstallDefaultHandler(int sig) { sys_sigemptyset(&sa.sa_mask); sa.sa_handler_ = SIG_DFL; sa.sa_flags = SA_RESTART; - sys_rt_sigaction(sig, &sa, NULL, sizeof(kernel_sigset_t)); + sys_rt_sigaction(sig, &sa, nullptr, sizeof(kernel_sigset_t)); #else signal(sig, SIG_DFL); #endif @@ -203,7 +206,7 @@ void InstallDefaultHandler(int sig) { // The global exception handler stack. This is needed because there may exist // multiple ExceptionHandler instances in a process. Each will have itself // registered in this stack. -std::vector* g_handler_stack_ = NULL; +std::vector* g_handler_stack_ = nullptr; pthread_mutex_t g_handler_stack_mutex_ = PTHREAD_MUTEX_INITIALIZER; // sizeof(CrashContext) can be too big w.r.t the size of alternatate stack @@ -226,7 +229,7 @@ ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor, callback_(callback), callback_context_(callback_context), minidump_descriptor_(descriptor), - crash_handler_(NULL) { + crash_handler_(nullptr) { if (server_fd >= 0) crash_generation_client_.reset(CrashGenerationClient::TryCreate(server_fd)); @@ -263,7 +266,7 @@ ExceptionHandler::~ExceptionHandler() { g_handler_stack_->erase(handler); if (g_handler_stack_->empty()) { delete g_handler_stack_; - g_handler_stack_ = NULL; + g_handler_stack_ = nullptr; RestoreAlternateStackLocked(); RestoreHandlersLocked(); } @@ -278,7 +281,7 @@ bool ExceptionHandler::InstallHandlersLocked() { // Fail if unable to store all the old handlers. for (int i = 0; i < kNumHandledSignals; ++i) { - if (sigaction(kExceptionSignals[i], NULL, &old_handlers[i]) == -1) + if (sigaction(kExceptionSignals[i], nullptr, &old_handlers[i]) == -1) return false; } @@ -294,7 +297,7 @@ bool ExceptionHandler::InstallHandlersLocked() { sa.sa_flags = SA_ONSTACK | SA_SIGINFO; for (int i = 0; i < kNumHandledSignals; ++i) { - if (sigaction(kExceptionSignals[i], &sa, NULL) == -1) { + if (sigaction(kExceptionSignals[i], &sa, nullptr) == -1) { // At this point it is impractical to back out changes, and so failure to // install a signal is intentionally ignored. } @@ -311,7 +314,7 @@ void ExceptionHandler::RestoreHandlersLocked() { return; for (int i = 0; i < kNumHandledSignals; ++i) { - if (sigaction(kExceptionSignals[i], &old_handlers[i], NULL) == -1) { + if (sigaction(kExceptionSignals[i], &old_handlers[i], nullptr) == -1) { InstallDefaultHandler(kExceptionSignals[i]); } } @@ -352,7 +355,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { // This forces the signal to be thrown again, but this time the kernel // will call the function with the right arguments. struct sigaction cur_handler; - if (sigaction(sig, NULL, &cur_handler) == 0 && + if (sigaction(sig, nullptr, &cur_handler) == 0 && cur_handler.sa_sigaction == SignalHandler && (cur_handler.sa_flags & SA_SIGINFO) == 0) { // Reset signal handler with the right flags. @@ -362,7 +365,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { cur_handler.sa_sigaction = SignalHandler; cur_handler.sa_flags = SA_ONSTACK | SA_SIGINFO; - if (sigaction(sig, &cur_handler, NULL) == -1) { + if (sigaction(sig, &cur_handler, nullptr) == -1) { // When resetting the handler fails, try to reset the // default one to avoid an infinite loop here. InstallDefaultHandler(sig); @@ -444,7 +447,8 @@ bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) { // Allow ourselves to be dumped if the signal is trusted. bool signal_trusted = info->si_code > 0; bool signal_pid_trusted = info->si_code == SI_USER || - info->si_code == SI_TKILL; + info->si_code == SI_TKILL || + info->si_code == SI_QUEUE; if (signal_trusted || (signal_pid_trusted && info->si_pid == getpid())) { sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); } @@ -461,10 +465,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, @@ -472,7 +473,7 @@ bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) { } #endif g_crash_context_.tid = syscall(__NR_gettid); - if (crash_handler_ != NULL) { + if (crash_handler_ != nullptr) { if (crash_handler_(&g_crash_context_, sizeof(g_crash_context_), callback_context_)) { return true; @@ -536,8 +537,8 @@ bool ExceptionHandler::GenerateDump(CrashContext* context) { } const pid_t child = sys_clone( - ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL, - NULL); + ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, nullptr, + nullptr, nullptr); if (child == -1) { sys_close(fdes[0]); sys_close(fdes[1]); @@ -645,7 +646,8 @@ bool ExceptionHandler::WriteMinidump(const string& dump_path, MinidumpCallback callback, void* callback_context) { MinidumpDescriptor descriptor(dump_path); - ExceptionHandler eh(descriptor, NULL, callback, callback_context, false, -1); + ExceptionHandler eh(descriptor, nullptr, callback, callback_context, false, + -1); return eh.WriteMinidump(); } @@ -701,8 +703,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 +727,11 @@ bool ExceptionHandler::WriteMinidump() { #elif defined(__mips__) context.siginfo.si_addr = reinterpret_cast(context.context.uc_mcontext.pc); +#elif defined(__riscv) + context.siginfo.si_addr = + reinterpret_cast(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 f80843ea7..adeee7069 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. // @@ -35,15 +34,24 @@ #include #include +#include #include #include "client/linux/crash_generation/crash_generation_client.h" #include "client/linux/handler/minidump_descriptor.h" #include "client/linux/minidump_writer/minidump_writer.h" -#include "common/scoped_ptr.h" #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 @@ -192,17 +200,14 @@ 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 }; // Returns whether out-of-process dump generation is used or not. bool IsOutOfProcess() const { - return crash_generation_client_.get() != NULL; + return crash_generation_client_.get() != nullptr; } // Add information about a memory mapping. This can be used if @@ -247,7 +252,7 @@ class ExceptionHandler { const MinidumpCallback callback_; void* const callback_context_; - scoped_ptr crash_generation_client_; + std::unique_ptr crash_generation_client_; MinidumpDescriptor minidump_descriptor_; diff --git a/src/client/linux/handler/exception_handler_unittest.cc b/src/client/linux/handler/exception_handler_unittest.cc index 35dcbfd4d..876cb2df8 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -40,6 +43,7 @@ #include #endif +#include #include #include "breakpad_googletest_includes.h" @@ -48,6 +52,7 @@ #include "common/linux/eintr_wrapper.h" #include "common/linux/ignore_ret.h" #include "common/linux/linux_libc_support.h" +#include "common/scoped_ptr.h" #include "common/tests/auto_tempdir.h" #include "common/using_std_string.h" #include "third_party/lss/linux_syscall_support.h" @@ -119,7 +124,7 @@ class ExceptionHandlerTest : public ::testing::Test { } void TearDown() { - sigaction(SIGCHLD, &old_action, NULL); + sigaction(SIGCHLD, &old_action, nullptr); } struct sigaction old_action; @@ -160,7 +165,7 @@ void ReadMinidumpPathFromPipe(int fd, string* path) { TEST(ExceptionHandlerTest, SimpleWithPath) { AutoTempDir temp_dir; ExceptionHandler handler( - MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); + MinidumpDescriptor(temp_dir.path()), nullptr, nullptr, nullptr, true, -1); EXPECT_EQ(temp_dir.path(), handler.minidump_descriptor().directory()); string temp_subdir = temp_dir.path() + "/subdir"; handler.set_minidump_descriptor(MinidumpDescriptor(temp_subdir)); @@ -171,7 +176,8 @@ TEST(ExceptionHandlerTest, SimpleWithFD) { AutoTempDir temp_dir; string path; const int fd = CreateTMPFile(temp_dir.path(), &path); - ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, true, -1); + ExceptionHandler handler( + MinidumpDescriptor(fd), nullptr, nullptr, nullptr, true, -1); close(fd); } @@ -221,15 +227,16 @@ void ChildCrash(bool use_fd) { const pid_t child = fork(); if (child == 0) { { - google_breakpad::scoped_ptr handler; + std::unique_ptr handler; if (use_fd) { handler.reset(new ExceptionHandler(MinidumpDescriptor(minidump_fd), - NULL, NULL, NULL, true, -1)); + nullptr, nullptr, nullptr, true, + -1)); } else { close(fds[0]); // Close the reading end. void* fd_param = reinterpret_cast(fds[1]); handler.reset(new ExceptionHandler(MinidumpDescriptor(temp_dir.path()), - NULL, DoneCallback, fd_param, + nullptr, DoneCallback, fd_param, true, -1)); } // Crash with the exception handler in scope. @@ -261,14 +268,14 @@ TEST(ExceptionHandlerTest, ChildCrashWithFD) { #if !defined(__ANDROID_API__) || __ANDROID_API__ >= __ANDROID_API_N__ static void* SleepFunction(void* unused) { while (true) usleep(1000000); - return NULL; + return nullptr; } static void* CrashFunction(void* b_ptr) { pthread_barrier_t* b = reinterpret_cast(b_ptr); pthread_barrier_wait(b); DoNullPointerDereference(); - return NULL; + return nullptr; } // Tests that concurrent crashes do not enter a loop by alternately triggering @@ -277,9 +284,9 @@ TEST(ExceptionHandlerTest, ParallelChildCrashesDontHang) { AutoTempDir temp_dir; const pid_t child = fork(); if (child == 0) { - google_breakpad::scoped_ptr handler( - new ExceptionHandler(MinidumpDescriptor(temp_dir.path()), NULL, NULL, - NULL, true, -1)); + std::unique_ptr handler( + new ExceptionHandler(MinidumpDescriptor(temp_dir.path()), nullptr, + nullptr, nullptr, true, -1)); // We start a number of threads to make sure handling the signal takes // enough time for the second thread to enter the signal handler. @@ -287,8 +294,8 @@ TEST(ExceptionHandlerTest, ParallelChildCrashesDontHang) { google_breakpad::scoped_array sleep_threads( new pthread_t[num_sleep_threads]); for (int i = 0; i < num_sleep_threads; ++i) { - ASSERT_EQ(0, pthread_create(&sleep_threads[i], NULL, SleepFunction, - NULL)); + ASSERT_EQ(0, pthread_create(&sleep_threads[i], nullptr, SleepFunction, + nullptr)); } int num_crash_threads = 2; @@ -296,18 +303,33 @@ TEST(ExceptionHandlerTest, ParallelChildCrashesDontHang) { new pthread_t[num_crash_threads]); // Barrier to synchronize crashing both threads at the same time. pthread_barrier_t b; - ASSERT_EQ(0, pthread_barrier_init(&b, NULL, num_crash_threads + 1)); + ASSERT_EQ(0, pthread_barrier_init(&b, nullptr, num_crash_threads + 1)); for (int i = 0; i < num_crash_threads; ++i) { - ASSERT_EQ(0, pthread_create(&crash_threads[i], NULL, CrashFunction, &b)); + ASSERT_EQ(0, + pthread_create(&crash_threads[i], nullptr, CrashFunction, &b)); } pthread_barrier_wait(&b); for (int i = 0; i < num_crash_threads; ++i) { - ASSERT_EQ(0, pthread_join(crash_threads[i], NULL)); + ASSERT_EQ(0, pthread_join(crash_threads[i], nullptr)); + } + } + + // 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); } } - // Wait a while until the child should have crashed. - usleep(1000000); // Kill the child if it is still running. kill(child, SIGKILL); @@ -356,14 +378,14 @@ static bool InstallRaiseSIGKILL() { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = RaiseSIGKILL; - return sigaction(SIGSEGV, &sa, NULL) != -1; + return sigaction(SIGSEGV, &sa, nullptr) != -1; } static void CrashWithCallbacks(ExceptionHandler::FilterCallback filter, ExceptionHandler::MinidumpCallback done, - string path) { + const string& path) { ExceptionHandler handler( - MinidumpDescriptor(path), filter, done, NULL, true, -1); + MinidumpDescriptor(path), filter, done, nullptr, true, -1); // Crash with the exception handler in scope. DoNullPointerDereference(); } @@ -374,7 +396,7 @@ TEST(ExceptionHandlerTest, RedeliveryOnFilterCallbackFalse) { const pid_t child = fork(); if (child == 0) { ASSERT_TRUE(InstallRaiseSIGKILL()); - CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path()); + CrashWithCallbacks(FilterCallbackReturnFalse, nullptr, temp_dir.path()); } ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); @@ -386,7 +408,7 @@ TEST(ExceptionHandlerTest, RedeliveryOnDoneCallbackFalse) { const pid_t child = fork(); if (child == 0) { ASSERT_TRUE(InstallRaiseSIGKILL()); - CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path()); + CrashWithCallbacks(nullptr, DoneCallbackReturnFalse, temp_dir.path()); } ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); @@ -398,7 +420,7 @@ TEST(ExceptionHandlerTest, NoRedeliveryOnDoneCallbackTrue) { const pid_t child = fork(); if (child == 0) { ASSERT_TRUE(InstallRaiseSIGKILL()); - CrashWithCallbacks(NULL, DoneCallbackReturnTrue, temp_dir.path()); + CrashWithCallbacks(nullptr, DoneCallbackReturnTrue, temp_dir.path()); } ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); @@ -410,7 +432,7 @@ TEST(ExceptionHandlerTest, NoRedeliveryOnFilterCallbackTrue) { const pid_t child = fork(); if (child == 0) { ASSERT_TRUE(InstallRaiseSIGKILL()); - CrashWithCallbacks(FilterCallbackReturnTrue, NULL, temp_dir.path()); + CrashWithCallbacks(FilterCallbackReturnTrue, nullptr, temp_dir.path()); } ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); @@ -425,7 +447,7 @@ TEST(ExceptionHandlerTest, RedeliveryToDefaultHandler) { // are undesirable in this child. signal(SIGSEGV, SIG_DFL); - CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path()); + CrashWithCallbacks(FilterCallbackReturnFalse, nullptr, temp_dir.path()); } // As RaiseSIGKILL wasn't installed, the redelivery should just kill the child @@ -447,8 +469,8 @@ TEST(ExceptionHandlerTest, RedeliveryOnBadSignalHandlerFlag) { // Create a new exception handler, this installs a new SIGSEGV // handler, after saving the old one. ExceptionHandler handler( - MinidumpDescriptor(temp_dir.path()), NULL, - DoneCallbackReturnFalse, NULL, true, -1); + MinidumpDescriptor(temp_dir.path()), nullptr, + DoneCallbackReturnFalse, nullptr, true, -1); // Install the default SIGSEGV handler, saving the current one. // Then re-install the current one with 'signal', this loses the @@ -472,12 +494,12 @@ TEST(ExceptionHandlerTest, StackedHandlersDeliveredToTop) { const pid_t child = fork(); if (child == 0) { ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()), - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, true, -1); - CrashWithCallbacks(NULL, DoneCallbackRaiseSIGKILL, temp_dir.path()); + CrashWithCallbacks(nullptr, DoneCallbackRaiseSIGKILL, temp_dir.path()); } ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); } @@ -488,12 +510,12 @@ TEST(ExceptionHandlerTest, StackedHandlersNotDeliveredToBottom) { const pid_t child = fork(); if (child == 0) { ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()), - NULL, + nullptr, DoneCallbackRaiseSIGKILL, - NULL, + nullptr, true, -1); - CrashWithCallbacks(NULL, NULL, temp_dir.path()); + CrashWithCallbacks(nullptr, nullptr, temp_dir.path()); } ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); } @@ -504,12 +526,12 @@ TEST(ExceptionHandlerTest, StackedHandlersFilteredToBottom) { const pid_t child = fork(); if (child == 0) { ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()), - NULL, + nullptr, DoneCallbackRaiseSIGKILL, - NULL, + nullptr, true, -1); - CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path()); + CrashWithCallbacks(FilterCallbackReturnFalse, nullptr, temp_dir.path()); } ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); } @@ -520,12 +542,12 @@ TEST(ExceptionHandlerTest, StackedHandlersUnhandledToBottom) { const pid_t child = fork(); if (child == 0) { ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()), - NULL, + nullptr, DoneCallbackRaiseSIGKILL, - NULL, + nullptr, true, -1); - CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path()); + CrashWithCallbacks(nullptr, DoneCallbackReturnFalse, temp_dir.path()); } ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); } @@ -543,7 +565,8 @@ TEST(ExceptionHandlerTest, FirstChanceHandlerRuns) { const pid_t child = fork(); if (child == 0) { ExceptionHandler handler( - MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); + MinidumpDescriptor(temp_dir.path()), nullptr, nullptr, nullptr, true, + -1); google_breakpad::SetFirstChanceExceptionHandler(SimpleFirstChanceHandler); DoNullPointerDereference(); } @@ -580,12 +603,12 @@ TEST(ExceptionHandlerTest, InstructionPointerMemory) { const pid_t child = fork(); if (child == 0) { close(fds[0]); - ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, + ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), nullptr, DoneCallback, reinterpret_cast(fds[1]), true, -1); // Get some executable memory. char* memory = - reinterpret_cast(mmap(NULL, + reinterpret_cast(mmap(nullptr, kMemorySize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, @@ -672,12 +695,12 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { const pid_t child = fork(); if (child == 0) { close(fds[0]); - ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, + ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), nullptr, DoneCallback, reinterpret_cast(fds[1]), true, -1); // Get some executable memory. char* memory = - reinterpret_cast(mmap(NULL, + reinterpret_cast(mmap(nullptr, kMemorySize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, @@ -763,12 +786,12 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { const pid_t child = fork(); if (child == 0) { close(fds[0]); - ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, + ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), nullptr, DoneCallback, reinterpret_cast(fds[1]), true, -1); // Get some executable memory. char* memory = - reinterpret_cast(mmap(NULL, + reinterpret_cast(mmap(nullptr, kMemorySize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, @@ -848,7 +871,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) { const pid_t child = fork(); if (child == 0) { close(fds[0]); - ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, + ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), nullptr, DoneCallback, reinterpret_cast(fds[1]), true, -1); // Try calling a NULL pointer. @@ -856,7 +879,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) { // Volatile markings are needed to keep Clang from generating invalid // opcodes. See http://crbug.com/498354 for details. volatile void_function memory_function = - reinterpret_cast(NULL); + static_cast(nullptr); memory_function(); // not reached exit(1); @@ -924,7 +947,7 @@ TEST(ExceptionHandlerTest, ModuleInfo) { // Get some memory. char* memory = - reinterpret_cast(mmap(NULL, + reinterpret_cast(mmap(nullptr, kMemorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, @@ -935,7 +958,7 @@ TEST(ExceptionHandlerTest, ModuleInfo) { AutoTempDir temp_dir; ExceptionHandler handler( - MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); + MinidumpDescriptor(temp_dir.path()), nullptr, nullptr, nullptr, true, -1); // Add info about the anonymous memory mapping. handler.AddMappingInfo(kMemoryName, @@ -1029,7 +1052,7 @@ TEST(ExceptionHandlerTest, ExternalDumper) { const pid_t child = fork(); if (child == 0) { close(fds[0]); - ExceptionHandler handler(MinidumpDescriptor("/tmp1"), NULL, NULL, + ExceptionHandler handler(MinidumpDescriptor("/tmp1"), nullptr, nullptr, reinterpret_cast(fds[1]), true, -1); handler.set_crash_handler(CrashHandler); DoNullPointerDereference(); @@ -1095,8 +1118,8 @@ TEST(ExceptionHandlerTest, ExternalDumper) { TEST(ExceptionHandlerTest, WriteMinidumpExceptionStream) { AutoTempDir temp_dir; - ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL, - NULL, false, -1); + ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), nullptr, + nullptr, nullptr, false, -1); ASSERT_TRUE(handler.WriteMinidump()); string minidump_path = handler.minidump_descriptor().path(); @@ -1116,7 +1139,8 @@ TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithFD) { AutoTempDir temp_dir; string path; const int fd = CreateTMPFile(temp_dir.path(), &path); - ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, false, -1); + ExceptionHandler handler( + MinidumpDescriptor(fd), nullptr, nullptr, nullptr, false, -1); ASSERT_TRUE(handler.WriteMinidump()); // Check by the size of the data written to the FD that a minidump was // generated. @@ -1131,8 +1155,8 @@ TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithFD) { TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithPath) { AutoTempDir temp_dir; - ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL, - NULL, false, -1); + ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), nullptr, + nullptr, nullptr, false, -1); ASSERT_TRUE(handler.WriteMinidump()); const MinidumpDescriptor& minidump_1 = handler.minidump_descriptor(); @@ -1176,7 +1200,7 @@ TEST(ExceptionHandlerTest, AdditionalMemory) { AutoTempDir temp_dir; ExceptionHandler handler( - MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); + MinidumpDescriptor(temp_dir.path()), nullptr, nullptr, nullptr, true, -1); // Add the memory region to the list of memory to be included. handler.RegisterAppMemory(memory, kMemorySize); @@ -1215,7 +1239,7 @@ TEST(ExceptionHandlerTest, AdditionalMemoryRemove) { AutoTempDir temp_dir; ExceptionHandler handler( - MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); + MinidumpDescriptor(temp_dir.path()), nullptr, nullptr, nullptr, true, -1); // Add the memory region to the list of memory to be included. handler.RegisterAppMemory(memory, kMemorySize); diff --git a/src/client/linux/handler/microdump_extra_info.h b/src/client/linux/handler/microdump_extra_info.h index bf01f0c7b..6418c1304 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. // @@ -41,10 +40,10 @@ struct MicrodumpExtraInfo { const char* process_type; MicrodumpExtraInfo() - : build_fingerprint(NULL), - product_info(NULL), - gpu_fingerprint(NULL), - process_type(NULL) {} + : build_fingerprint(nullptr), + product_info(nullptr), + gpu_fingerprint(nullptr), + process_type(nullptr) {} }; } diff --git a/src/client/linux/handler/minidump_descriptor.cc b/src/client/linux/handler/minidump_descriptor.cc index bd94474e9..7b4c721f0 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. // @@ -27,6 +26,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include #include #include "client/linux/handler/minidump_descriptor.h" @@ -43,7 +47,7 @@ MinidumpDescriptor::MinidumpDescriptor(const MinidumpDescriptor& descriptor) : mode_(descriptor.mode_), fd_(descriptor.fd_), directory_(descriptor.directory_), - c_path_(NULL), + c_path_(nullptr), size_limit_(descriptor.size_limit_), address_within_principal_mapping_( descriptor.address_within_principal_mapping_), @@ -67,7 +71,7 @@ MinidumpDescriptor& MinidumpDescriptor::operator=( path_.clear(); if (c_path_) { // This descriptor already had a path set, so generate a new one. - c_path_ = NULL; + c_path_ = nullptr; UpdatePath(); } size_limit_ = descriptor.size_limit_; diff --git a/src/client/linux/handler/minidump_descriptor.h b/src/client/linux/handler/minidump_descriptor.h index c7e4f2b37..72d119d9e 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. // @@ -31,6 +30,7 @@ #define CLIENT_LINUX_HANDLER_MINIDUMP_DESCRIPTOR_H_ #include +#include #include #include @@ -61,7 +61,7 @@ class MinidumpDescriptor { : mode_(kWriteMinidumpToFile), fd_(-1), directory_(directory), - c_path_(NULL), + c_path_(nullptr), size_limit_(-1), address_within_principal_mapping_(0), skip_dump_if_principal_mapping_not_referenced_(false), @@ -72,7 +72,7 @@ class MinidumpDescriptor { explicit MinidumpDescriptor(int fd) : mode_(kWriteMinidumpToFd), fd_(fd), - c_path_(NULL), + c_path_(nullptr), size_limit_(-1), address_within_principal_mapping_(0), skip_dump_if_principal_mapping_not_referenced_(false), diff --git a/src/client/linux/log/log.cc b/src/client/linux/log/log.cc index 318794095..2a48d7fea 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/linux/log/log.h" #if defined(__ANDROID__) diff --git a/src/client/linux/log/log.h b/src/client/linux/log/log.h index f94bbd5fb..93aeffcf4 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 fa3c1713a..903a29d6e 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. // @@ -30,8 +29,14 @@ // This translation unit generates microdumps into the console (logcat on // Android). See crbug.com/410294 for more info and design docs. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/linux/microdump_writer/microdump_writer.h" +#include + #include #include @@ -49,8 +54,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; @@ -137,9 +142,9 @@ class MicrodumpWriter { bool sanitize_stack, const MicrodumpExtraInfo& microdump_extra_info, LinuxDumper* dumper) - : ucontext_(context ? &context->context : NULL), -#if !defined(__ARM_EABI__) && !defined(__mips__) - float_state_(context ? &context->float_state : NULL), + : ucontext_(context ? &context->context : nullptr), +#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE + float_state_(context ? &context->float_state : nullptr), #endif dumper_(dumper), mapping_list_(mappings), @@ -148,8 +153,8 @@ class MicrodumpWriter { address_within_principal_mapping_(address_within_principal_mapping), sanitize_stack_(sanitize_stack), microdump_extra_info_(microdump_extra_info), - log_line_(NULL), - stack_copy_(NULL), + log_line_(nullptr), + stack_copy_(nullptr), stack_len_(0), stack_lower_bound_(0), stack_pointer_(0) { @@ -336,9 +341,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 +422,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_); @@ -592,7 +605,7 @@ class MicrodumpWriter { continue; } - DumpModule(mapping, true, i, NULL); + DumpModule(mapping, true, i, nullptr); } // Next write all the mappings provided by the caller for (MappingList::const_iterator iter = mapping_list_.begin(); @@ -605,7 +618,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_; @@ -643,7 +656,7 @@ bool WriteMicrodump(pid_t crashing_process, bool sanitize_stack, const MicrodumpExtraInfo& microdump_extra_info) { LinuxPtraceDumper dumper(crashing_process); - const ExceptionHandler::CrashContext* context = NULL; + const ExceptionHandler::CrashContext* context = nullptr; if (blob) { if (blob_size != sizeof(ExceptionHandler::CrashContext)) return false; diff --git a/src/client/linux/microdump_writer/microdump_writer.h b/src/client/linux/microdump_writer/microdump_writer.h index a1e53df62..47b03e8f2 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 6339ac0cd..93172824c 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -43,7 +46,6 @@ #include "common/linux/breakpad_getcontext.h" #include "common/linux/eintr_wrapper.h" #include "common/linux/ignore_ret.h" -#include "common/scoped_ptr.h" #include "common/tests/auto_tempdir.h" #include "common/using_std_string.h" @@ -166,7 +168,8 @@ void ExtractMicrodumpStackContents(const string& microdump_content, result->reserve(result->size() + data.size() / 2); for (size_t i = 0; i < data.size(); i += 2) { std::string byte = data.substr(i, 2); - result->push_back(static_cast(strtoul(byte.c_str(), NULL, 16))); + result->push_back( + static_cast(strtoul(byte.c_str(), nullptr, 16))); } } } @@ -397,7 +400,7 @@ TEST(MicrodumpWriterTest, NoProductInfo) { MappingList no_mappings; const MicrodumpExtraInfo kMicrodumpExtraInfoNoProductInfo( - MakeMicrodumpExtraInfo(kBuildFingerprint, NULL, kGPUFingerprint)); + MakeMicrodumpExtraInfo(kBuildFingerprint, nullptr, kGPUFingerprint)); CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoProductInfo, &buf); ASSERT_TRUE(ContainsMicrodump(buf)); @@ -412,7 +415,7 @@ TEST(MicrodumpWriterTest, NoGPUInfo) { MappingList no_mappings; const MicrodumpExtraInfo kMicrodumpExtraInfoNoGPUInfo( - MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, NULL)); + MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, nullptr)); CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoGPUInfo, &buf); ASSERT_TRUE(ContainsMicrodump(buf)); diff --git a/src/client/linux/minidump_writer/cpu_set.h b/src/client/linux/minidump_writer/cpu_set.h index 1cca9aa5a..9023d3a5b 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. // @@ -80,7 +79,7 @@ class CpuSet { size_t item_len = static_cast(p_end - p); const char* item_next = static_cast(my_memchr(p, ',', item_len)); - if (item_next != NULL) { + if (item_next != nullptr) { p = item_next + 1; item_len = static_cast(item_next - item); } else { diff --git a/src/client/linux/minidump_writer/cpu_set_unittest.cc b/src/client/linux/minidump_writer/cpu_set_unittest.cc index e2274bd17..b99e98de3 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -36,7 +39,7 @@ #include "breakpad_googletest_includes.h" #include "client/linux/minidump_writer/cpu_set.h" -#include "common/linux/tests/auto_testfile.h" +#include "common/linux/scoped_tmpfile.h" using namespace google_breakpad; @@ -44,15 +47,6 @@ namespace { typedef testing::Test CpuSetTest; -// Helper class to write test text file to a temporary file and return -// its file descriptor. -class ScopedTestFile : public AutoTestFile { -public: - explicit ScopedTestFile(const char* text) - : AutoTestFile("cpu_set", text) { - } -}; - } TEST(CpuSetTest, EmptyCount) { @@ -61,8 +55,8 @@ TEST(CpuSetTest, EmptyCount) { } TEST(CpuSetTest, OneCpu) { - ScopedTestFile file("10"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("10")); CpuSet set; ASSERT_TRUE(set.ParseSysFile(file.GetFd())); @@ -70,8 +64,8 @@ TEST(CpuSetTest, OneCpu) { } TEST(CpuSetTest, OneCpuTerminated) { - ScopedTestFile file("10\n"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("10\n")); CpuSet set; ASSERT_TRUE(set.ParseSysFile(file.GetFd())); @@ -79,8 +73,8 @@ TEST(CpuSetTest, OneCpuTerminated) { } TEST(CpuSetTest, TwoCpusWithComma) { - ScopedTestFile file("1,10"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("1,10")); CpuSet set; ASSERT_TRUE(set.ParseSysFile(file.GetFd())); @@ -88,8 +82,8 @@ TEST(CpuSetTest, TwoCpusWithComma) { } TEST(CpuSetTest, TwoCpusWithRange) { - ScopedTestFile file("1-2"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("1-2")); CpuSet set; ASSERT_TRUE(set.ParseSysFile(file.GetFd())); @@ -97,8 +91,8 @@ TEST(CpuSetTest, TwoCpusWithRange) { } TEST(CpuSetTest, TenCpusWithRange) { - ScopedTestFile file("9-18"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("9-18")); CpuSet set; ASSERT_TRUE(set.ParseSysFile(file.GetFd())); @@ -106,8 +100,8 @@ TEST(CpuSetTest, TenCpusWithRange) { } TEST(CpuSetTest, MultiItems) { - ScopedTestFile file("0, 2-4, 128"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("0, 2-4, 128")); CpuSet set; ASSERT_TRUE(set.ParseSysFile(file.GetFd())); @@ -115,14 +109,16 @@ TEST(CpuSetTest, MultiItems) { } TEST(CpuSetTest, IntersectWith) { - ScopedTestFile file1("9-19"); - ASSERT_TRUE(file1.IsOk()); + ScopedTmpFile file1; + ASSERT_TRUE(file1.InitString("9-19")); + CpuSet set1; ASSERT_TRUE(set1.ParseSysFile(file1.GetFd())); ASSERT_EQ(11, set1.GetCount()); - ScopedTestFile file2("16-24"); - ASSERT_TRUE(file2.IsOk()); + ScopedTmpFile file2; + ASSERT_TRUE(file2.InitString("16-24")); + CpuSet set2; ASSERT_TRUE(set2.ParseSysFile(file2.GetFd())); ASSERT_EQ(9, set2.GetCount()); @@ -133,8 +129,9 @@ TEST(CpuSetTest, IntersectWith) { } TEST(CpuSetTest, SelfIntersection) { - ScopedTestFile file1("9-19"); - ASSERT_TRUE(file1.IsOk()); + ScopedTmpFile file1; + ASSERT_TRUE(file1.InitString("9-19")); + CpuSet set1; ASSERT_TRUE(set1.ParseSysFile(file1.GetFd())); ASSERT_EQ(11, set1.GetCount()); @@ -144,14 +141,16 @@ TEST(CpuSetTest, SelfIntersection) { } TEST(CpuSetTest, EmptyIntersection) { - ScopedTestFile file1("0-19"); - ASSERT_TRUE(file1.IsOk()); + ScopedTmpFile file1; + ASSERT_TRUE(file1.InitString("0-19")); + CpuSet set1; ASSERT_TRUE(set1.ParseSysFile(file1.GetFd())); ASSERT_EQ(20, set1.GetCount()); - ScopedTestFile file2("20-39"); - ASSERT_TRUE(file2.IsOk()); + ScopedTmpFile file2; + ASSERT_TRUE(file2.InitString("20-39")); + CpuSet set2; ASSERT_TRUE(set2.ParseSysFile(file2.GetFd())); ASSERT_EQ(20, set2.GetCount()); diff --git a/src/client/linux/minidump_writer/directory_reader.h b/src/client/linux/minidump_writer/directory_reader.h index a4bde1803..62bba8779 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 7292a6368..975ace9e7 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -48,7 +51,7 @@ TEST(DirectoryReaderTest, CompareResults) { std::set dent_set; DIR* const dir = opendir("/proc/self"); - ASSERT_TRUE(dir != NULL); + ASSERT_TRUE(dir != nullptr); struct dirent* dent; while ((dent = readdir(dir))) diff --git a/src/client/linux/minidump_writer/line_reader.h b/src/client/linux/minidump_writer/line_reader.h index 9fc4b7cc8..d54a67d04 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. // diff --git a/src/client/linux/minidump_writer/line_reader_unittest.cc b/src/client/linux/minidump_writer/line_reader_unittest.cc index e1ac445ae..bc1f9d399 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. // @@ -27,13 +26,17 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include #include "client/linux/minidump_writer/line_reader.h" #include "breakpad_googletest_includes.h" -#include "common/linux/tests/auto_testfile.h" +#include "common/linux/scoped_tmpfile.h" using namespace google_breakpad; @@ -41,22 +44,11 @@ namespace { typedef testing::Test LineReaderTest; -class ScopedTestFile : public AutoTestFile { -public: - explicit ScopedTestFile(const char* text) - : AutoTestFile("line_reader", text) { - } - - ScopedTestFile(const char* text, size_t text_len) - : AutoTestFile("line_reader", text, text_len) { - } -}; - } TEST(LineReaderTest, EmptyFile) { - ScopedTestFile file(""); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("")); LineReader reader(file.GetFd()); const char* line; @@ -65,8 +57,8 @@ TEST(LineReaderTest, EmptyFile) { } TEST(LineReaderTest, OneLineTerminated) { - ScopedTestFile file("a\n"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("a\n")); LineReader reader(file.GetFd()); const char* line; @@ -81,8 +73,8 @@ TEST(LineReaderTest, OneLineTerminated) { } TEST(LineReaderTest, OneLine) { - ScopedTestFile file("a"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("a")); LineReader reader(file.GetFd()); const char* line; @@ -97,8 +89,8 @@ TEST(LineReaderTest, OneLine) { } TEST(LineReaderTest, TwoLinesTerminated) { - ScopedTestFile file("a\nb\n"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("a\nb\n")); LineReader reader(file.GetFd()); const char* line; @@ -119,8 +111,8 @@ TEST(LineReaderTest, TwoLinesTerminated) { } TEST(LineReaderTest, TwoLines) { - ScopedTestFile file("a\nb"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("a\nb")); LineReader reader(file.GetFd()); const char* line; @@ -143,8 +135,8 @@ TEST(LineReaderTest, TwoLines) { TEST(LineReaderTest, MaxLength) { char l[LineReader::kMaxLineLen-1]; memset(l, 'a', sizeof(l)); - ScopedTestFile file(l, sizeof(l)); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitData(l, sizeof(l))); LineReader reader(file.GetFd()); const char* line; @@ -159,8 +151,8 @@ TEST(LineReaderTest, TooLong) { // Note: this writes kMaxLineLen 'a' chars in the test file. char l[LineReader::kMaxLineLen]; memset(l, 'a', sizeof(l)); - ScopedTestFile file(l, sizeof(l)); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitData(l, sizeof(l))); LineReader reader(file.GetFd()); const char* line; diff --git a/src/client/linux/minidump_writer/linux_core_dumper.cc b/src/client/linux/minidump_writer/linux_core_dumper.cc index 92e3a8444..4bf9094e9 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. // @@ -30,6 +29,10 @@ // linux_core_dumper.cc: Implement google_breakpad::LinuxCoreDumper. // See linux_core_dumper.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/linux/minidump_writer/linux_core_dumper.h" #include @@ -112,8 +115,11 @@ bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { #elif defined(__mips__) stack_pointer = reinterpret_cast(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]); +#elif defined(__riscv) + stack_pointer = reinterpret_cast( + 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(stack_pointer); return true; @@ -208,19 +214,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 8a7c924b6..3fc712236 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 774480319..9ea064da9 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. // @@ -30,6 +29,10 @@ // linux_core_dumper_unittest.cc: // Unit tests for google_breakpad::LinuxCoreDumoer. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "breakpad_googletest_includes.h" @@ -61,9 +64,9 @@ TEST(LinuxCoreDumperTest, BuildProcPath) { EXPECT_TRUE(dumper.BuildProcPath(maps_path, pid, "maps")); EXPECT_STREQ(maps_path_expected, maps_path); - EXPECT_FALSE(dumper.BuildProcPath(NULL, pid, "maps")); + EXPECT_FALSE(dumper.BuildProcPath(nullptr, pid, "maps")); EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, "")); - EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, NULL)); + EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, nullptr)); char long_node[NAME_MAX]; size_t long_node_len = NAME_MAX - strlen(procfs_path) - 1; diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc index 7fd6532ad..25cf19018 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. // @@ -35,6 +34,10 @@ // rules apply as detailed at the top of minidump_writer.h: no libc calls and // use the alternative allocator. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/linux/minidump_writer/linux_dumper.h" #include @@ -44,15 +47,22 @@ #include #include +#if defined(__CHROMEOS__) +#include +#endif // defined(__CHROMEOS__) + #include "client/linux/minidump_writer/line_reader.h" #include "common/linux/elfutils.h" #include "common/linux/file_id.h" #include "common/linux/linux_libc_support.h" #include "common/linux/memory_mapped_file.h" #include "common/linux/safe_readlink.h" +#include "common/memory_allocator.h" #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 @@ -324,7 +334,7 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, // Special-case linux-gate because it's not a real file. if (my_strcmp(mapping.name, kLinuxGateLibraryName) == 0) { - void* linux_gate = NULL; + void* linux_gate = nullptr; if (pid_ == sys_getpid()) { linux_gate = reinterpret_cast(mapping.start_addr); } else { @@ -341,7 +351,7 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, return false; bool filename_modified = HandleDeletedFileInMapping(filename); - MemoryMappedFile mapped_file(filename, mapping.offset); + MemoryMappedFile mapped_file(filename, 0); if (!mapped_file.data() || mapped_file.size() < SELFMAG) return false; @@ -454,7 +464,7 @@ bool ElfFileSoName(const LinuxDumper& dumper, if (!dumper.GetMappingAbsolutePath(mapping, filename)) return false; - MemoryMappedFile mapped_file(filename, mapping.offset); + MemoryMappedFile mapped_file(filename, 0); if (!mapped_file.data() || mapped_file.size() < SELFMAG) { // mmap failed return false; @@ -483,7 +493,7 @@ void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping, // file_path := /path/to/libname.so // file_name := libname.so const char* basename = my_strrchr(file_path, '/'); - basename = basename == NULL ? file_path : (basename + 1); + basename = basename == nullptr ? file_path : (basename + 1); my_strlcpy(file_name, basename, file_name_size); return; } @@ -574,10 +584,10 @@ bool LinuxDumper::EnumerateMappings() { bool exec = (*(i2 + 3) == 'x'); const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */); if (*i3 == ' ') { - const char* name = NULL; + const char* name = nullptr; // Only copy name if the name is a valid path name, or if // it's the VDSO image. - if (((name = my_strchr(line, '/')) == NULL) && + if (((name = my_strchr(line, '/')) == nullptr) && linux_gate_loc && reinterpret_cast(start_addr) == linux_gate_loc) { name = kLinuxGateLibraryName; @@ -610,7 +620,7 @@ bool LinuxDumper::EnumerateMappings() { module->size = end_addr - start_addr; module->offset = offset; module->exec = exec; - if (name != NULL) { + if (name != nullptr) { const unsigned l = my_strlen(name); if (l < sizeof(module->name)) my_memcpy(module->name, name, l); @@ -835,8 +845,7 @@ void LinuxDumper::SanitizeStackCopy(uint8_t* stack_copy, size_t stack_len, } // Zero memory that is below the current stack pointer. - const uintptr_t offset = - (sp_offset + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); + const uintptr_t offset = PageAllocator::AlignUp(sp_offset, sizeof(uintptr_t)); if (offset) { my_memset(stack_copy, 0, offset); } @@ -886,8 +895,7 @@ bool LinuxDumper::StackHasPointerToMapping(const uint8_t* stack_copy, // aligned word in the target process. const uintptr_t low_addr = mapping.system_mapping_info.start_addr; const uintptr_t high_addr = mapping.system_mapping_info.end_addr; - const uintptr_t offset = - (sp_offset + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); + const uintptr_t offset = PageAllocator::AlignUp(sp_offset, sizeof(uintptr_t)); for (const uint8_t* sp = stack_copy + offset; sp <= stack_copy + stack_len - sizeof(uintptr_t); @@ -910,7 +918,7 @@ const MappingInfo* LinuxDumper::FindMapping(const void* address) const { return mappings_[i]; } - return NULL; + return nullptr; } // Find the mapping which the given memory address falls in. Uses the @@ -923,7 +931,7 @@ const MappingInfo* LinuxDumper::FindMappingNoBias(uintptr_t address) const { return mappings_[i]; } } - return NULL; + return nullptr; } bool LinuxDumper::HandleDeletedFileInMapping(char* path) const { diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h index 7bee160f1..2d5b2e52b 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 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 331f4bb34..fddfd3ca9 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. // @@ -31,6 +30,10 @@ // threads. The first word of each thread's stack is set to the thread // id. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -38,6 +41,7 @@ #include #include +#include "common/macros.h" #include "common/scoped_ptr.h" #include "third_party/lss/linux_syscall_support.h" @@ -51,6 +55,8 @@ #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 @@ -63,12 +69,12 @@ void* thread_function(void* data) { uint8_t byte = 1; if (write(pipefd, &byte, sizeof(byte)) != sizeof(byte)) { perror("ERROR: parent notification failed"); - return NULL; + return nullptr; } register volatile pid_t* thread_id_ptr asm(TID_PTR_REGISTER) = thread_id; while (true) asm volatile ("" : : "r" (thread_id_ptr)); - return NULL; + unreachable(); } int main(int argc, char* argv[]) { diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc index e3ddb81a6..6d8b4cf92 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. // @@ -36,6 +35,10 @@ // rules apply as detailed at the top of minidump_writer.h: no libc calls and // use the alternative allocator. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/linux/minidump_writer/linux_ptrace_dumper.h" #include @@ -56,22 +59,55 @@ #include "client/linux/minidump_writer/directory_reader.h" #include "client/linux/minidump_writer/line_reader.h" +#include "common/linux/eintr_wrapper.h" #include "common/linux/linux_libc_support.h" #include "third_party/lss/linux_syscall_support.h" +#if defined(__arm__) +/* + * https://elixir.bootlin.com/linux/v6.8-rc2/source/arch/arm/include/asm/user.h#L81 + * User specific VFP registers. If only VFPv2 is present, registers 16 to 31 + * are ignored by the ptrace system call and the signal handler. + */ +typedef struct { + unsigned long long fpregs[32]; + unsigned long fpscr; +// Kernel just appends fpscr to the copy of fpregs, so we need to force +// compiler to build the same layout. +} __attribute__((packed, aligned(4))) user_vfp_t; +#endif // defined(__arm__) + // Suspends a thread by attaching to it. static bool SuspendThread(pid_t pid) { // This may fail if the thread has just died or debugged. errno = 0; - if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 && + if (sys_ptrace(PTRACE_ATTACH, pid, nullptr, nullptr) != 0 && errno != 0) { return false; } - while (sys_waitpid(pid, NULL, __WALL) < 0) { - if (errno != EINTR) { - sys_ptrace(PTRACE_DETACH, pid, NULL, NULL); + while (true) { + int status; + int r = HANDLE_EINTR(sys_waitpid(pid, &status, __WALL)); + if (r < 0) { + sys_ptrace(PTRACE_DETACH, pid, nullptr, nullptr); return false; } + + if (!WIFSTOPPED(status)) + return false; + + // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise, this + // signal will be delivered after PTRACE_DETACH, and the thread will enter + // the "T (stopped)" state. + if (WSTOPSIG(status) == SIGSTOP) + break; + + // Signals other than SIGSTOP that are received need to be reinjected, + // or they will otherwise get lost. + r = sys_ptrace(PTRACE_CONT, pid, nullptr, + reinterpret_cast(WSTOPSIG(status))); + if (r < 0) + return false; } #if defined(__i386) || defined(__x86_64) // On x86, the stack pointer is NULL or -1, when executing trusted code in @@ -82,14 +118,14 @@ static bool SuspendThread(pid_t pid) { // We thus test the stack pointer and exclude any threads that are part of // the seccomp sandbox's trusted code. user_regs_struct regs; - if (sys_ptrace(PTRACE_GETREGS, pid, NULL, ®s) == -1 || + if (sys_ptrace(PTRACE_GETREGS, pid, nullptr, ®s) == -1 || #if defined(__i386) !regs.esp #elif defined(__x86_64) !regs.rsp #endif ) { - sys_ptrace(PTRACE_DETACH, pid, NULL, NULL); + sys_ptrace(PTRACE_DETACH, pid, nullptr, nullptr); return false; } #endif @@ -98,7 +134,7 @@ static bool SuspendThread(pid_t pid) { // Resumes a thread by detaching from it. static bool ResumeThread(pid_t pid) { - return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0; + return sys_ptrace(PTRACE_DETACH, pid, nullptr, nullptr) >= 0; } namespace google_breakpad { @@ -149,6 +185,24 @@ bool LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child, return true; } +// This read VFP registers via either PTRACE_GETREGSET or PTRACE_GETREGS +#if defined(__arm__) +static bool ReadVFPRegistersArm32(pid_t tid, struct iovec* io) { +#ifdef PTRACE_GETREGSET + if (sys_ptrace(PTRACE_GETREGSET, tid, reinterpret_cast(NT_ARM_VFP), + io) == 0 && io->iov_len == sizeof(user_vfp_t)) { + return true; + } +#endif // PTRACE_GETREGSET +#ifdef PTRACE_GETVFPREGS + if (sys_ptrace(PTRACE_GETVFPREGS, tid, nullptr, io->iov_base) == 0) { + return true; + } +#endif // PTRACE_GETVFPREGS + return false; +} +#endif // defined(__arm__) + bool LinuxPtraceDumper::ReadRegisterSet(ThreadInfo* info, pid_t tid) { #ifdef PTRACE_GETREGSET @@ -160,7 +214,24 @@ bool LinuxPtraceDumper::ReadRegisterSet(ThreadInfo* info, pid_t tid) info->GetFloatingPointRegisters(&io.iov_base, &io.iov_len); if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) { - return false; + // We are going to check if we can read VFP registers on ARM32. + // Currently breakpad does not support VFP registers to be a part of minidump, + // so this is only to confirm that we can actually read FP registers. + // That is needed to prevent a false-positive minidumps failures with ARM32 + // binaries running on top of ARM64 Linux kernels. +#if defined(__arm__) + switch (errno) { + case EIO: + case EINVAL: + user_vfp_t vfp; + struct iovec io; + io.iov_base = &vfp; + io.iov_len = sizeof(vfp); + return ReadVFPRegistersArm32(tid, &io); + default: + return false; + } +#endif // defined(__arm__) } return true; #else @@ -171,22 +242,47 @@ bool LinuxPtraceDumper::ReadRegisterSet(ThreadInfo* info, pid_t tid) bool LinuxPtraceDumper::ReadRegisters(ThreadInfo* info, pid_t tid) { #ifdef PTRACE_GETREGS void* gp_addr; - info->GetGeneralPurposeRegisters(&gp_addr, NULL); - if (sys_ptrace(PTRACE_GETREGS, tid, NULL, gp_addr) == -1) { + info->GetGeneralPurposeRegisters(&gp_addr, nullptr); + if (sys_ptrace(PTRACE_GETREGS, tid, nullptr, gp_addr) == -1) { return false; } + // When running on arm processors the binary may be built with softfp or + // hardfp. If built with softfp we have no hardware registers to read from, + // so the following read will always fail. gcc defines __SOFTFP__ macro, + // clang13 does not do so. see: https://reviews.llvm.org/D135680. + // If you are using clang and the macro is NOT defined, please include the + // macro define for applicable targets. +#if !defined(__SOFTFP__) #if !(defined(__ANDROID__) && defined(__ARM_EABI__)) // When running an arm build on an arm64 device, attempting to get the // floating point registers fails. On Android, the floating point registers // aren't written to the cpu context anyway, so just don't get them here. // See http://crbug.com/508324 void* fp_addr; - info->GetFloatingPointRegisters(&fp_addr, NULL); - if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, fp_addr) == -1) { - return false; + info->GetFloatingPointRegisters(&fp_addr, nullptr); + if (sys_ptrace(PTRACE_GETFPREGS, tid, nullptr, fp_addr) == -1) { + // We are going to check if we can read VFP registers on ARM32. + // Currently breakpad does not support VFP registers to be a part of minidump, + // so this is only to confirm that we can actually read FP registers. + // That is needed to prevent a false-positive minidumps failures with ARM32 + // binaries running on top of ARM64 Linux kernels. +#if defined(__arm__) + switch (errno) { + case EIO: + case EINVAL: + user_vfp_t vfp; + struct iovec io; + io.iov_base = &vfp; + io.iov_len = sizeof(vfp); + return ReadVFPRegistersArm32(tid, &io); + default: + return false; + } +#endif // defined(__arm__) } #endif // !(defined(__ANDROID__) && defined(__ARM_EABI__)) +#endif // !defined(__SOFTFP__) return true; #else // PTRACE_GETREGS return false; @@ -203,7 +299,7 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { pid_t tid = threads_[index]; - assert(info != NULL); + assert(info != nullptr); char status_path[NAME_MAX]; if (!BuildProcPath(status_path, tid, "status")) return false; @@ -246,7 +342,7 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { int eax, ebx, ecx, edx; __cpuid(1, eax, ebx, ecx, edx); if (edx & bit_FXSAVE) { - if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1) { + if (sys_ptrace(PTRACE_GETFPXREGS, tid, nullptr, &info->fpxregs) == -1) { return false; } } else { @@ -298,8 +394,11 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { #elif defined(__mips__) stack_pointer = reinterpret_cast(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]); +#elif defined(__riscv) + stack_pointer = reinterpret_cast( + 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(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 cee581784..7828934fa 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 da71e15dc..9dafa06c4 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. // @@ -33,6 +32,10 @@ // This file was renamed from linux_dumper_unittest.cc and modified due // to LinuxDumper being splitted into two classes. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -63,6 +66,8 @@ #endif using namespace google_breakpad; +using google_breakpad::elf::FileID; +using google_breakpad::elf::kDefaultBuildIdSize; namespace { @@ -91,7 +96,7 @@ pid_t SetupChildProcess(int number_of_threads) { "linux_dumper_unittest_helper", pipe_fd_string, kNumberOfThreadsArgument, - NULL); + nullptr); // Kill if we get here. printf("Errno from exec: %d", errno); std::string err_str = "Exec of " + helper_path + " failed"; @@ -192,7 +197,7 @@ TEST_F(LinuxPtraceDumperChildTest, FindMappings) { ASSERT_TRUE(dumper.FindMapping(reinterpret_cast(getpid))); ASSERT_TRUE(dumper.FindMapping(reinterpret_cast(printf))); - ASSERT_FALSE(dumper.FindMapping(NULL)); + ASSERT_FALSE(dumper.FindMapping(nullptr)); } TEST_F(LinuxPtraceDumperChildTest, ThreadList) { @@ -215,7 +220,7 @@ TEST_F(LinuxPtraceDumperChildTest, ThreadList) { class StackHelper { public: StackHelper() - : fd_(-1), mapping_(NULL), size_(0) {} + : fd_(-1), mapping_(nullptr), size_(0) {} ~StackHelper() { if (size_) munmap(mapping_, size_); @@ -261,7 +266,7 @@ void LinuxPtraceDumperMappingsTest::SetUp() { ASSERT_NE(-1, fd) << "Failed to open file: " << helper_path_ << ", Error: " << strerror(errno); char* mapping = - reinterpret_cast(mmap(NULL, + reinterpret_cast(mmap(nullptr, kMappingSize, PROT_READ, MAP_SHARED, @@ -318,10 +323,10 @@ TEST_F(LinuxPtraceDumperChildTest, BuildProcPath) { EXPECT_TRUE(dumper.BuildProcPath(maps_path, pid, "maps")); EXPECT_STREQ(maps_path_expected, maps_path); - EXPECT_FALSE(dumper.BuildProcPath(NULL, pid, "maps")); + EXPECT_FALSE(dumper.BuildProcPath(nullptr, pid, "maps")); EXPECT_FALSE(dumper.BuildProcPath(maps_path, 0, "maps")); EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, "")); - EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, NULL)); + EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, nullptr)); char long_node[NAME_MAX]; size_t long_node_len = NAME_MAX - strlen("/proc/123") - 1; @@ -462,6 +467,9 @@ TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) { #elif defined(__mips__) pid_t* process_tid_location = reinterpret_cast(one_thread.mcontext.gregs[1]); +#elif defined(__riscv) + pid_t* process_tid_location = + reinterpret_cast(one_thread.mcontext.__gregs[4]); #else #error This test has not been ported to this platform. #endif @@ -559,6 +567,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 32634ef00..06113954f 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. // @@ -43,10 +42,15 @@ // a canonical instance in the LinuxDumper object. We use the placement // new form to allocate objects and we don't delete them. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/linux/handler/minidump_descriptor.h" #include "client/linux/minidump_writer/minidump_writer.h" #include "client/minidump_file_writer-inl.h" +#include #include #include #include @@ -71,6 +75,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 +89,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 +101,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; @@ -135,9 +144,9 @@ class MinidumpWriter { LinuxDumper* dumper) : fd_(minidump_fd), path_(minidump_path), - ucontext_(context ? &context->context : NULL), -#if !defined(__ARM_EABI__) && !defined(__mips__) - float_state_(context ? &context->float_state : NULL), + ucontext_(context ? &context->context : nullptr), +#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE + float_state_(context ? &context->float_state : nullptr), #endif dumper_(dumper), minidump_size_limit_(-1), @@ -237,7 +246,7 @@ class MinidumpWriter { header.get()->signature = MD_HEADER_SIGNATURE; header.get()->version = MD_HEADER_VERSION; - header.get()->time_date_stamp = time(NULL); + header.get()->time_date_stamp = time(nullptr); header.get()->stream_count = kNumWriters; header.get()->stream_directory_rva = dir.position(); } @@ -317,7 +326,7 @@ class MinidumpWriter { bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer, uintptr_t pc, int max_stack_len, uint8_t** stack_copy) { - *stack_copy = NULL; + *stack_copy = nullptr; const void* stack; size_t stack_len; @@ -468,7 +477,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_); @@ -602,7 +611,7 @@ class MinidumpWriter { continue; MDRawModule mod; - if (!FillRawModule(mapping, true, i, &mod, NULL)) + if (!FillRawModule(mapping, true, i, &mod, nullptr)) return false; list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); } @@ -632,40 +641,88 @@ class MinidumpWriter { mod->base_of_image = mapping.start_addr; mod->size_of_image = mapping.size; - auto_wasteful_vector identifier_bytes( - dumper_->allocator()); + char file_name[NAME_MAX]; + char file_path[NAME_MAX]; + + dumper_->GetMappingEffectiveNameAndPath(mapping, file_path, + sizeof(file_path), file_name, + sizeof(file_name)); - 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); - } + RSDS_DEBUG_FORMAT rsds; + PEFileFormat file_format = PEFile::TryGetDebugInfo(file_path, &rsds); - if (!identifier_bytes.empty()) { - UntypedMDRVA cv(&minidump_writer_); - if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size())) - return false; + if (file_format == PEFileFormat::notPeCoff) { + // The module is not a PE/COFF file, process as an ELF. + auto_wasteful_vector 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 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(rsds.guid[0]) << 24 | + static_cast(rsds.guid[1]) << 16 | + static_cast(rsds.guid[2]) << 8 | + static_cast(rsds.guid[3]); + cv_ptr->signature.data2 = + static_cast(rsds.guid[4]) << 8 | rsds.guid[5]; + cv_ptr->signature.data3 = + static_cast(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(rsds.age[0]) << 24 | + static_cast(rsds.age[1]) << 16 | + static_cast(rsds.age[2]) << 8 | + static_cast(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; @@ -773,7 +830,7 @@ class MinidumpWriter { // The dynamic linker makes information available that helps gdb find all // DSOs loaded into the program. If this information is indeed available, // dump it to a MD_LINUX_DSO_DEBUG stream. - struct r_debug* r_debug = NULL; + struct r_debug* r_debug = nullptr; uint32_t dynamic_length = 0; for (int i = 0; ; ++i) { @@ -1085,9 +1142,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(cpu_count); } } @@ -1203,6 +1258,59 @@ class MinidumpWriter { sys_close(fd); } + 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(cpu_count); + } + } + } + return true; } #else @@ -1223,7 +1331,7 @@ class MinidumpWriter { size_t len; uint8_t data[kBufSize]; }* buffers = reinterpret_cast(Alloc(sizeof(Buffers))); - buffers->next = NULL; + buffers->next = nullptr; buffers->len = 0; size_t total = 0; @@ -1241,7 +1349,7 @@ class MinidumpWriter { if (bufptr->len == kBufSize) { bufptr->next = reinterpret_cast(Alloc(sizeof(Buffers))); bufptr = bufptr->next; - bufptr->next = NULL; + bufptr->next = nullptr; bufptr->len = 0; } } @@ -1260,7 +1368,7 @@ class MinidumpWriter { // zero bytes being read after the final buffer was just allocated. if (buffers->len == 0) { // This can only occur with final buffer. - assert(buffers->next == NULL); + assert(buffers->next == nullptr); continue; } memory.Copy(pos, &buffers->data, buffers->len); @@ -1289,7 +1397,7 @@ class MinidumpWriter { uts.release, uts.version, uts.machine, - NULL + nullptr }; bool first_item = true; for (const char** cur_info = info_table; *cur_info; cur_info++) { @@ -1333,7 +1441,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_; @@ -1370,7 +1478,7 @@ bool WriteMinidumpImpl(const char* minidump_path, uintptr_t principal_mapping_address, bool sanitize_stacks) { LinuxPtraceDumper dumper(crashing_process); - const ExceptionHandler::CrashContext* context = NULL; + const ExceptionHandler::CrashContext* context = nullptr; if (blob) { if (blob_size != sizeof(ExceptionHandler::CrashContext)) return false; @@ -1410,7 +1518,7 @@ bool WriteMinidump(int minidump_fd, pid_t crashing_process, bool skip_stacks_if_mapping_unreferenced, uintptr_t principal_mapping_address, bool sanitize_stacks) { - return WriteMinidumpImpl(NULL, minidump_fd, -1, + return WriteMinidumpImpl(nullptr, minidump_fd, -1, crashing_process, blob, blob_size, MappingList(), AppMemoryList(), skip_stacks_if_mapping_unreferenced, @@ -1426,7 +1534,7 @@ bool WriteMinidump(const char* minidump_path, pid_t process, dumper.set_crash_thread(process_blamed_thread); MappingList mapping_list; AppMemoryList app_memory_list; - MinidumpWriter writer(minidump_path, -1, NULL, mapping_list, + MinidumpWriter writer(minidump_path, -1, nullptr, mapping_list, app_memory_list, false, 0, false, &dumper); if (!writer.Init()) return false; @@ -1455,7 +1563,7 @@ bool WriteMinidump(int minidump_fd, pid_t crashing_process, bool skip_stacks_if_mapping_unreferenced, uintptr_t principal_mapping_address, bool sanitize_stacks) { - return WriteMinidumpImpl(NULL, minidump_fd, -1, crashing_process, + return WriteMinidumpImpl(nullptr, minidump_fd, -1, crashing_process, blob, blob_size, mappings, appmem, skip_stacks_if_mapping_unreferenced, @@ -1487,7 +1595,7 @@ bool WriteMinidump(int minidump_fd, off_t minidump_size_limit, bool skip_stacks_if_mapping_unreferenced, uintptr_t principal_mapping_address, bool sanitize_stacks) { - return WriteMinidumpImpl(NULL, minidump_fd, minidump_size_limit, + return WriteMinidumpImpl(nullptr, minidump_fd, minidump_size_limit, crashing_process, blob, blob_size, mappings, appmem, skip_stacks_if_mapping_unreferenced, @@ -1499,7 +1607,7 @@ bool WriteMinidump(const char* filename, const MappingList& mappings, const AppMemoryList& appmem, LinuxDumper* dumper) { - MinidumpWriter writer(filename, -1, NULL, mappings, appmem, + MinidumpWriter writer(filename, -1, nullptr, mappings, appmem, false, 0, false, dumper); if (!writer.Init()) return false; diff --git a/src/client/linux/minidump_writer/minidump_writer.h b/src/client/linux/minidump_writer/minidump_writer.h index e3b0b16da..24e3c7bdc 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 d192e5cbb..3b1b3b4b6 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -54,6 +57,8 @@ #include "google_breakpad/processor/minidump.h" using namespace google_breakpad; +using google_breakpad::elf::FileID; +using google_breakpad::elf::kDefaultBuildIdSize; namespace { @@ -140,7 +145,7 @@ TEST(MinidumpWriterTest, MappingInfo) { // Get some memory. char* memory = - reinterpret_cast(mmap(NULL, + reinterpret_cast(mmap(nullptr, memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, @@ -445,7 +450,7 @@ TEST(MinidumpWriterTest, MappingInfoContained) { lseek(fd, 0, SEEK_SET); char* memory = - reinterpret_cast(mmap(NULL, + reinterpret_cast(mmap(nullptr, memory_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, @@ -540,7 +545,7 @@ TEST(MinidumpWriterTest, DeletedBinary) { binpath.c_str(), pipe_fd_string, kNumberOfThreadsArgument.c_str(), - NULL); + nullptr); } close(fds[1]); // Wait for the child process to signal that it's ready. @@ -715,6 +720,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 @@ -740,9 +748,9 @@ TEST(MinidumpWriterTest, InvalidStackPointer) { bool found_empty_stack = false; for (int i = 0; i < dump_thread_list->thread_count(); i++) { MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i); - ASSERT_TRUE(thread->thread() != NULL); + ASSERT_TRUE(thread->thread() != nullptr); // When the stack size is zero bytes, GetMemory() returns NULL. - if (thread->GetMemory() == NULL) { + if (thread->GetMemory() == nullptr) { found_empty_stack = true; break; } @@ -784,7 +792,7 @@ TEST(MinidumpWriterTest, MinidumpSizeLimit) { helper_path.c_str(), pipe_fd_string, number_of_threads_arg, - NULL); + nullptr); } close(fds[1]); @@ -821,7 +829,7 @@ TEST(MinidumpWriterTest, MinidumpSizeLimit) { string normal_dump = temp_dir.path() + "/minidump-writer-unittest.dmp"; ASSERT_TRUE(WriteMinidump(normal_dump.c_str(), -1, - child_pid, NULL, 0, + child_pid, nullptr, 0, MappingList(), AppMemoryList())); struct stat st; ASSERT_EQ(0, stat(normal_dump.c_str(), &st)); @@ -834,10 +842,10 @@ TEST(MinidumpWriterTest, MinidumpSizeLimit) { ASSERT_TRUE(dump_thread_list); for (unsigned int i = 0; i < dump_thread_list->thread_count(); i++) { MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i); - ASSERT_TRUE(thread->thread() != NULL); + ASSERT_TRUE(thread->thread() != nullptr); // When the stack size is zero bytes, GetMemory() returns NULL. MinidumpMemoryRegion* memory = thread->GetMemory(); - ASSERT_TRUE(memory != NULL); + ASSERT_TRUE(memory != nullptr); total_normal_stack_size += memory->GetSize(); } } @@ -852,7 +860,7 @@ TEST(MinidumpWriterTest, MinidumpSizeLimit) { string same_dump = temp_dir.path() + "/minidump-writer-unittest-same.dmp"; ASSERT_TRUE(WriteMinidump(same_dump.c_str(), minidump_size_limit, - child_pid, NULL, 0, + child_pid, nullptr, 0, MappingList(), AppMemoryList())); struct stat st; ASSERT_EQ(0, stat(same_dump.c_str(), &st)); @@ -885,7 +893,7 @@ TEST(MinidumpWriterTest, MinidumpSizeLimit) { string limit_dump = temp_dir.path() + "/minidump-writer-unittest-limit.dmp"; ASSERT_TRUE(WriteMinidump(limit_dump.c_str(), minidump_size_limit, - child_pid, NULL, 0, + child_pid, nullptr, 0, MappingList(), AppMemoryList())); struct stat st; ASSERT_EQ(0, stat(limit_dump.c_str(), &st)); @@ -902,10 +910,10 @@ TEST(MinidumpWriterTest, MinidumpSizeLimit) { int total_limit_stack_size = 0; for (unsigned int i = 0; i < dump_thread_list->thread_count(); i++) { MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i); - ASSERT_TRUE(thread->thread() != NULL); + ASSERT_TRUE(thread->thread() != nullptr); // When the stack size is zero bytes, GetMemory() returns NULL. MinidumpMemoryRegion* memory = thread->GetMemory(); - ASSERT_TRUE(memory != NULL); + ASSERT_TRUE(memory != nullptr); total_limit_stack_size += memory->GetSize(); } 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 8e2319e76..399f1a123 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. // @@ -30,6 +29,10 @@ // minidump_writer_unittest_utils.cc: // Shared routines used by unittests under client/linux/minidump_writer. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include 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 f16cc086b..f93885ee3 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 000000000..7b3fe6c08 --- /dev/null +++ b/src/client/linux/minidump_writer/pe_file.cc @@ -0,0 +1,151 @@ +// 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + +#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(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(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(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(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(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(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( + 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 000000000..97984ab5d --- /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 + 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(base) + position; + return reinterpret_cast(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 000000000..017ac0619 --- /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 + +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_ diff --git a/src/client/linux/minidump_writer/proc_cpuinfo_reader.h b/src/client/linux/minidump_writer/proc_cpuinfo_reader.h index d9461bf30..5ba1bafa6 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. // @@ -75,7 +74,7 @@ class ProcCpuInfoReader { // - can contain spaces. // - some fields have an empty char* sep = static_cast(my_memchr(line, ':', line_len)); - if (sep == NULL) + if (sep == nullptr) continue; // Record the value. Skip leading space after the column to get 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 d9b1203e4..4ac525695 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -36,33 +39,19 @@ #include "client/linux/minidump_writer/proc_cpuinfo_reader.h" #include "breakpad_googletest_includes.h" -#include "common/linux/tests/auto_testfile.h" +#include "common/linux/scoped_tmpfile.h" using namespace google_breakpad; -#if !defined(__ANDROID__) -#define TEMPDIR "/tmp" -#else -#define TEMPDIR "/data/local/tmp" -#endif - - namespace { typedef testing::Test ProcCpuInfoReaderTest; -class ScopedTestFile : public AutoTestFile { -public: - explicit ScopedTestFile(const char* text) - : AutoTestFile("proc_cpuinfo_reader", text) { - } -}; - } TEST(ProcCpuInfoReaderTest, EmptyFile) { - ScopedTestFile file(""); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("")); ProcCpuInfoReader reader(file.GetFd()); const char* field; @@ -70,8 +59,8 @@ TEST(ProcCpuInfoReaderTest, EmptyFile) { } TEST(ProcCpuInfoReaderTest, OneLineTerminated) { - ScopedTestFile file("foo : bar\n"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("foo : bar\n")); ProcCpuInfoReader reader(file.GetFd()); const char* field; @@ -83,8 +72,8 @@ TEST(ProcCpuInfoReaderTest, OneLineTerminated) { } TEST(ProcCpuInfoReaderTest, OneLine) { - ScopedTestFile file("foo : bar"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("foo : bar")); ProcCpuInfoReader reader(file.GetFd()); const char* field; @@ -98,8 +87,8 @@ TEST(ProcCpuInfoReaderTest, OneLine) { } TEST(ProcCpuInfoReaderTest, TwoLinesTerminated) { - ScopedTestFile file("foo : bar\nzoo : tut\n"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("foo : bar\nzoo : tut\n")); ProcCpuInfoReader reader(file.GetFd()); const char* field; @@ -115,8 +104,8 @@ TEST(ProcCpuInfoReaderTest, TwoLinesTerminated) { } TEST(ProcCpuInfoReaderTest, SkipMalformedLine) { - ScopedTestFile file("this line should have a column\nfoo : bar\n"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("this line should have a column\nfoo : bar\n")); ProcCpuInfoReader reader(file.GetFd()); const char* field; @@ -128,8 +117,8 @@ TEST(ProcCpuInfoReaderTest, SkipMalformedLine) { } TEST(ProcCpuInfoReaderTest, SkipOneEmptyLine) { - ScopedTestFile file("\n\nfoo : bar\n"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("\n\nfoo : bar\n")); ProcCpuInfoReader reader(file.GetFd()); const char* field; @@ -141,8 +130,8 @@ TEST(ProcCpuInfoReaderTest, SkipOneEmptyLine) { } TEST(ProcCpuInfoReaderTest, SkipEmptyField) { - ScopedTestFile file(" : bar\nzoo : tut\n"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString(" : bar\nzoo : tut\n")); ProcCpuInfoReader reader(file.GetFd()); const char* field; @@ -154,8 +143,8 @@ TEST(ProcCpuInfoReaderTest, SkipEmptyField) { } TEST(ProcCpuInfoReaderTest, SkipTwoEmptyLines) { - ScopedTestFile file("foo : bar\n\n\nfoo : bar\n"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("foo : bar\n\n\nfoo : bar\n")); ProcCpuInfoReader reader(file.GetFd()); const char* field; @@ -171,8 +160,8 @@ TEST(ProcCpuInfoReaderTest, SkipTwoEmptyLines) { } TEST(ProcCpuInfoReaderTest, FieldWithSpaces) { - ScopedTestFile file("foo bar : zoo\n"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("foo bar : zoo\n")); ProcCpuInfoReader reader(file.GetFd()); const char* field; @@ -184,8 +173,8 @@ TEST(ProcCpuInfoReaderTest, FieldWithSpaces) { } TEST(ProcCpuInfoReaderTest, EmptyValue) { - ScopedTestFile file("foo :\n"); - ASSERT_TRUE(file.IsOk()); + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("foo :\n")); ProcCpuInfoReader reader(file.GetFd()); const char* field; diff --git a/src/client/linux/sender/google_crash_report_sender.cc b/src/client/linux/sender/google_crash_report_sender.cc index 6bf337a8d..2fa6a2b41 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/google_crashdump_uploader.h" #include #include @@ -101,5 +104,5 @@ int main(int argc, char* argv[]) { FLAGS_crash_server, FLAGS_proxy_host, FLAGS_proxy_userpasswd); - g.Upload(NULL, NULL, NULL); + g.Upload(nullptr, nullptr, nullptr); } diff --git a/src/client/mac/Breakpad.xcodeproj/project.pbxproj b/src/client/mac/Breakpad.xcodeproj/project.pbxproj index 10876535d..ed782c918 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 = ""; }; DE43468F11C72973004F095F /* sv */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = sv; path = sender/sv.lproj/InfoPlist.strings; sourceTree = ""; }; DE43469011C72976004F095F /* tr */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = tr; path = sender/tr.lproj/InfoPlist.strings; sourceTree = ""; }; + EB9CF89F24F01E1D00F9B6D1 /* encoding_util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = encoding_util.m; path = ../../common/mac/encoding_util.m; sourceTree = ""; }; + EB9CF8AD24F01E1D00F9B6D1 /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = minidump_upload.m; path = ../../common/mac/minidump_upload.m; sourceTree = ""; }; + EB9CF8AE24F01E1D00F9B6D1 /* encoding_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = encoding_util.h; path = ../../common/mac/encoding_util.h; sourceTree = ""; }; + EB9CF8AF24F01E1D00F9B6D1 /* HTTPSimplePostRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPSimplePostRequest.h; path = ../../common/mac/HTTPSimplePostRequest.h; sourceTree = ""; }; + EB9CF8B024F01E1D00F9B6D1 /* HTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPRequest.h; path = ../../common/mac/HTTPRequest.h; sourceTree = ""; }; + EB9CF8B124F01E1D00F9B6D1 /* HTTPPutRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPPutRequest.m; path = ../../common/mac/HTTPPutRequest.m; sourceTree = ""; }; + EB9CF8B224F01E1D00F9B6D1 /* HTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPRequest.m; path = ../../common/mac/HTTPRequest.m; sourceTree = ""; }; + EB9CF8B324F01E1D00F9B6D1 /* SymbolCollectorClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SymbolCollectorClient.m; path = ../../common/mac/SymbolCollectorClient.m; sourceTree = ""; }; + EB9CF8B424F01E1D00F9B6D1 /* HTTPGetRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPGetRequest.h; path = ../../common/mac/HTTPGetRequest.h; sourceTree = ""; }; + EB9CF8B524F01E1D00F9B6D1 /* HTTPGetRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPGetRequest.m; path = ../../common/mac/HTTPGetRequest.m; sourceTree = ""; }; + EB9CF8B624F01E1D00F9B6D1 /* HTTPSimplePostRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPSimplePostRequest.m; path = ../../common/mac/HTTPSimplePostRequest.m; sourceTree = ""; }; + EB9CF8B724F01E1D00F9B6D1 /* SymbolCollectorClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolCollectorClient.h; path = ../../common/mac/SymbolCollectorClient.h; sourceTree = ""; }; + EB9CF8B824F01E1D00F9B6D1 /* HTTPPutRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPPutRequest.h; path = ../../common/mac/HTTPPutRequest.h; sourceTree = ""; }; 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 = ""; }; @@ -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 9e191ce27..e2b48aa15 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. // diff --git a/src/client/mac/Framework/Breakpad.mm b/src/client/mac/Framework/Breakpad.mm index 1a46b5977..def43b7da 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. // diff --git a/src/client/mac/Framework/OnDemandServer.h b/src/client/mac/Framework/OnDemandServer.h index be0d2b79a..e7a52e7d2 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. // diff --git a/src/client/mac/Framework/OnDemandServer.mm b/src/client/mac/Framework/OnDemandServer.mm index b6b59ca5a..d2f3a283c 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. // @@ -81,15 +80,15 @@ 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 @@ kr = breakpad::BootstrapRegister( bootstrap_subset_port, const_cast(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 @@ 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 11bc2e434..4a4ed9844 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. // diff --git a/src/client/mac/crash_generation/ConfigFile.mm b/src/client/mac/crash_generation/ConfigFile.mm index 57d07590a..fe89e8586 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. // @@ -105,13 +104,14 @@ BOOL EnsureDirectoryPathExists(NSString* dirPath) { time_t processStartTime = strtol(processStartTimeString, NULL, 10); time_t processUptime = tv.tv_sec - processStartTime; // Store the uptime in milliseconds. - sprintf(processUptimeString, "%llu", - static_cast(processUptime) * 1000); + snprintf(processUptimeString, sizeof(processUptimeString), "%llu", + static_cast(processUptime) * 1000); if (!AppendConfigString(BREAKPAD_PROCESS_UP_TIME, processUptimeString)) return false; } - sprintf(processCrashtimeString, "%zd", tv.tv_sec); + snprintf(processCrashtimeString, sizeof(processCrashtimeString), "%llu", + static_cast(tv.tv_sec)); return AppendConfigString(BREAKPAD_PROCESS_CRASH_TIME, processCrashtimeString); } diff --git a/src/client/mac/crash_generation/Inspector.h b/src/client/mac/crash_generation/Inspector.h index c96711363..fb9240c26 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. // diff --git a/src/client/mac/crash_generation/Inspector.mm b/src/client/mac/crash_generation/Inspector.mm index d5fc29e02..4c0a78062 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. // @@ -29,26 +28,23 @@ // // Utility that can inspect another process and write a crash dump -#include -#include +#import "client/mac/crash_generation/Inspector.h" + +#import #include #include #include -#include -#import "client/mac/crash_generation/Inspector.h" +#include +#include +#import "GTMDefines.h" #import "client/mac/Framework/Breakpad.h" #import "client/mac/handler/minidump_generator.h" - #import "common/mac/MachIPC.h" #include "common/mac/bootstrap_compat.h" #include "common/mac/launch_reporter.h" -#import "GTMDefines.h" - -#import - namespace google_breakpad { //============================================================================= @@ -359,4 +355,3 @@ } } // namespace google_breakpad - diff --git a/src/client/mac/crash_generation/InspectorMain.mm b/src/client/mac/crash_generation/InspectorMain.mm index 137c6a1e1..fb3199d3f 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 a3a95dcac..30870f179 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 ceeb3b32a..7622dddd2 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/mac/crash_generation/crash_generation_client.h" #include "client/mac/crash_generation/crash_generation_server.h" diff --git a/src/client/mac/crash_generation/crash_generation_client.h b/src/client/mac/crash_generation/crash_generation_client.h index 527f577a5..06cc0a313 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 ae44e8bf8..f099dd4c5 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/mac/crash_generation/crash_generation_server.h" #include @@ -66,7 +69,7 @@ CrashGenerationServer::~CrashGenerationServer() { } bool CrashGenerationServer::Start() { - int thread_create_result = pthread_create(&server_thread_, NULL, + int thread_create_result = pthread_create(&server_thread_, nullptr, &WaitForMessages, this); started_ = thread_create_result == 0; return started_; @@ -82,7 +85,7 @@ bool CrashGenerationServer::Stop() { const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000; kern_return_t result = sender.SendMessage(quit_message, kSendTimeoutMs); if (result == KERN_SUCCESS) { - int thread_join_result = pthread_join(server_thread_, NULL); + int thread_join_result = pthread_join(server_thread_, nullptr); started_ = thread_join_result != 0; } @@ -94,7 +97,7 @@ void* CrashGenerationServer::WaitForMessages(void* server) { CrashGenerationServer* self = reinterpret_cast(server); while (self->WaitForOneMessage()) {} - return NULL; + return nullptr; } bool CrashGenerationServer::WaitForOneMessage() { @@ -120,7 +123,7 @@ bool CrashGenerationServer::WaitForOneMessage() { ScopedTaskSuspend suspend(remote_task); MinidumpGenerator generator(remote_task, handler_thread); - dump_path = generator.UniqueNameInDirectory(dump_dir_, NULL); + dump_path = generator.UniqueNameInDirectory(dump_dir_, nullptr); if (info.exception_type && info.exception_code) { generator.SetExceptionInformation(info.exception_type, diff --git a/src/client/mac/crash_generation/crash_generation_server.h b/src/client/mac/crash_generation/crash_generation_server.h index 82fef146e..2c4b56cf5 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. // diff --git a/src/client/mac/handler/breakpad_nlist_64.cc b/src/client/mac/handler/breakpad_nlist_64.cc index b4f04c917..fcf09baef 100644 --- a/src/client/mac/handler/breakpad_nlist_64.cc +++ b/src/client/mac/handler/breakpad_nlist_64.cc @@ -65,6 +65,10 @@ * I've modified it to be compatible with 64-bit images. */ +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "breakpad_nlist_64.h" #include @@ -217,7 +221,7 @@ int __breakpad_fdnlist(int fd, nlist_type* list, const char** symbolNames, /* Read in the fat archs */ struct fat_arch* fat_archs = (struct fat_arch*)malloc(fh.nfat_arch * sizeof(struct fat_arch)); - if (fat_archs == NULL) { + if (fat_archs == nullptr) { return -1; } if (read(fd, (char*)fat_archs, @@ -244,7 +248,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 = nullptr; for (unsigned i = 0; i < fh.nfat_arch; i++) { if (fat_archs[i].cputype == cpu_type) { fap = &fat_archs[i]; @@ -282,7 +286,7 @@ int __breakpad_fdnlist(int fd, nlist_type* list, const char** symbolNames, struct load_command* load_commands = (struct load_command*)malloc(mh.sizeofcmds); - if (load_commands == NULL) { + if (load_commands == nullptr) { return -1; } if (read(fd, (char*)load_commands, mh.sizeofcmds) != @@ -290,7 +294,7 @@ int __breakpad_fdnlist(int fd, nlist_type* list, const char** symbolNames, free(load_commands); return -1; } - struct symtab_command* stp = NULL; + struct symtab_command* stp = nullptr; struct load_command* lcp = load_commands; // iterate through all load commands, looking for // LC_SYMTAB load command @@ -311,7 +315,7 @@ int __breakpad_fdnlist(int fd, nlist_type* list, const char** symbolNames, } lcp = (struct load_command*)((char*)lcp + lcp->cmdsize); } - if (stp == NULL) { + if (stp == nullptr) { free(load_commands); return -1; } diff --git a/src/client/mac/handler/breakpad_nlist_64.h b/src/client/mac/handler/breakpad_nlist_64.h index a1a3e83c9..7093d2849 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. // diff --git a/src/client/mac/handler/dynamic_images.cc b/src/client/mac/handler/dynamic_images.cc index b78c20877..3bee00b47 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/mac/handler/dynamic_images.h" extern "C" { // needed to compile on Leopard @@ -48,6 +51,7 @@ extern "C" { // needed to compile on Leopard #include #include "breakpad_nlist_64.h" +#include "common/memory_allocator.h" #if !TARGET_OS_IPHONE #include @@ -189,7 +193,7 @@ kern_return_t ReadTaskMemory(task_port_t target_task, mach_vm_address_t page_address = address & (-systemPageSize); mach_vm_address_t last_page_address = - (address + length + (systemPageSize - 1)) & (-systemPageSize); + PageAllocator::AlignUp(address + length, systemPageSize); mach_vm_size_t page_size = last_page_address - page_address; uint8_t* local_start; @@ -529,7 +533,7 @@ DynamicImage* DynamicImages::GetExecutableImage() { return GetImage(executable_index); } - return NULL; + return nullptr; } //============================================================================== diff --git a/src/client/mac/handler/dynamic_images.h b/src/client/mac/handler/dynamic_images.h index e81ea7f3a..68a506956 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. // @@ -111,7 +110,7 @@ class DynamicImage { DynamicImage(uint8_t* header, // data is copied size_t header_size, // includes load commands uint64_t load_address, - string file_path, + const string& file_path, uintptr_t image_mod_date, mach_port_t task, cpu_type_t cpu_type) @@ -207,7 +206,8 @@ class DynamicImageRef { public: 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 { return (*const_cast(this)->p) @@ -254,7 +254,7 @@ class DynamicImages { if (i < (int)image_list_.size()) { return image_list_[i]; } - return NULL; + return nullptr; } // Returns the image corresponding to the main executable. diff --git a/src/client/mac/handler/exception_handler.cc b/src/client/mac/handler/exception_handler.cc index 287fe1bec..5fe626e9d 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. // @@ -27,6 +26,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include #include #include #include @@ -34,11 +38,13 @@ #include #include +#include #include "client/mac/handler/exception_handler.h" #include "client/mac/handler/minidump_generator.h" #include "common/mac/macho_utilities.h" #include "common/mac/scoped_task_suspend-inl.h" +#include "common/macros.h" #include "google_breakpad/common/minidump_exception_mac.h" #ifndef __EXCEPTIONS @@ -230,10 +236,10 @@ ExceptionHandler::ExceptionHandler(const string& dump_path, filter_(filter), callback_(callback), callback_context_(callback_context), - directCallback_(NULL), - handler_thread_(NULL), + directCallback_(nullptr), + handler_thread_(nullptr), handler_port_(MACH_PORT_NULL), - previous_(NULL), + previous_(nullptr), installed_exception_handler_(false), is_in_teardown_(false), last_minidump_write_result_(false), @@ -254,13 +260,13 @@ ExceptionHandler::ExceptionHandler(DirectCallback callback, void* callback_context, bool install_handler) : dump_path_(), - filter_(NULL), - callback_(NULL), + filter_(nullptr), + callback_(nullptr), callback_context_(callback_context), directCallback_(callback), - handler_thread_(NULL), + handler_thread_(nullptr), handler_port_(MACH_PORT_NULL), - previous_(NULL), + previous_(nullptr), installed_exception_handler_(false), is_in_teardown_(false), last_minidump_write_result_(false), @@ -308,8 +314,8 @@ bool ExceptionHandler::WriteMinidump(const string& dump_path, bool write_exception_stream, MinidumpCallback callback, void* callback_context) { - ExceptionHandler handler(dump_path, NULL, callback, callback_context, false, - NULL); + ExceptionHandler handler(dump_path, nullptr, callback, callback_context, + false, nullptr); return handler.WriteMinidump(write_exception_stream); } @@ -340,8 +346,13 @@ bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child, bool result = generator.Write(dump_filename.c_str()); if (callback) { +#ifdef SENTRY_BACKEND_BREAKPAD + return callback(dump_path.c_str(), dump_id.c_str(), + callback_context, nullptr, result); +#else return callback(dump_path.c_str(), dump_id.c_str(), callback_context, result); +#endif } return result; } @@ -390,6 +401,11 @@ bool ExceptionHandler::WriteMinidumpWithException( } else { string minidump_id; + std::remove_pointer::type mctx = {}; + breakpad_ucontext_t uctx = {}; + uctx.uc_mcsize = sizeof(mctx); + uctx.uc_mcontext = &mctx; + // Putting the MinidumpGenerator in its own context will ensure that the // destructor is executed, closing the newly created minidump file. if (!dump_path_.empty()) { @@ -397,6 +413,7 @@ bool ExceptionHandler::WriteMinidumpWithException( report_current_thread ? MACH_PORT_NULL : mach_thread_self()); md.SetTaskContext(task_context); + if (exception_type && exception_code) { // If this is a real exception, give the filter (if any) a chance to // decide if this should be sent. @@ -407,6 +424,13 @@ bool ExceptionHandler::WriteMinidumpWithException( exception_subcode, thread_name); } + // fill context + if (!task_context) + { + md.GetThreadContext(thread_name, &uctx); + task_context = &uctx; + } + result = md.Write(next_minidump_path_c_); } @@ -415,8 +439,12 @@ bool ExceptionHandler::WriteMinidumpWithException( // If the user callback returned true and we're handling an exception // (rather than just writing out the file), then we should exit without // forwarding the exception to the next handler. - if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_, +#ifdef SENTRY_BACKEND_BREAKPAD + if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_, task_context, result)) { +#else + if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_, result)) { +#endif if (exit_after_write) _exit(exception_type); } @@ -512,7 +540,7 @@ void* ExceptionHandler::WaitForMessage(void* exception_handler_class) { // Don't touch self, since this message could have been sent // from its destructor. if (receive.header.msgh_id == kShutdownMessage) - return NULL; + return nullptr; self->SuspendThreads(); @@ -541,7 +569,7 @@ void* ExceptionHandler::WaitForMessage(void* exception_handler_class) { // Write out the dump and save the result for later retrieval self->last_minidump_write_result_ = self->WriteMinidumpWithException(exception_type, exception_code, - 0, NULL, thread, + 0, nullptr, thread, false, false); #if USE_PROTECTED_ALLOCATIONS @@ -576,7 +604,7 @@ void* ExceptionHandler::WaitForMessage(void* exception_handler_class) { // Generate the minidump with the exception data. self->WriteMinidumpWithException(receive.exception, receive.code[0], - subcode, NULL, receive.thread.name, + subcode, nullptr, receive.thread.name, true, false); #if USE_PROTECTED_ALLOCATIONS @@ -609,7 +637,7 @@ void* ExceptionHandler::WaitForMessage(void* exception_handler_class) { } } - return NULL; + unreachable(); } // static @@ -634,7 +662,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { bool ExceptionHandler::InstallHandler() { // If a handler is already installed, something is really wrong. - if (gProtectedData.handler != NULL) { + if (gProtectedData.handler != nullptr) { return false; } if (!IsOutOfProcess()) { @@ -645,7 +673,7 @@ bool ExceptionHandler::InstallHandler() { sa.sa_sigaction = ExceptionHandler::SignalHandler; sa.sa_flags = SA_SIGINFO; - scoped_ptr old(new struct sigaction); + std::unique_ptr old(new struct sigaction); if (sigaction(SIGABRT, &sa, old.get()) == -1) { return false; } @@ -695,13 +723,13 @@ bool ExceptionHandler::UninstallHandler(bool in_exception) { kern_return_t result = KERN_SUCCESS; if (old_handler_.get()) { - sigaction(SIGABRT, old_handler_.get(), NULL); + sigaction(SIGABRT, old_handler_.get(), nullptr); #if USE_PROTECTED_ALLOCATIONS mprotect(gProtectedData.protected_buffer, PAGE_SIZE, PROT_READ | PROT_WRITE); #endif old_handler_.reset(); - gProtectedData.handler = NULL; + gProtectedData.handler = nullptr; } if (installed_exception_handler_) { @@ -726,7 +754,7 @@ bool ExceptionHandler::UninstallHandler(bool in_exception) { #endif } - previous_ = NULL; + previous_ = nullptr; installed_exception_handler_ = false; } @@ -734,7 +762,7 @@ bool ExceptionHandler::UninstallHandler(bool in_exception) { } bool ExceptionHandler::Setup(bool install_handler) { - if (pthread_mutex_init(&minidump_write_mutex_, NULL)) + if (pthread_mutex_init(&minidump_write_mutex_, nullptr)) return false; // Create a receive right @@ -782,7 +810,7 @@ bool ExceptionHandler::Teardown() { return false; } - handler_thread_ = NULL; + handler_thread_ = nullptr; handler_port_ = MACH_PORT_NULL; pthread_mutex_destroy(&minidump_write_mutex_); diff --git a/src/client/mac/handler/exception_handler.h b/src/client/mac/handler/exception_handler.h index fe7491fd4..f4d286a7f 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. // @@ -39,10 +38,10 @@ #include #include +#include #include #include "client/mac/handler/ucontext_compat.h" -#include "common/scoped_ptr.h" #if !TARGET_OS_IPHONE #include "client/mac/crash_generation/crash_generation_client.h" @@ -76,18 +75,34 @@ class ExceptionHandler { // will immediately report the exception as unhandled without writing a // minidump, allowing another handler the opportunity to handle it. typedef bool (*FilterCallback)(void* context); - +#ifdef SENTRY_BACKEND_BREAKPAD // A callback function to run after the minidump has been written. // |minidump_id| is a unique id for the dump, so the minidump // file is /.dmp. // |context| is the value passed into the constructor. + // |user_context| is the context of exception's thread // |succeeded| indicates whether a minidump file was successfully written. // 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); + void* context, + breakpad_ucontext_t *user_context, bool succeeded); +#else + // A callback function to run after the minidump has been written. + // |minidump_id| is a unique id for the dump, so the minidump + // file is /.dmp. + // |context| is the value passed into the constructor. + // |succeeded| indicates whether a minidump file was successfully written. + // 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); +#endif // A callback function which will be called directly if an exception occurs. // This bypasses the minidump file writing and simply gives the client @@ -160,7 +175,7 @@ class ExceptionHandler { #if TARGET_OS_IPHONE return false; #else - return crash_generation_client_.get() != NULL; + return crash_generation_client_.get() != nullptr; #endif } @@ -268,11 +283,11 @@ class ExceptionHandler { // Old signal handler for SIGABRT. Used to be able to restore it when // uninstalling. - scoped_ptr old_handler_; + std::unique_ptr old_handler_; #if !TARGET_OS_IPHONE // Client for out-of-process dump generation. - scoped_ptr crash_generation_client_; + std::unique_ptr crash_generation_client_; #endif }; diff --git a/src/client/mac/handler/mach_vm_compat.h b/src/client/mac/handler/mach_vm_compat.h index 9e9028b92..b7dc159b5 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 e0351c4bb..f55e2ca42 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. // @@ -27,20 +26,24 @@ // (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 -#include +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "client/mac/handler/minidump_generator.h" +#include +#include +#include +#include #include #include #include -#include -#include -#include +#include #include +#include -#include - -#include "client/mac/handler/minidump_generator.h" +#include #if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT) #include @@ -62,6 +65,8 @@ using MacStringUtils::IntegerValueAtIndex; namespace google_breakpad { +using mach_o::FileID; + #if defined(__LP64__) && __LP64__ #define LC_SEGMENT_ARCH LC_SEGMENT_64 #else @@ -78,8 +83,8 @@ MinidumpGenerator::MinidumpGenerator() crashing_task_(mach_task_self()), handler_thread_(mach_thread_self()), cpu_type_(DynamicImages::GetNativeCPUType()), - task_context_(NULL), - dynamic_images_(NULL), + task_context_(nullptr), + dynamic_images_(nullptr), memory_blocks_(&allocator_) { GatherSystemInformation(); } @@ -96,14 +101,14 @@ MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task, crashing_task_(crashing_task), handler_thread_(handler_thread), cpu_type_(DynamicImages::GetNativeCPUType()), - task_context_(NULL), - dynamic_images_(NULL), + task_context_(nullptr), + dynamic_images_(nullptr), memory_blocks_(&allocator_) { if (crashing_task != mach_task_self()) { dynamic_images_ = new DynamicImages(crashing_task_); cpu_type_ = dynamic_images_->GetCPUType(); } else { - dynamic_images_ = NULL; + dynamic_images_ = nullptr; cpu_type_ = DynamicImages::GetNativeCPUType(); } @@ -129,11 +134,11 @@ void MinidumpGenerator::GatherSystemInformation() { CFStringRef vers_path = CFSTR("/System/Library/CoreServices/SystemVersion.plist"); CFURLRef sys_vers = - CFURLCreateWithFileSystemPath(NULL, + CFURLCreateWithFileSystemPath(nullptr, vers_path, kCFURLPOSIXPathStyle, false); - CFReadStreamRef read_stream = CFReadStreamCreateWithFile(NULL, sys_vers); + CFReadStreamRef read_stream = CFReadStreamCreateWithFile(nullptr, sys_vers); CFRelease(sys_vers); if (!read_stream) { return; @@ -142,7 +147,7 @@ void MinidumpGenerator::GatherSystemInformation() { CFRelease(read_stream); return; } - CFMutableDataRef data = NULL; + CFMutableDataRef data = nullptr; while (true) { // Actual data file tests: Mac at 480 bytes and iOS at 413 bytes. const CFIndex kMaxBufferLength = 1024; @@ -152,13 +157,13 @@ void MinidumpGenerator::GatherSystemInformation() { if (num_bytes_read < 0) { if (data) { CFRelease(data); - data = NULL; + data = nullptr; } break; } else if (num_bytes_read == 0) { break; } else if (!data) { - data = CFDataCreateMutable(NULL, 0); + data = CFDataCreateMutable(nullptr, 0); } CFDataAppendBytes(data, data_bytes, num_bytes_read); } @@ -169,7 +174,7 @@ void MinidumpGenerator::GatherSystemInformation() { } CFDictionaryRef list = static_cast(CFPropertyListCreateWithData( - NULL, data, kCFPropertyListImmutable, NULL, NULL)); + nullptr, data, kCFPropertyListImmutable, nullptr, nullptr)); CFRelease(data); if (!list) { return; @@ -195,10 +200,62 @@ void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t* task_context) { task_context_ = task_context; } +bool MinidumpGenerator::GetThreadContext(mach_port_t thread_id, breakpad_ucontext_t* context) +{ + breakpad_thread_state_data_t state; + mach_msg_type_number_t state_count + = static_cast(sizeof(state)); + + if (!GetThreadState(thread_id, state, &state_count)) + return false; + +#ifdef HAS_X86_SUPPORT + MDRawContextAMD64 amd64_ctx; + GetContextX86_64(state, &amd64_ctx); + +#define CopyReg(reg) context->uc_mcontext->__ss.__##reg = amd64_ctx.reg + + CopyReg(rax); + CopyReg(rbx); + CopyReg(rcx); + CopyReg(rdx); + CopyReg(rdi); + CopyReg(rsi); + CopyReg(rbp); + CopyReg(rsp); + CopyReg(r8); + CopyReg(r9); + CopyReg(r10); + CopyReg(r11); + CopyReg(r12); + CopyReg(r13); + CopyReg(r14); + CopyReg(r15); + CopyReg(rip); + CopyReg(cs); + CopyReg(fs); + CopyReg(gs); + context->uc_mcontext->__ss.__rflags = amd64_ctx.eflags; +#undef CopyReg +#endif +#ifdef HAS_ARM64_SUPPORT + MDRawContextARM64_Old arm64_ctx; + GetContextARM64(state, &arm64_ctx); + + std::copy_n(std::begin(arm64_ctx.iregs), std::size(context->uc_mcontext->__ss.__x), std::begin(context->uc_mcontext->__ss.__x)); + context->uc_mcontext->__ss.__fp = arm64_ctx.iregs[MD_CONTEXT_ARM64_REG_FP]; + context->uc_mcontext->__ss.__lr = arm64_ctx.iregs[MD_CONTEXT_ARM64_REG_LR]; + context->uc_mcontext->__ss.__sp = arm64_ctx.iregs[MD_CONTEXT_ARM64_REG_SP]; + context->uc_mcontext->__ss.__pc = arm64_ctx.iregs[MD_CONTEXT_ARM64_REG_PC]; + context->uc_mcontext->__ss.__cpsr = arm64_ctx.cpsr; +#endif + return true; +} + string MinidumpGenerator::UniqueNameInDirectory(const string& dir, string* unique_name) { - CFUUIDRef uuid = CFUUIDCreate(NULL); - CFStringRef uuid_cfstr = CFUUIDCreateString(NULL, uuid); + CFUUIDRef uuid = CFUUIDCreate(nullptr); + CFStringRef uuid_cfstr = CFUUIDCreateString(nullptr, uuid); CFRelease(uuid); string file_name(ConvertToString(uuid_cfstr)); CFRelease(uuid_cfstr); @@ -554,6 +611,15 @@ MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state, *register_location = context.location(); MDRawContextARM64_Old* context_ptr = context.get(); + GetContextARM64(state, context_ptr); + return true; +} + +void MinidumpGenerator::GetContextARM64(breakpad_thread_state_data_t state, + MDRawContextARM64_Old* context_ptr) { + arm_thread_state64_t* machine_state = + reinterpret_cast(state); + context_ptr->context_flags = MD_CONTEXT_ARM64_FULL_OLD; #define AddGPR(a) \ @@ -595,8 +661,6 @@ MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state, AddGPR(27); AddGPR(28); #undef AddGPR - - return true; } #endif @@ -846,14 +910,19 @@ bool MinidumpGenerator::WriteContextX86_64( breakpad_thread_state_data_t state, MDLocationDescriptor* register_location) { TypedMDRVA context(&writer_); - x86_thread_state64_t* machine_state = - reinterpret_cast(state); - if (!context.Allocate()) return false; *register_location = context.location(); MDRawContextAMD64* context_ptr = context.get(); + GetContextX86_64(state, context_ptr); + return true; +} + +void MinidumpGenerator::GetContextX86_64(breakpad_thread_state_data_t state, + MDRawContextAMD64* context_ptr) { + x86_thread_state64_t* machine_state = + reinterpret_cast(state); #define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ REGISTER_FROM_THREADSTATE(machine_state, a)) @@ -885,8 +954,6 @@ bool MinidumpGenerator::WriteContextX86_64( AddReg(fs); AddReg(gs); #undef AddReg - - return true; } #endif @@ -1066,9 +1133,8 @@ bool MinidumpGenerator::WriteMemoryListStream( ip_memory_d.start_of_memory_range = std::max(uintptr_t(addr), uintptr_t(ip - (kIPMemorySize / 2))); - uintptr_t end_of_range = - std::min(uintptr_t(ip + (kIPMemorySize / 2)), - uintptr_t(addr + size)); + uintptr_t end_of_range = std::min(uintptr_t(ip + (kIPMemorySize / 2)), + uintptr_t(addr + size)); uintptr_t range_diff = end_of_range - static_cast(ip_memory_d.start_of_memory_range); ip_memory_d.memory.data_size = static_cast(range_diff); @@ -1180,7 +1246,7 @@ bool MinidumpGenerator::WriteSystemInfoStream( // CPU Information uint32_t number_of_processors; size_t len = sizeof(number_of_processors); - sysctlbyname("hw.ncpu", &number_of_processors, &len, NULL, 0); + sysctlbyname("hw.ncpu", &number_of_processors, &len, nullptr, 0); MDRawSystemInfo* info_ptr = info.get(); switch (cpu_type_) { @@ -1449,7 +1515,7 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule* module, int cpu_type, unsigned char identifier[16]; bool result = false; if (in_memory) { - MacFileUtilities::MachoID macho(module_path, + MacFileUtilities::MachoID macho( reinterpret_cast(module->base_of_image), static_cast(module->size_of_image)); result = macho.UUIDCommand(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier); @@ -1557,7 +1623,7 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory* misc_info_stream) { uint mibsize = static_cast(sizeof(mib) / sizeof(mib[0])); struct kinfo_proc proc; size_t size = sizeof(proc); - if (sysctl(mib, mibsize, &proc, &size, NULL, 0) == 0) { + if (sysctl(mib, mibsize, &proc, &size, nullptr, 0) == 0) { info_ptr->process_create_time = static_cast(proc.kp_proc.p_starttime.tv_sec); } @@ -1566,11 +1632,11 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory* misc_info_stream) { uint64_t speed; const uint64_t kOneMillion = 1000 * 1000; size = sizeof(speed); - sysctlbyname("hw.cpufrequency_max", &speed, &size, NULL, 0); + sysctlbyname("hw.cpufrequency_max", &speed, &size, nullptr, 0); info_ptr->processor_max_mhz = static_cast(speed / kOneMillion); info_ptr->processor_mhz_limit = static_cast(speed / kOneMillion); size = sizeof(speed); - sysctlbyname("hw.cpufrequency", &speed, &size, NULL, 0); + sysctlbyname("hw.cpufrequency", &speed, &size, nullptr, 0); info_ptr->processor_current_mhz = static_cast(speed / kOneMillion); return true; diff --git a/src/client/mac/handler/minidump_generator.h b/src/client/mac/handler/minidump_generator.h index e3a271b0b..d74b28f1e 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. // @@ -45,6 +44,7 @@ #include "dynamic_images.h" #include "mach_vm_compat.h" +#include "AvailabilityMacros.h" #if !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7) #define HAS_PPC_SUPPORT @@ -131,6 +131,9 @@ class MinidumpGenerator { // the MinidumpGenerator class. static void GatherSystemInformation(); + // Get context of |thread_id| thread + bool GetThreadContext(mach_port_t thread_id, breakpad_ucontext_t* context); + protected: // Overridable Stream writers virtual bool WriteExceptionStream(MDRawDirectory* exception_stream); @@ -176,6 +179,8 @@ class MinidumpGenerator { #ifdef HAS_ARM64_SUPPORT bool WriteStackARM64(breakpad_thread_state_data_t state, MDMemoryDescriptor* stack_location); + void GetContextARM64(breakpad_thread_state_data_t state, + MDRawContextARM64_Old* context_ptr); bool WriteContextARM64(breakpad_thread_state_data_t state, MDLocationDescriptor* register_location); uint64_t CurrentPCForStackARM64(breakpad_thread_state_data_t state); @@ -200,6 +205,8 @@ class MinidumpGenerator { uint64_t CurrentPCForStackX86(breakpad_thread_state_data_t state); bool WriteStackX86_64(breakpad_thread_state_data_t state, MDMemoryDescriptor* stack_location); + void GetContextX86_64(breakpad_thread_state_data_t state, + MDRawContextAMD64* context_ptr); bool WriteContextX86_64(breakpad_thread_state_data_t state, MDLocationDescriptor* register_location); uint64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state); diff --git a/src/client/mac/handler/protected_memory_allocator.cc b/src/client/mac/handler/protected_memory_allocator.cc index 6142ad124..8e70b05ed 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. // @@ -31,6 +30,10 @@ // // See the header file for documentation +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "protected_memory_allocator.h" #include @@ -66,7 +69,7 @@ char *ProtectedMemoryAllocator::Allocate(vm_size_t bytes) { return p; } - return NULL; // ran out of memory in our allocation block + return nullptr; // ran out of memory in our allocation block } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/client/mac/handler/protected_memory_allocator.h b/src/client/mac/handler/protected_memory_allocator.h index 7e188db26..86413c879 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 0a80e434c..d7564fc9c 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,9 +30,13 @@ // minidump_test // // Created by Neal Sidhwaney on 4/17/08. -// Copyright 2008 Google Inc. All rights reserved. +// Copyright 2008 Google LLC // +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/mac/handler/testcases/DynamicImagesTests.h" #include "client/mac/handler/dynamic_images.h" diff --git a/src/client/mac/handler/testcases/DynamicImagesTests.h b/src/client/mac/handler/testcases/DynamicImagesTests.h index e1e79993b..f60ee69c6 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 2014b9078..aeec44fb5 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,9 +30,13 @@ // minidump_test // // Created by Neal Sidhwaney on 4/13/08. -// Copyright 2008 Google Inc. All rights reserved. +// Copyright 2008 Google LLC // +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/mac/handler/testcases/breakpad_nlist_test.h" #include #include "client/mac/handler/breakpad_nlist_64.h" @@ -70,7 +73,7 @@ void BreakpadNlistTest::CompareToNM() { symbolNames[0] = (const char*)symbolName; symbolNames[1] = "\0"; breakpad_nlist_64("/usr/lib/dyld", &list, symbolNames); - uint64_t nmAddr = strtol(oneNMAddr, NULL, 16); + uint64_t nmAddr = strtol(oneNMAddr, nullptr, 16); if (!IsSymbolMoreThanOnceInDyld(symbolName)) { CPTAssert(nmAddr == symbolList[0].n_value); } diff --git a/src/client/mac/handler/testcases/breakpad_nlist_test.h b/src/client/mac/handler/testcases/breakpad_nlist_test.h index ee8010c75..ca407ea8f 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 // // diff --git a/src/client/mac/handler/testcases/dwarftests.h b/src/client/mac/handler/testcases/dwarftests.h index 21ff7a44f..0c35374a3 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 diff --git a/src/client/mac/handler/testcases/dwarftests.mm b/src/client/mac/handler/testcases/dwarftests.mm index 40c69aff2..c02a2d23e 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 1e4b752e5..ce5ae6e94 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. // @@ -30,8 +29,14 @@ #ifndef CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_ #define CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_ +#include #include +// do not have sense at least for mac 10.15 +#if defined(MAC_OS_X_VERSION_10_15) +typedef ucontext_t breakpad_ucontext_t; +#define breakpad_uc_mcontext uc_mcontext +#else // The purpose of this file is to work around the fact that ucontext_t's // uc_mcontext member is an mcontext_t rather than an mcontext64_t on ARM64. #if defined(__aarch64__) @@ -43,5 +48,6 @@ typedef ucontext64_t breakpad_ucontext_t; typedef ucontext_t breakpad_ucontext_t; #define breakpad_uc_mcontext uc_mcontext #endif // defined(__aarch64__) +#endif #endif // CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_ diff --git a/src/client/mac/sender/crash_report_sender.h b/src/client/mac/sender/crash_report_sender.h index 6a29d48a1..13379ceaa 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 88d26fb03..170fa07f6 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 0897dade0..4eba71633 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 13b6130ad..f2bcd0b17 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 7b3be2d69..36f9572aa 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 87c43024b..2de84f3f1 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 0a6d736d1..e20b0e877 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 6e6a8833d..ed0a7eca3 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 de6733269..af2cc1411 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. // diff --git a/src/client/mac/tests/BreakpadFramework_Test.mm b/src/client/mac/tests/BreakpadFramework_Test.mm index 2ea103c69..7a7013306 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 128f25c10..4dd18f900 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. // @@ -30,6 +29,10 @@ // crash_generation_server_test.cc // Unit tests for CrashGenerationServer +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -99,12 +102,12 @@ int CrashGenerationServerTest::i = 0; // Test that starting and stopping a server works TEST_F(CrashGenerationServerTest, testStartStopServer) { CrashGenerationServer server(mach_port_name, - NULL, // filter callback - NULL, // filter context - NULL, // dump callback - NULL, // dump context - NULL, // exit callback - NULL, // exit context + nullptr, // filter callback + nullptr, // filter context + nullptr, // dump callback + nullptr, // dump context + nullptr, // exit callback + nullptr, // exit context false, // generate dumps ""); // dump path ASSERT_TRUE(server.Start()); @@ -115,12 +118,12 @@ TEST_F(CrashGenerationServerTest, testStartStopServer) { // Test without actually dumping TEST_F(CrashGenerationServerTest, testRequestDumpNoDump) { CrashGenerationServer server(mach_port_name, - NULL, // filter callback - NULL, // filter context - NULL, // dump callback - NULL, // dump context - NULL, // exit callback - NULL, // exit context + nullptr, // filter callback + nullptr, // filter context + nullptr, // dump callback + nullptr, // dump context + nullptr, // exit callback + nullptr, // exit context false, // don't generate dumps temp_dir.path()); // dump path ASSERT_TRUE(server.Start()); @@ -141,7 +144,7 @@ TEST_F(CrashGenerationServerTest, testRequestDumpNoDump) { // check that no minidump was written string pattern = temp_dir.path() + "/*"; glob_t dirContents; - ret = glob(pattern.c_str(), GLOB_NOSORT, NULL, &dirContents); + ret = glob(pattern.c_str(), GLOB_NOSORT, nullptr, &dirContents); EXPECT_EQ(GLOB_NOMATCH, ret); if (ret != GLOB_NOMATCH) globfree(&dirContents); @@ -167,12 +170,12 @@ void* RequestDump(void* context) { // Test that actually writing a minidump works TEST_F(CrashGenerationServerTest, testRequestDump) { CrashGenerationServer server(mach_port_name, - NULL, // filter callback - NULL, // filter context + nullptr, // filter callback + nullptr, // filter context dumpCallback, // dump callback this, // dump context - NULL, // exit callback - NULL, // exit context + nullptr, // exit callback + nullptr, // exit context true, // generate dumps temp_dir.path()); // dump path ASSERT_TRUE(server.Start()); @@ -184,7 +187,8 @@ TEST_F(CrashGenerationServerTest, testRequestDump) { // because MinidumpGenerator assumes the handler thread is not // the only thread pthread_t thread; - if (pthread_create(&thread, NULL, RequestDump, (void*)mach_port_name) != 0) + if (pthread_create(&thread, nullptr, RequestDump, (void*)mach_port_name) + != 0) exit(1); void* result; pthread_join(thread, &result); @@ -217,12 +221,12 @@ static void Crasher() { // the parent. TEST_F(CrashGenerationServerTest, testChildProcessCrash) { CrashGenerationServer server(mach_port_name, - NULL, // filter callback - NULL, // filter context + nullptr, // filter callback + nullptr, // filter context dumpCallback, // dump callback this, // dump context - NULL, // exit callback - NULL, // exit context + nullptr, // exit callback + nullptr, // exit context true, // generate dumps temp_dir.path()); // dump path ASSERT_TRUE(server.Start()); @@ -231,7 +235,7 @@ TEST_F(CrashGenerationServerTest, testChildProcessCrash) { ASSERT_NE(-1, pid); if (pid == 0) { // Instantiate an OOP exception handler. - ExceptionHandler eh("", NULL, NULL, NULL, true, mach_port_name); + ExceptionHandler eh("", nullptr, nullptr, nullptr, true, mach_port_name); Crasher(); // not reached exit(0); @@ -280,12 +284,12 @@ TEST_F(CrashGenerationServerTest, testChildProcessCrash) { // produces a valid minidump. TEST_F(CrashGenerationServerTest, testChildProcessCrashCrossArchitecture) { CrashGenerationServer server(mach_port_name, - NULL, // filter callback - NULL, // filter context + nullptr, // filter callback + nullptr, // filter context dumpCallback, // dump callback this, // dump context - NULL, // exit callback - NULL, // exit context + nullptr, // exit callback + nullptr, // exit context true, // generate dumps temp_dir.path()); // dump path ASSERT_TRUE(server.Start()); @@ -296,7 +300,7 @@ TEST_F(CrashGenerationServerTest, testChildProcessCrashCrossArchitecture) { helper_path.c_str(), "crash", mach_port_name, - NULL + nullptr }; pid_t pid = spawn_child_process(argv); ASSERT_NE(-1, pid); @@ -369,8 +373,8 @@ TEST_F(CrashGenerationServerTest, testFilter) { this, // filter context dumpCallback, // dump callback this, // dump context - NULL, // exit callback - NULL, // exit context + nullptr, // exit callback + nullptr, // exit context true, // generate dumps temp_dir.path()); // dump path ASSERT_TRUE(server.Start()); @@ -379,7 +383,7 @@ TEST_F(CrashGenerationServerTest, testFilter) { ASSERT_NE(-1, pid); if (pid == 0) { // Instantiate an OOP exception handler. - ExceptionHandler eh("", NULL, NULL, NULL, true, mach_port_name); + ExceptionHandler eh("", nullptr, nullptr, nullptr, true, mach_port_name); Crasher(); // not reached exit(0); diff --git a/src/client/mac/tests/exception_handler_test.cc b/src/client/mac/tests/exception_handler_test.cc index 50f03f81b..fb42c8bb2 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. // @@ -29,6 +28,10 @@ // exception_handler_test.cc: Unit tests for google_breakpad::ExceptionHandler +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -110,7 +113,8 @@ void ExceptionHandlerTest::InProcessCrash(bool aborting) { if (pid == 0) { // In the child process. close(fds[0]); - ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL); + ExceptionHandler eh(tempDir.path(), nullptr, MDCallback, &fds[1], true, + nullptr); // crash SoonToCrash(aborting ? &AbortCrasher : &Crasher); // not reached @@ -192,8 +196,8 @@ static bool DumpNameMDCallback(const char* dump_dir, const char* file_name, } TEST_F(ExceptionHandlerTest, WriteMinidump) { - ExceptionHandler eh(tempDir.path(), NULL, DumpNameMDCallback, this, true, - NULL); + ExceptionHandler eh(tempDir.path(), nullptr, DumpNameMDCallback, this, true, + nullptr); ASSERT_TRUE(eh.WriteMinidump()); // Ensure that minidump file exists and is > 0 bytes. @@ -211,8 +215,8 @@ TEST_F(ExceptionHandlerTest, WriteMinidump) { } TEST_F(ExceptionHandlerTest, WriteMinidumpWithException) { - ExceptionHandler eh(tempDir.path(), NULL, DumpNameMDCallback, this, true, - NULL); + ExceptionHandler eh(tempDir.path(), nullptr, DumpNameMDCallback, this, true, + nullptr); ASSERT_TRUE(eh.WriteMinidump(true)); // Ensure that minidump file exists and is > 0 bytes. @@ -320,10 +324,11 @@ TEST_F(ExceptionHandlerTest, InstructionPointerMemory) { pid_t pid = fork(); if (pid == 0) { close(fds[0]); - ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL); + ExceptionHandler eh(tempDir.path(), nullptr, MDCallback, &fds[1], true, + nullptr); // Get some executable memory. char* memory = - reinterpret_cast(mmap(NULL, + reinterpret_cast(mmap(nullptr, kMemorySize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, @@ -419,10 +424,11 @@ TEST_F(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { pid_t pid = fork(); if (pid == 0) { close(fds[0]); - ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL); + ExceptionHandler eh(tempDir.path(), nullptr, MDCallback, &fds[1], true, + nullptr); // Get some executable memory. char* memory = - reinterpret_cast(mmap(NULL, + reinterpret_cast(mmap(nullptr, kMemorySize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, @@ -518,10 +524,11 @@ TEST_F(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { pid_t pid = fork(); if (pid == 0) { close(fds[0]); - ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL); + ExceptionHandler eh(tempDir.path(), nullptr, MDCallback, &fds[1], true, + nullptr); // Get some executable memory. char* memory = - reinterpret_cast(mmap(NULL, + reinterpret_cast(mmap(nullptr, kMemorySize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, @@ -608,13 +615,14 @@ TEST_F(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) { pid_t pid = fork(); if (pid == 0) { close(fds[0]); - ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL); + ExceptionHandler eh(tempDir.path(), nullptr, MDCallback, &fds[1], true, + nullptr); // Try calling a NULL pointer. typedef void (*void_function)(void); // Volatile markings are needed to keep Clang from generating invalid // opcodes. See http://crbug.com/498354 for details. volatile void_function memory_function = - reinterpret_cast(NULL); + static_cast(nullptr); memory_function(); // not reached exit(1); @@ -654,7 +662,7 @@ TEST_F(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) { static void* Junk(void*) { sleep(1000000); - return NULL; + return nullptr; } // Test that the memory list gets written correctly when multiple @@ -667,11 +675,12 @@ TEST_F(ExceptionHandlerTest, MemoryListMultipleThreads) { pid_t pid = fork(); if (pid == 0) { close(fds[0]); - ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL); + ExceptionHandler eh(tempDir.path(), nullptr, MDCallback, &fds[1], true, + nullptr); // Run an extra thread so >2 memory regions will be written. pthread_t junk_thread; - if (pthread_create(&junk_thread, NULL, Junk, NULL) == 0) + if (pthread_create(&junk_thread, nullptr, Junk, nullptr) == 0) pthread_detach(junk_thread); // Just crash. diff --git a/src/client/mac/tests/minidump_generator_test.cc b/src/client/mac/tests/minidump_generator_test.cc index 1f374657a..4ab6abfba 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. // @@ -29,6 +28,10 @@ // minidump_generator_test.cc: Unit tests for google_breakpad::MinidumpGenerator +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #ifndef MAC_OS_X_VERSION_10_6 #define MAC_OS_X_VERSION_10_6 1060 @@ -84,19 +87,19 @@ static void* Junk(void* data) { while (!*wait) { usleep(10000); } - return NULL; + return nullptr; } TEST_F(MinidumpGeneratorTest, InProcess) { MinidumpGenerator generator; string dump_filename = - MinidumpGenerator::UniqueNameInDirectory(tempDir.path(), NULL); + MinidumpGenerator::UniqueNameInDirectory(tempDir.path(), nullptr); // Run an extra thread since MinidumpGenerator assumes there // are 2 or more threads. pthread_t junk_thread; bool quit = false; - ASSERT_EQ(0, pthread_create(&junk_thread, NULL, Junk, &quit)); + ASSERT_EQ(0, pthread_create(&junk_thread, nullptr, Junk, &quit)); ASSERT_TRUE(generator.Write(dump_filename.c_str())); // Ensure that minidump file exists and is > 0 bytes. @@ -106,7 +109,7 @@ TEST_F(MinidumpGeneratorTest, InProcess) { // join the background thread quit = true; - pthread_join(junk_thread, NULL); + pthread_join(junk_thread, nullptr); // Read the minidump, sanity check some data. Minidump minidump(dump_filename.c_str()); @@ -181,7 +184,7 @@ TEST_F(MinidumpGeneratorTest, OutOfProcess) { // Write a minidump of the child process. MinidumpGenerator generator(child_task, MACH_PORT_NULL); string dump_filename = - MinidumpGenerator::UniqueNameInDirectory(tempDir.path(), NULL); + MinidumpGenerator::UniqueNameInDirectory(tempDir.path(), nullptr); ASSERT_TRUE(generator.Write(dump_filename.c_str())); // Ensure that minidump file exists and is > 0 bytes. @@ -245,7 +248,7 @@ TEST_F(MinidumpGeneratorTest, CrossArchitectureDump) { const char* argv[] = { helper_path.c_str(), machPortName, - NULL + nullptr }; pid_t pid = spawn_child_process(argv); ASSERT_NE(-1, pid); @@ -260,7 +263,7 @@ TEST_F(MinidumpGeneratorTest, CrossArchitectureDump) { // Write a minidump of the child process. MinidumpGenerator generator(child_task, MACH_PORT_NULL); string dump_filename = - MinidumpGenerator::UniqueNameInDirectory(tempDir.path(), NULL); + MinidumpGenerator::UniqueNameInDirectory(tempDir.path(), nullptr); ASSERT_TRUE(generator.Write(dump_filename.c_str())); // Ensure that minidump file exists and is > 0 bytes. diff --git a/src/client/mac/tests/minidump_generator_test_helper.cc b/src/client/mac/tests/minidump_generator_test_helper.cc index 4e8ce3cf0..34f22c74d 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. // @@ -31,6 +30,10 @@ // minidump_generator_test.cc can launch to test certain things // that require a separate executable. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "client/mac/handler/exception_handler.h" @@ -64,7 +67,8 @@ int main(int argc, char** argv) { } } else if (argc == 3 && strcmp(argv[1], "crash") == 0) { // Instantiate an OOP exception handler - google_breakpad::ExceptionHandler eh("", NULL, NULL, NULL, true, argv[2]); + google_breakpad::ExceptionHandler eh("", nullptr, nullptr, nullptr, true, + argv[2]); // and crash. int *a = (int*)0x42; *a = 1; diff --git a/src/client/mac/tests/spawn_child_process.h b/src/client/mac/tests/spawn_child_process.h index e52ff6b65..983816fc3 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. // @@ -130,9 +129,9 @@ pid_t spawn_child_process(const char** argv) { argv_v.push_back(strdup(*argv)); argv++; } - argv_v.push_back(NULL); + argv_v.push_back(nullptr); pid_t new_pid = 0; - int result = posix_spawnp(&new_pid, argv_v[0], NULL, &spawnattr, + int result = posix_spawnp(&new_pid, argv_v[0], nullptr, &spawnattr, &argv_v[0], *_NSGetEnviron()); posix_spawnattr_destroy(&spawnattr); diff --git a/src/client/minidump_file_writer-inl.h b/src/client/minidump_file_writer-inl.h index bdac2dae8..d95f3554d 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. // diff --git a/src/client/minidump_file_writer.cc b/src/client/minidump_file_writer.cc index 5c3c5cbb0..d82fd8158 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. // @@ -31,6 +30,11 @@ // // See minidump_file_writer.h for documentation. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include #include #include #include @@ -39,6 +43,7 @@ #include "client/minidump_file_writer-inl.h" #include "common/linux/linux_libc_support.h" +#include "common/memory_allocator.h" #include "common/string_conversion.h" #if defined(__linux__) && __linux__ #include "third_party/lss/linux_syscall_support.h" @@ -284,7 +289,7 @@ MDRVA MinidumpFileWriter::Allocate(size_t size) { return current_position; } #endif - size_t aligned_size = (size + 7) & ~7; // 64-bit alignment + size_t aligned_size = PageAllocator::AlignUp(size, 8); // 64-bit alignment if (position_ + aligned_size > size_) { size_t growth = aligned_size; diff --git a/src/client/minidump_file_writer.h b/src/client/minidump_file_writer.h index c66dc5912..253a93a97 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. // diff --git a/src/client/minidump_file_writer_unittest.cc b/src/client/minidump_file_writer_unittest.cc index 16c407d2e..21e0b8a1a 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. // @@ -37,6 +36,10 @@ -o minidump_file_writer_unittest */ +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include diff --git a/src/client/solaris/handler/Makefile b/src/client/solaris/handler/Makefile index 6da9464e6..b22fe5614 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 c96683f6f..69d2d09e7 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. // @@ -29,16 +28,20 @@ // Author: Alfred Peng +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "client/solaris/handler/exception_handler.h" + +#include #include +#include #include #include +#include #include -#include -#include -#include - -#include "client/solaris/handler/exception_handler.h" #include "common/solaris/guid_creator.h" #include "common/solaris/message_output.h" #include "google_breakpad/common/minidump_format.h" @@ -54,7 +57,7 @@ static const int kSigTable[] = { SIGBUS }; -std::vector* ExceptionHandler::handler_stack_ = NULL; +std::vector* ExceptionHandler::handler_stack_ = nullptr; int ExceptionHandler::handler_stack_index_ = 0; pthread_mutex_t ExceptionHandler::handler_stack_mutex_ = PTHREAD_MUTEX_INITIALIZER; @@ -78,7 +81,7 @@ ExceptionHandler::ExceptionHandler(const string& dump_path, if (install_handler) { pthread_mutex_lock(&handler_stack_mutex_); - if (handler_stack_ == NULL) + if (handler_stack_ == nullptr) handler_stack_ = new std::vector; handler_stack_->push_back(this); pthread_mutex_unlock(&handler_stack_mutex_); @@ -106,22 +109,22 @@ ExceptionHandler::~ExceptionHandler() { // When destroying the last ExceptionHandler that installed a handler, // clean up the handler stack. delete handler_stack_; - handler_stack_ = NULL; + handler_stack_ = nullptr; } pthread_mutex_unlock(&handler_stack_mutex_); } bool ExceptionHandler::WriteMinidump() { - return InternalWriteMinidump(0, 0, NULL); + return InternalWriteMinidump(0, 0, nullptr); } // static bool ExceptionHandler::WriteMinidump(const string& dump_path, MinidumpCallback callback, void* callback_context) { - ExceptionHandler handler(dump_path, NULL, callback, + ExceptionHandler handler(dump_path, nullptr, callback, callback_context, false); - return handler.InternalWriteMinidump(0, 0, NULL); + return handler.InternalWriteMinidump(0, 0, nullptr); } void ExceptionHandler::SetupHandler() { @@ -129,12 +132,12 @@ void ExceptionHandler::SetupHandler() { // of the crashing lwp. struct sigaltstack sig_stack; sig_stack.ss_sp = malloc(MINSIGSTKSZ); - if (sig_stack.ss_sp == NULL) + if (sig_stack.ss_sp == nullptr) return; sig_stack.ss_size = MINSIGSTKSZ; sig_stack.ss_flags = 0; - if (sigaltstack(&sig_stack, NULL) < 0) + if (sigaltstack(&sig_stack, nullptr) < 0) return; for (size_t i = 0; i < sizeof(kSigTable) / sizeof(kSigTable[0]); ++i) SetupHandler(kSigTable[i]); @@ -188,7 +191,7 @@ void ExceptionHandler::HandleException(int signo) { // Restore original handler. current_handler->TeardownHandler(signo); - ucontext_t* sig_ctx = NULL; + ucontext_t* sig_ctx = nullptr; if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) { // if (current_handler->InternalWriteMinidump(signo, &sig_ctx)) { // Fully handled this exception, safe to exit. @@ -199,7 +202,7 @@ void ExceptionHandler::HandleException(int signo) { typedef void (*SignalHandler)(int signo); SignalHandler old_handler = reinterpret_cast(current_handler->old_handlers_[signo]); - if (old_handler != NULL) + if (old_handler != nullptr) old_handler(signo); } diff --git a/src/client/solaris/handler/exception_handler.h b/src/client/solaris/handler/exception_handler.h index cd6c85ea1..04d140f02 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. // diff --git a/src/client/solaris/handler/exception_handler_test.cc b/src/client/solaris/handler/exception_handler_test.cc index 4d2b33faf..3d2f17930 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. // @@ -29,15 +28,19 @@ // Author: Alfred Peng +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "client/solaris/handler/exception_handler.h" + +#include #include +#include +#include +#include #include -#include -#include -#include -#include - -#include "client/solaris/handler/exception_handler.h" #include "client/solaris/handler/solaris_lwp.h" using namespace google_breakpad; @@ -66,18 +69,18 @@ static void* thread_crash(void*) { sleep(3); a = foo(a); printf("%x\n", a); - return NULL; + return nullptr; } static void* thread_main(void*) { while (!should_exit) sleep(1); - return NULL; + return nullptr; } static void CreateCrashThread() { pthread_t h; - pthread_create(&h, NULL, thread_crash, NULL); + pthread_create(&h, nullptr, thread_crash, nullptr); pthread_detach(h); } @@ -85,7 +88,7 @@ static void CreateCrashThread() { static void CreateThread(int num) { pthread_t h; for (int i = 0; i < num; ++i) { - pthread_create(&h, NULL, thread_main, NULL); + pthread_create(&h, nullptr, thread_main, nullptr); pthread_detach(h); } } @@ -106,7 +109,7 @@ static bool MinidumpCallback(const char* dump_path, int main(int argc, char* argv[]) { int handler_index = 1; - ExceptionHandler handler_ignore(".", NULL, MinidumpCallback, + ExceptionHandler handler_ignore(".", nullptr, MinidumpCallback, (void*)handler_index, true); CreateCrashThread(); CreateThread(10); diff --git a/src/client/solaris/handler/minidump_generator.cc b/src/client/solaris/handler/minidump_generator.cc index 567566655..9982d0bb1 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. // @@ -29,24 +28,30 @@ // Author: Alfred Peng +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "client/solaris/handler/minidump_generator.h" + +#include #include +#include #include #include #include #include #include +#include #include -#include -#include - -#include "client/solaris/handler/minidump_generator.h" #include "client/minidump_file_writer-inl.h" #include "common/solaris/file_id.h" namespace { using namespace google_breakpad; +using namespace google_breakpad::elf::FileID; // Argument for the writer function. struct WriterArgument { @@ -86,7 +91,7 @@ struct FindCrashLwpContext { int crashing_lwpid; FindCrashLwpContext() : - lwp_lister(NULL), + lwp_lister(nullptr), crashing_stack_bottom(0UL), crashing_lwpid(-1) { } @@ -152,7 +157,7 @@ bool WriteLwpStack(const SolarisLwp* lwp_lister, #if TARGET_CPU_SPARC bool WriteContext(MDRawContextSPARC* context, ucontext_t* sig_ctx) { - assert(sig_ctx != NULL); + assert(sig_ctx != nullptr); int* regs = sig_ctx->uc_mcontext.gregs; context->context_flags = MD_CONTEXT_SPARC_FULL; @@ -232,7 +237,7 @@ bool WriteCrashedLwpStream(MinidumpFileWriter* minidump_writer, const WriterArgument* writer_args, const lwpstatus_t* lsp, MDRawThread* lwp) { - assert(writer_args->sig_ctx != NULL); + assert(writer_args->sig_ctx != nullptr); lwp->thread_id = lsp->pr_lwpid; @@ -333,7 +338,7 @@ bool WriteCPUInformation(MDRawSystemInfo* sys_info) { build = strchr(uts.version, '_'); ++build; sys_info->build_number = atoi(build); - + return true; } @@ -352,10 +357,10 @@ bool WriteOSInformation(MinidumpFileWriter* minidump_writer, uts.version, uts.machine, "OpenSolaris", - NULL + nullptr }; for (const char** cur_os_info = os_info_table; - *cur_os_info != NULL; + *cur_os_info != nullptr; ++cur_os_info) { if (cur_os_info != os_info_table && space_left > 1) { strcat(os_version, " "); @@ -398,7 +403,7 @@ bool LwpInformationCallback(lwpstatus_t* lsp, void* context) { memset(&lwp, 0, sizeof(MDRawThread)); if (lsp->pr_lwpid != callback_context->writer_args->crashed_lwpid || - callback_context->writer_args->sig_ctx == NULL) { + callback_context->writer_args->sig_ctx == nullptr) { success = WriteLwpStream(callback_context->minidump_writer, callback_context->writer_args->lwp_lister, lsp, &lwp); @@ -515,7 +520,7 @@ bool ModuleInfoCallback(const ModuleInfo& module_info, void* context) { return false; buf[count] = '\0'; - if ((realname = strrchr(buf, '/')) == NULL) + if ((realname = strrchr(buf, '/')) == nullptr) return false; realname++; @@ -577,7 +582,7 @@ 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) + if (writer_args->sig_ctx == nullptr) return false; TypedMDRVA exception(minidump_writer); @@ -591,9 +596,9 @@ bool WriteExceptionStream(MinidumpFileWriter* minidump_writer, exception.get()->exception_record.exception_flags = 0; #if TARGET_CPU_SPARC - if (writer_args->sig_ctx != NULL) { - exception.get()->exception_record.exception_address = - writer_args->sig_ctx->uc_mcontext.gregs[REG_PC]; + if (writer_args->sig_ctx != nullptr) { + exception.get()->exception_record.exception_address = + writer_args->sig_ctx->uc_mcontext.gregs[REG_PC]; } else { return true; } @@ -606,7 +611,7 @@ bool WriteExceptionStream(MinidumpFileWriter* minidump_writer, memset(context.get(), 0, sizeof(MDRawContextSPARC)); return WriteContext(context.get(), writer_args->sig_ctx); #elif TARGET_CPU_X86 - if (writer_args->sig_ctx != NULL) { + if (writer_args->sig_ctx != nullptr) { exception.get()->exception_record.exception_address = writer_args->sig_ctx->uc_mcontext.gregs[EIP]; } else { @@ -621,7 +626,7 @@ bool WriteExceptionStream(MinidumpFileWriter* minidump_writer, memset(context.get(), 0, sizeof(MDRawContextX86)); return WriteContext(context.get(), (int*)&writer_args->sig_ctx->uc_mcontext.gregs, - NULL); + nullptr); #endif } @@ -689,21 +694,21 @@ void* Write(void* argument) { WriterArgument* writer_args = static_cast(argument); if (!writer_args->lwp_lister->ControlAllLwps(true)) - return NULL; + return nullptr; AutoLwpResumer lwpResumer(writer_args->lwp_lister); if (writer_args->sighandler_ebp != 0 && writer_args->lwp_lister->FindSigContext(writer_args->sighandler_ebp, &writer_args->sig_ctx)) { - writer_args->crashed_stack_bottom = - writer_args->lwp_lister->GetLwpStackBottom( + writer_args->crashed_stack_bottom = + writer_args->lwp_lister->GetLwpStackBottom( #if TARGET_CPU_SPARC - writer_args->sig_ctx->uc_mcontext.gregs[REG_O6] + writer_args->sig_ctx->uc_mcontext.gregs[REG_O6] #elif TARGET_CPU_X86 - writer_args->sig_ctx->uc_mcontext.gregs[UESP] + writer_args->sig_ctx->uc_mcontext.gregs[UESP] #endif - ); + ); int crashed_lwpid = FindCrashingLwp(writer_args->crashed_stack_bottom, writer_args->requester_pid, @@ -724,7 +729,7 @@ void* Write(void* argument) { return 0; header.get()->signature = MD_HEADER_SIGNATURE; header.get()->version = MD_HEADER_VERSION; - header.get()->time_date_stamp = time(NULL); + header.get()->time_date_stamp = time(nullptr); header.get()->stream_count = writer_count; header.get()->stream_directory_rva = dir.position(); @@ -757,9 +762,9 @@ bool MinidumpGenerator::WriteMinidumpToFile(const char* file_pathname, // The exception handler thread. pthread_t handler_thread; - assert(file_pathname != NULL); + assert(file_pathname != nullptr); - if (file_pathname == NULL) + if (file_pathname == nullptr) return false; MinidumpFileWriter minidump_writer; @@ -773,10 +778,10 @@ bool MinidumpGenerator::WriteMinidumpToFile(const char* file_pathname, argument.crashed_lwpid = pthread_self(); argument.signo = signo; argument.sighandler_ebp = sighandler_ebp; - argument.sig_ctx = NULL; + argument.sig_ctx = nullptr; - pthread_create(&handler_thread, NULL, Write, (void*)&argument); - pthread_join(handler_thread, NULL); + pthread_create(&handler_thread, nullptr, Write, (void*)&argument); + pthread_join(handler_thread, nullptr); return true; } diff --git a/src/client/solaris/handler/minidump_generator.h b/src/client/solaris/handler/minidump_generator.h index daa6fe015..7d2adbce5 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. // diff --git a/src/client/solaris/handler/minidump_test.cc b/src/client/solaris/handler/minidump_test.cc index 5f685ef24..7a20eb827 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. // @@ -29,6 +28,10 @@ // Author: Alfred Peng +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -48,10 +51,10 @@ static void* Reporter(void*) { snprintf(buffer, sizeof(buffer), "./minidump_test.out"); fprintf(stdout, "Writing %s\n", buffer); - md.WriteMinidumpToFile(buffer, 0, 0, NULL); + md.WriteMinidumpToFile(buffer, 0, 0, nullptr); doneWritingReport = true; - return NULL; + return nullptr; } static void SleepyFunction() { @@ -63,7 +66,7 @@ static void SleepyFunction() { int main(int argc, char * const argv[]) { pthread_t reporter_thread; - if (pthread_create(&reporter_thread, NULL, Reporter, NULL) == 0) { + if (pthread_create(&reporter_thread, nullptr, Reporter, nullptr) == 0) { pthread_detach(reporter_thread); } else { perror("pthread_create"); diff --git a/src/client/solaris/handler/solaris_lwp.cc b/src/client/solaris/handler/solaris_lwp.cc index cb6cc8ab9..77c6bcd54 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. // @@ -29,11 +28,20 @@ // Author: Alfred Peng +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "client/solaris/handler/solaris_lwp.h" + +#include #include #include #include #include #include +#include +#include #include #include #include @@ -41,12 +49,8 @@ #include #include -#include -#include -#include #include -#include "client/solaris/handler/solaris_lwp.h" #include "common/solaris/message_output.h" using namespace google_breakpad; @@ -70,9 +74,9 @@ struct AddressValidatingContext { // Convert from string to int. static bool LocalAtoi(char* s, int* r) { - assert(s != NULL); - assert(r != NULL); - char* endptr = NULL; + assert(s != nullptr); + assert(r != nullptr); + char* endptr = nullptr; int ret = strtol(s, &endptr, 10); if (endptr == s) return false; @@ -103,11 +107,11 @@ static int IterateLwpAll(int pid, int count = 0; snprintf(lwp_path, sizeof (lwp_path), "/proc/%d/lwp", (int)pid); - if ((dir = opendir(lwp_path)) == NULL) + if ((dir = opendir(lwp_path)) == nullptr) return -1; - struct dirent* entry = NULL; - while ((entry = readdir(dir)) != NULL) { + struct dirent* entry = nullptr; + while ((entry = readdir(dir)) != nullptr) { if ((strcmp(entry->d_name, ".") != 0) && (strcmp(entry->d_name, "..") != 0)) { int lwpid = 0; @@ -131,11 +135,11 @@ static int IterateLwpAll(int pid, void* GetNextFrame(void** last_ebp) { void* sp = *last_ebp; if ((unsigned long)sp == (unsigned long)last_ebp) - return NULL; + return nullptr; if ((unsigned long)sp & (sizeof(void*) - 1)) - return NULL; + return nullptr; if ((unsigned long)sp - (unsigned long)last_ebp > 100000) - return NULL; + return nullptr; return sp; } #elif defined(__sparc) @@ -238,7 +242,7 @@ int SolarisLwp::ControlAllLwps(bool suspend) { } int SolarisLwp::GetLwpCount() const { - return IterateLwpAll(pid_, NULL); + return IterateLwpAll(pid_, nullptr); } int SolarisLwp::Lwp_iter_all(int pid, @@ -258,9 +262,9 @@ int SolarisLwp::Lwp_iter_all(int pid, * The /proc/pid/lstatus file has the array of lwpstatus_t's and the * /proc/pid/lpsinfo file has the array of lwpsinfo_t's. */ - if (read_lfile(pid, "lstatus", Lhp) == NULL) + if (read_lfile(pid, "lstatus", Lhp) == nullptr) return -1; - if (read_lfile(pid, "lpsinfo", Lphp) == NULL) { + if (read_lfile(pid, "lpsinfo", Lphp) == nullptr) { return -1; } @@ -272,7 +276,7 @@ int SolarisLwp::Lwp_iter_all(int pid, sp = Lsp; Lsp = (lwpstatus_t*)((uintptr_t)Lsp + Lhp->pr_entsize); } else { - sp = NULL; + sp = nullptr; } if (callback_param && !(callback_param->call_back)(sp, callback_param->context)) @@ -294,7 +298,7 @@ uintptr_t SolarisLwp::GetLwpStackBottom(uintptr_t current_esp) const { } int SolarisLwp::GetModuleCount() const { - return ListModules(NULL); + return ListModules(nullptr); } int SolarisLwp::ListModules( @@ -317,7 +321,7 @@ int SolarisLwp::ListModules( return -1; /* - * Determine number of mappings, this value must be + * Determine number of mappings, this value must be * larger than the actual module count */ size = status.st_size; @@ -334,7 +338,7 @@ int SolarisLwp::ListModules( prmap_t* _maps; int _num; int module_count = 0; - + /* * Scan each mapping - note it is assummed that the mappings are * presented in order. We fill holes between mappings. On intel diff --git a/src/client/solaris/handler/solaris_lwp.h b/src/client/solaris/handler/solaris_lwp.h index afe352ce6..f2fe7c197 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. // @@ -90,7 +89,7 @@ struct CallbackParam { // Callback context; void* context; - CallbackParam() : call_back(NULL), context(NULL) { + CallbackParam() : call_back(nullptr), context(nullptr) { } CallbackParam(CallbackFunc func, void* func_context) : diff --git a/src/client/windows/breakpad_client.gyp b/src/client/windows/breakpad_client.gyp deleted file mode 100644 index 647975342..000000000 --- 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 3fd4b9b7e..75ed4b9b0 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 c74868198..31667b567 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. // @@ -47,8 +46,8 @@ struct CustomInfoEntry { CustomInfoEntry() { // Putting name and value in initializer list makes VC++ show warning 4351. - set_name(NULL); - set_value(NULL); + set_name(nullptr); + set_value(nullptr); } CustomInfoEntry(const wchar_t* name_arg, const wchar_t* value_arg) { @@ -106,12 +105,12 @@ struct ProtocolMessage { id(0), dump_type(MiniDumpNormal), thread_id(0), - exception_pointers(NULL), - assert_info(NULL), + exception_pointers(nullptr), + assert_info(nullptr), custom_client_info(), - dump_request_handle(NULL), - dump_generated_handle(NULL), - server_alive_handle(NULL) { + dump_request_handle(nullptr), + dump_generated_handle(nullptr), + server_alive_handle(nullptr) { } // Creates an instance with the given parameters. diff --git a/src/client/windows/crash_generation/client_info.cc b/src/client/windows/crash_generation/client_info.cc index ed3126381..75eca7947 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/windows/crash_generation/client_info.h" #include "client/windows/common/ipc_protocol.h" @@ -49,12 +52,12 @@ ClientInfo::ClientInfo(CrashGenerationServer* crash_server, assert_info_(assert_info), custom_client_info_(custom_client_info), thread_id_(thread_id), - process_handle_(NULL), - dump_requested_handle_(NULL), - dump_generated_handle_(NULL), - dump_request_wait_handle_(NULL), - process_exit_wait_handle_(NULL), - crash_id_(NULL) { + process_handle_(nullptr), + dump_requested_handle_(nullptr), + dump_generated_handle_(nullptr), + dump_request_wait_handle_(nullptr), + process_exit_wait_handle_(nullptr), + crash_id_(0) { GetSystemTimeAsFileTime(&start_time_); } @@ -72,26 +75,26 @@ bool ClientInfo::Initialize() { } crash_id_ = start_time_.dwLowDateTime; - dump_requested_handle_ = CreateEvent(NULL, // Security attributes. - TRUE, // Manual reset. - FALSE, // Initial state. - NULL); // Name. + dump_requested_handle_ = CreateEvent(nullptr, // Security attributes. + TRUE, // Manual reset. + FALSE, // Initial state. + nullptr); // Name. if (!dump_requested_handle_) { return false; } - dump_generated_handle_ = CreateEvent(NULL, // Security attributes. - TRUE, // Manual reset. - FALSE, // Initial state. - NULL); // Name. - return dump_generated_handle_ != NULL; + dump_generated_handle_ = CreateEvent(nullptr, // Security attributes. + TRUE, // Manual reset. + FALSE, // Initial state. + nullptr); // Name. + return dump_generated_handle_ != nullptr; } void ClientInfo::UnregisterDumpRequestWaitAndBlockUntilNoPending() { if (dump_request_wait_handle_) { // Wait for callbacks that might already be running to finish. UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE); - dump_request_wait_handle_ = NULL; + dump_request_wait_handle_ = nullptr; } } @@ -103,7 +106,7 @@ void ClientInfo::UnregisterProcessExitWait(bool block_until_no_pending) { } else { UnregisterWait(process_exit_wait_handle_); } - process_exit_wait_handle_ = NULL; + process_exit_wait_handle_ = nullptr; } } diff --git a/src/client/windows/crash_generation/client_info.h b/src/client/windows/crash_generation/client_info.h index 6a8fba31f..1c9cd3c3e 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 ba343768a..000000000 --- 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 3ba5d4e4f..9f5cc6f32 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. // @@ -27,9 +26,16 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/windows/crash_generation/crash_generation_client.h" -#include + +#include + #include + #include "client/windows/common/ipc_protocol.h" namespace google_breakpad { @@ -78,7 +84,7 @@ static bool TransactNamedPipeDebugHelper(HANDLE pipe, in_buffer, in_size, bytes_count, - NULL)) { + nullptr)) { return false; } @@ -86,7 +92,7 @@ static bool TransactNamedPipeDebugHelper(HANDLE pipe, // and read. // Sleep(5000); - return ReadFile(pipe, out_buffer, out_size, bytes_count, NULL) != FALSE; + return ReadFile(pipe, out_buffer, out_size, bytes_count, nullptr) != FALSE; } **/ @@ -95,15 +101,15 @@ CrashGenerationClient::CrashGenerationClient( MINIDUMP_TYPE dump_type, const CustomClientInfo* custom_info) : pipe_name_(pipe_name), - pipe_handle_(NULL), + pipe_handle_(nullptr), custom_info_(), dump_type_(dump_type), - crash_event_(NULL), - crash_generated_(NULL), - server_alive_(NULL), + crash_event_(nullptr), + crash_generated_(nullptr), + server_alive_(nullptr), server_process_id_(0), thread_id_(0), - exception_pointers_(NULL) { + exception_pointers_(nullptr) { memset(&assert_info_, 0, sizeof(assert_info_)); if (custom_info) { custom_info_ = *custom_info; @@ -118,12 +124,12 @@ CrashGenerationClient::CrashGenerationClient( pipe_handle_(pipe_handle), custom_info_(), dump_type_(dump_type), - crash_event_(NULL), - crash_generated_(NULL), - server_alive_(NULL), + crash_event_(nullptr), + crash_generated_(nullptr), + server_alive_(nullptr), server_process_id_(0), thread_id_(0), - exception_pointers_(NULL) { + exception_pointers_(nullptr) { memset(&assert_info_, 0, sizeof(assert_info_)); if (custom_info) { custom_info_ = *custom_info; @@ -198,12 +204,12 @@ bool CrashGenerationClient::RequestUpload(DWORD crash_id) { return false; } - CustomClientInfo custom_info = {NULL, 0}; + CustomClientInfo custom_info = {nullptr, 0}; ProtocolMessage msg(MESSAGE_TAG_UPLOAD_REQUEST, crash_id, - static_cast(NULL), NULL, NULL, NULL, - custom_info, NULL, NULL, NULL); + MiniDumpNormal, nullptr, nullptr, + nullptr, custom_info, nullptr, nullptr, nullptr); DWORD bytes_count = 0; - bool success = WriteFile(pipe, &msg, sizeof(msg), &bytes_count, NULL) != 0; + bool success = WriteFile(pipe, &msg, sizeof(msg), &bytes_count, nullptr) != 0; CloseHandle(pipe); return success; @@ -214,19 +220,22 @@ HANDLE CrashGenerationClient::ConnectToServer() { kPipeDesiredAccess, kPipeFlagsAndAttributes); if (!pipe) { - return NULL; + return nullptr; } DWORD mode = kPipeMode; - if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) { + if (!SetNamedPipeHandleState(pipe, &mode, nullptr, nullptr)) { CloseHandle(pipe); - pipe = NULL; + pipe = nullptr; } return pipe; } bool CrashGenerationClient::RegisterClient(HANDLE pipe) { +#ifdef _GAMING_XBOX + return false; +#else ProtocolMessage msg(MESSAGE_TAG_REGISTRATION_REQUEST, GetCurrentProcessId(), dump_type_, @@ -234,9 +243,9 @@ bool CrashGenerationClient::RegisterClient(HANDLE pipe) { &exception_pointers_, &assert_info_, custom_info_, - NULL, - NULL, - NULL); + nullptr, + nullptr, + nullptr); ProtocolMessage reply; DWORD bytes_count = 0; // The call to TransactNamedPipe below can be changed to a call @@ -248,7 +257,7 @@ bool CrashGenerationClient::RegisterClient(HANDLE pipe) { &reply, sizeof(ProtocolMessage), &bytes_count, - NULL)) { + nullptr)) { return false; } @@ -259,7 +268,7 @@ bool CrashGenerationClient::RegisterClient(HANDLE pipe) { ProtocolMessage ack_msg; ack_msg.tag = MESSAGE_TAG_REGISTRATION_ACK; - if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, NULL)) { + if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, nullptr)) { return false; } crash_event_ = reply.dump_request_handle; @@ -268,6 +277,7 @@ bool CrashGenerationClient::RegisterClient(HANDLE pipe) { server_process_id_ = reply.id; return true; +#endif // _GAMING_XBOX } HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name, @@ -275,7 +285,7 @@ HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name, DWORD flags_attrs) { if (pipe_handle_) { HANDLE t = pipe_handle_; - pipe_handle_ = NULL; + pipe_handle_ = nullptr; return t; } @@ -283,10 +293,10 @@ HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name, HANDLE pipe = CreateFile(pipe_name, pipe_access, 0, - NULL, + nullptr, OPEN_EXISTING, flags_attrs, - NULL); + nullptr); if (pipe != INVALID_HANDLE_VALUE) { return pipe; } @@ -303,20 +313,20 @@ HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name, } } - return NULL; + return nullptr; } bool CrashGenerationClient::ValidateResponse( const ProtocolMessage& msg) const { return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) && (msg.id != 0) && - (msg.dump_request_handle != NULL) && - (msg.dump_generated_handle != NULL) && - (msg.server_alive_handle != NULL); + (msg.dump_request_handle != nullptr) && + (msg.dump_generated_handle != nullptr) && + (msg.server_alive_handle != nullptr); } bool CrashGenerationClient::IsRegistered() const { - return crash_event_ != NULL; + return crash_event_ != nullptr; } bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info, @@ -338,11 +348,11 @@ bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info, } bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) { - return RequestDump(ex_info, NULL); + return RequestDump(ex_info, nullptr); } bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) { - return RequestDump(NULL, assert_info); + return RequestDump(nullptr, assert_info); } bool CrashGenerationClient::SignalCrashEventAndWait() { @@ -377,8 +387,8 @@ HANDLE CrashGenerationClient::DuplicatePipeToClientProcess(const wchar_t* pipe_n HANDLE hProcess) { for (int i = 0; i < kPipeConnectMaxAttempts; ++i) { HANDLE local_pipe = CreateFile(pipe_name, kPipeDesiredAccess, - 0, NULL, OPEN_EXISTING, - kPipeFlagsAndAttributes, NULL); + 0, nullptr, OPEN_EXISTING, + kPipeFlagsAndAttributes, nullptr); if (local_pipe != INVALID_HANDLE_VALUE) { HANDLE remotePipe = INVALID_HANDLE_VALUE; if (DuplicateHandle(GetCurrentProcess(), local_pipe, diff --git a/src/client/windows/crash_generation/crash_generation_client.h b/src/client/windows/crash_generation/crash_generation_client.h index 457f73195..6afd044e6 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. // @@ -35,7 +34,6 @@ #include #include #include "client/windows/common/ipc_protocol.h" -#include "common/scoped_ptr.h" namespace google_breakpad { diff --git a/src/client/windows/crash_generation/crash_generation_server.cc b/src/client/windows/crash_generation/crash_generation_server.cc index 0af213ba2..35596b435 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. // @@ -27,13 +26,20 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/windows/crash_generation/crash_generation_server.h" + #include -#include + +#include + #include -#include "client/windows/common/auto_critical_section.h" -#include "common/scoped_ptr.h" +#include +#include "client/windows/common/auto_critical_section.h" #include "client/windows/crash_generation/client_info.h" namespace google_breakpad { @@ -80,9 +86,9 @@ static bool IsClientRequestValid(const ProtocolMessage& msg) { return msg.tag == MESSAGE_TAG_UPLOAD_REQUEST || (msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST && msg.id != 0 && - msg.thread_id != NULL && - msg.exception_pointers != NULL && - msg.assert_info != NULL); + msg.thread_id != nullptr && + msg.exception_pointers != nullptr && + msg.assert_info != nullptr); } #ifndef NDEBUG @@ -109,9 +115,9 @@ CrashGenerationServer::CrashGenerationServer( const std::wstring* dump_path) : pipe_name_(pipe_name), pipe_sec_attrs_(pipe_sec_attrs), - pipe_(NULL), - pipe_wait_handle_(NULL), - server_alive_handle_(NULL), + pipe_(nullptr), + pipe_wait_handle_(nullptr), + server_alive_handle_(nullptr), connect_callback_(connect_callback), connect_context_(connect_context), dump_callback_(dump_callback), @@ -126,7 +132,7 @@ CrashGenerationServer::CrashGenerationServer( server_state_(IPC_SERVER_STATE_UNINITIALIZED), shutting_down_(false), overlapped_(), - client_info_(NULL) { + client_info_(nullptr) { InitializeCriticalSection(&sync_); } @@ -215,16 +221,16 @@ bool CrashGenerationServer::Start() { server_state_ = IPC_SERVER_STATE_INITIAL; - server_alive_handle_ = CreateMutex(NULL, TRUE, NULL); + server_alive_handle_ = CreateMutex(nullptr, TRUE, nullptr); if (!server_alive_handle_) { return false; } // Event to signal the client connection and pipe reads and writes. - overlapped_.hEvent = CreateEvent(NULL, // Security descriptor. - TRUE, // Manual reset. - FALSE, // Initially nonsignaled. - NULL); // Name. + overlapped_.hEvent = CreateEvent(nullptr, // Security descriptor. + TRUE, // Manual reset. + FALSE, // Initially nonsignaled. + nullptr); // Name. if (!overlapped_.hEvent) { return false; } @@ -278,17 +284,17 @@ void CrashGenerationServer::HandleErrorState() { if (pipe_wait_handle_) { UnregisterWait(pipe_wait_handle_); - pipe_wait_handle_ = NULL; + pipe_wait_handle_ = nullptr; } if (pipe_) { CloseHandle(pipe_); - pipe_ = NULL; + pipe_ = nullptr; } if (overlapped_.hEvent) { CloseHandle(overlapped_.hEvent); - overlapped_.hEvent = NULL; + overlapped_.hEvent = nullptr; } } @@ -361,7 +367,7 @@ void CrashGenerationServer::HandleConnectedState() { assert(server_state_ == IPC_SERVER_STATE_CONNECTED); DWORD bytes_count = 0; - memset(&msg_, 0, sizeof(msg_)); + memset(static_cast(&msg_), 0, sizeof(msg_)); bool success = ReadFile(pipe_, &msg_, sizeof(msg_), @@ -423,7 +429,7 @@ void CrashGenerationServer::HandleReadDoneState() { return; } - scoped_ptr client_info( + std::unique_ptr client_info( new ClientInfo(this, msg_.id, msg_.dump_type, @@ -557,13 +563,13 @@ void CrashGenerationServer::HandleDisconnectingState() { assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING); // Done serving the client. - client_info_ = NULL; + client_info_ = nullptr; - overlapped_.Internal = NULL; - overlapped_.InternalHigh = NULL; + overlapped_.Internal = 0; + overlapped_.InternalHigh = 0; overlapped_.Offset = 0; overlapped_.OffsetHigh = 0; - overlapped_.Pointer = NULL; + overlapped_.Pointer = nullptr; if (!ResetEvent(overlapped_.hEvent)) { EnterErrorState(); @@ -615,34 +621,34 @@ bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info, if (reply->dump_request_handle) { DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle reply->dump_request_handle, // hSourceHandle - NULL, // hTargetProcessHandle + nullptr, // hTargetProcessHandle 0, // lpTargetHandle 0, // dwDesiredAccess FALSE, // bInheritHandle DUPLICATE_CLOSE_SOURCE); // dwOptions - reply->dump_request_handle = NULL; + reply->dump_request_handle = nullptr; } if (reply->dump_generated_handle) { DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle reply->dump_generated_handle, // hSourceHandle - NULL, // hTargetProcessHandle + nullptr, // hTargetProcessHandle 0, // lpTargetHandle 0, // dwDesiredAccess FALSE, // bInheritHandle DUPLICATE_CLOSE_SOURCE); // dwOptions - reply->dump_generated_handle = NULL; + reply->dump_generated_handle = nullptr; } if (reply->server_alive_handle) { DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle reply->server_alive_handle, // hSourceHandle - NULL, // hTargetProcessHandle + nullptr, // hTargetProcessHandle 0, // lpTargetHandle 0, // dwDesiredAccess FALSE, // bInheritHandle DUPLICATE_CLOSE_SOURCE); // dwOptions - reply->server_alive_handle = NULL; + reply->server_alive_handle = nullptr; } return false; @@ -770,7 +776,7 @@ void CrashGenerationServer::HandleConnectionRequest() { } bool CrashGenerationServer::AddClient(ClientInfo* client_info) { - HANDLE request_wait_handle = NULL; + HANDLE request_wait_handle = nullptr; if (!RegisterWaitForSingleObject(&request_wait_handle, client_info->dump_requested_handle(), OnDumpRequest, @@ -783,7 +789,7 @@ bool CrashGenerationServer::AddClient(ClientInfo* client_info) { client_info->set_dump_request_wait_handle(request_wait_handle); // OnClientEnd will be called when the client process terminates. - HANDLE process_wait_handle = NULL; + HANDLE process_wait_handle = nullptr; if (!RegisterWaitForSingleObject(&process_wait_handle, client_info->process_handle(), OnClientEnd, @@ -889,7 +895,7 @@ void CrashGenerationServer::HandleDumpRequest(const ClientInfo& client_info) { } if (dump_callback_ && execute_callback) { - std::wstring* ptr_dump_path = (dump_path == L"") ? NULL : &dump_path; + std::wstring* ptr_dump_path = (dump_path == L"") ? nullptr : &dump_path; dump_callback_(dump_context_, &client_info, ptr_dump_path); } @@ -903,7 +909,7 @@ bool CrashGenerationServer::GenerateDump(const ClientInfo& client, // We have to get the address of EXCEPTION_INFORMATION from // the client process address space. - EXCEPTION_POINTERS* client_ex_info = NULL; + EXCEPTION_POINTERS* client_ex_info = nullptr; if (!client.GetClientExceptionInfo(&client_ex_info)) { return false; } diff --git a/src/client/windows/crash_generation/crash_generation_server.h b/src/client/windows/crash_generation/crash_generation_server.h index 0ea90e510..b7004d6a9 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. // @@ -34,7 +33,6 @@ #include #include "client/windows/common/ipc_protocol.h" #include "client/windows/crash_generation/minidump_generator.h" -#include "common/scoped_ptr.h" namespace google_breakpad { class ClientInfo; diff --git a/src/client/windows/crash_generation/minidump_generator.cc b/src/client/windows/crash_generation/minidump_generator.cc index 573c2786e..3811d4acb 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/windows/crash_generation/minidump_generator.h" #include @@ -101,9 +104,9 @@ class HandleTraceData { }; HandleTraceData::HandleTraceData() - : verifier_module_(NULL), - enumerate_resource_(NULL), - handle_(NULL) { + : verifier_module_(nullptr), + enumerate_resource_(nullptr), + handle_(0) { } HandleTraceData::~HandleTraceData() { @@ -208,7 +211,7 @@ bool HandleTraceData::ReadExceptionCode( exception_pointers, &pointers, sizeof(pointers), - NULL)) { + nullptr)) { return false; } @@ -216,7 +219,7 @@ bool HandleTraceData::ReadExceptionCode( pointers.ExceptionRecord, exception_code, sizeof(*exception_code), - NULL)) { + nullptr)) { return false; } @@ -258,10 +261,10 @@ MinidumpGenerator::MinidumpGenerator( MDRawAssertionInfo* assert_info, const MINIDUMP_TYPE dump_type, const bool is_client_pointers) - : dbghelp_module_(NULL), - write_dump_(NULL), - rpcrt4_module_(NULL), - create_uuid_(NULL), + : dbghelp_module_(nullptr), + write_dump_(nullptr), + rpcrt4_module_(nullptr), + create_uuid_(nullptr), process_handle_(process_handle), process_id_(process_id), thread_id_(thread_id), @@ -276,8 +279,8 @@ MinidumpGenerator::MinidumpGenerator( full_dump_file_(INVALID_HANDLE_VALUE), dump_file_is_internal_(false), full_dump_file_is_internal_(false), - additional_streams_(NULL), - callback_info_(NULL) { + additional_streams_(nullptr), + callback_info_(nullptr) { uuid_ = {0}; InitializeCriticalSection(&module_load_sync_); InitializeCriticalSection(&get_proc_address_sync_); @@ -316,7 +319,7 @@ bool MinidumpGenerator::WriteMinidump() { return false; } - MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL; + MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = nullptr; MINIDUMP_EXCEPTION_INFORMATION dump_exception_info; // Setup the exception information object only if it's a dump @@ -432,9 +435,9 @@ bool MinidumpGenerator::WriteMinidump() { full_dump_file_, static_cast((dump_type_ & (~MiniDumpNormal)) | MiniDumpWithHandleData), - exception_pointers_ ? &dump_exception_info : NULL, + dump_exception_pointers, &user_streams, - NULL) != FALSE; + nullptr) != FALSE; } // Add handle operations trace stream to the minidump if it was collected. @@ -449,7 +452,7 @@ bool MinidumpGenerator::WriteMinidump() { dump_file_, static_cast((dump_type_ & (~MiniDumpWithFullMemory)) | MiniDumpNormal), - exception_pointers_ ? &dump_exception_info : NULL, + dump_exception_pointers, &user_streams, callback_info_) != FALSE; @@ -471,10 +474,10 @@ bool MinidumpGenerator::GenerateDumpFile(wstring* dump_path) { dump_file_ = CreateFile(dump_file_path.c_str(), GENERIC_WRITE, 0, - NULL, + nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, - NULL); + nullptr); if (dump_file_ == INVALID_HANDLE_VALUE) { return false; } @@ -506,10 +509,10 @@ bool MinidumpGenerator::GenerateFullDumpFile(wstring* full_dump_path) { full_dump_file_ = CreateFile(full_dump_file_path.c_str(), GENERIC_WRITE, 0, - NULL, + nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, - NULL); + nullptr); if (full_dump_file_ == INVALID_HANDLE_VALUE) { return false; } diff --git a/src/client/windows/crash_generation/minidump_generator.h b/src/client/windows/crash_generation/minidump_generator.h index a707c0bb1..f960c5dc2 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 20d63a841..9523b25c5 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. // @@ -27,17 +26,22 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "client/windows/handler/exception_handler.h" + +#include #include +#include #include -#include -#include - -#include "common/windows/string_utils-inl.h" +#include #include "client/windows/common/ipc_protocol.h" -#include "client/windows/handler/exception_handler.h" #include "common/windows/guid_string.h" +#include "common/windows/string_utils-inl.h" namespace google_breakpad { @@ -52,7 +56,7 @@ typedef struct { #define DBG_PRINTEXCEPTION_WIDE_C ((DWORD)0x4001000A) #endif -vector* ExceptionHandler::handler_stack_ = NULL; +vector* ExceptionHandler::handler_stack_ = nullptr; LONG ExceptionHandler::handler_stack_index_ = 0; CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_; volatile LONG ExceptionHandler::instance_count_ = 0; @@ -72,8 +76,8 @@ ExceptionHandler::ExceptionHandler(const wstring& dump_path, handler_types, dump_type, pipe_name, - NULL, // pipe_handle - NULL, // crash_generation_client + nullptr, // pipe_handle + nullptr, // crash_generation_client custom_info); } @@ -91,9 +95,9 @@ ExceptionHandler::ExceptionHandler(const wstring& dump_path, callback_context, handler_types, dump_type, - NULL, // pipe_name + nullptr, // pipe_name pipe_handle, - NULL, // crash_generation_client + nullptr, // crash_generation_client custom_info); } @@ -112,10 +116,10 @@ ExceptionHandler::ExceptionHandler( callback_context, handler_types, MiniDumpNormal, // dump_type - not used - NULL, // pipe_name - not used - NULL, // pipe_handle + nullptr, // pipe_name - not used + nullptr, // pipe_handle crash_generation_client, - NULL); // custom_info - not used + nullptr); // custom_info - not used } ExceptionHandler::ExceptionHandler(const wstring& dump_path, @@ -129,10 +133,10 @@ ExceptionHandler::ExceptionHandler(const wstring& dump_path, callback_context, handler_types, MiniDumpNormal, - NULL, // pipe_name - NULL, // pipe_handle - NULL, // crash_generation_client - NULL); // custom_info + nullptr, // pipe_name + nullptr, // pipe_handle + nullptr, // crash_generation_client + nullptr); // custom_info } void ExceptionHandler::Initialize( @@ -150,34 +154,34 @@ void ExceptionHandler::Initialize( filter_ = filter; callback_ = callback; callback_context_ = callback_context; - dump_path_c_ = NULL; - next_minidump_id_c_ = NULL; - next_minidump_path_c_ = NULL; - dbghelp_module_ = NULL; - minidump_write_dump_ = NULL; + dump_path_c_ = nullptr; + next_minidump_id_c_ = nullptr; + next_minidump_path_c_ = nullptr; + dbghelp_module_ = nullptr; + minidump_write_dump_ = nullptr; dump_type_ = dump_type; - rpcrt4_module_ = NULL; - uuid_create_ = NULL; + rpcrt4_module_ = nullptr; + uuid_create_ = nullptr; handler_types_ = handler_types; - previous_filter_ = NULL; + previous_filter_ = nullptr; #if _MSC_VER >= 1400 // MSVC 2005/8 - previous_iph_ = NULL; + previous_iph_ = nullptr; #endif // _MSC_VER >= 1400 - previous_pch_ = NULL; - handler_thread_ = NULL; + previous_pch_ = nullptr; + handler_thread_ = nullptr; is_shutdown_ = false; - handler_start_semaphore_ = NULL; - handler_finish_semaphore_ = NULL; + handler_start_semaphore_ = nullptr; + handler_finish_semaphore_ = nullptr; requesting_thread_id_ = 0; - exception_info_ = NULL; - assertion_ = NULL; + exception_info_ = nullptr; + assertion_ = nullptr; handler_return_value_ = false; handle_debug_exceptions_ = false; consume_invalid_handle_exceptions_ = false; // Attempt to use out-of-process if user has specified a pipe or a // crash generation client. - scoped_ptr client; + std::unique_ptr client; if (crash_generation_client) { client.reset(crash_generation_client); } else if (pipe_name) { @@ -188,7 +192,7 @@ void ExceptionHandler::Initialize( new CrashGenerationClient(pipe_handle, dump_type_, custom_info)); } - if (client.get() != NULL) { + if (client.get() != nullptr) { // If successful in registering with the monitoring process, // there is no need to setup in-process crash generation. if (client->Register()) { @@ -207,23 +211,24 @@ void ExceptionHandler::Initialize( // and it allows an easy way to get a snapshot of the requesting thread's // context outside of an exception. InitializeCriticalSection(&handler_critical_section_); - handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); - assert(handler_start_semaphore_ != NULL); + handler_start_semaphore_ = CreateSemaphore(nullptr, 0, 1, nullptr); + assert(handler_start_semaphore_ != nullptr); - handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); - assert(handler_finish_semaphore_ != NULL); + handler_finish_semaphore_ = CreateSemaphore(nullptr, 0, 1, nullptr); + assert(handler_finish_semaphore_ != nullptr); // Don't attempt to create the thread if we could not create the semaphores. - if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) { + if (handler_finish_semaphore_ != nullptr && + handler_start_semaphore_ != nullptr) { DWORD thread_id; const int kExceptionHandlerThreadInitialStackSize = 64 * 1024; - handler_thread_ = CreateThread(NULL, // lpThreadAttributes + handler_thread_ = CreateThread(nullptr, // lpThreadAttributes kExceptionHandlerThreadInitialStackSize, ExceptionHandlerThreadMain, this, // lpParameter 0, // dwCreationFlags &thread_id); - assert(handler_thread_ != NULL); + assert(handler_thread_ != nullptr); } dbghelp_module_ = LoadLibrary(L"dbghelp.dll"); @@ -248,7 +253,7 @@ void ExceptionHandler::Initialize( // Reserve one element for the instruction memory AppMemory instruction_memory; - instruction_memory.ptr = NULL; + instruction_memory.ptr = reinterpret_cast(nullptr); instruction_memory.length = 0; app_memory_info_.push_back(instruction_memory); @@ -335,7 +340,7 @@ ExceptionHandler::~ExceptionHandler() { // When destroying the last ExceptionHandler that installed a handler, // clean up the handler stack. delete handler_stack_; - handler_stack_ = NULL; + handler_stack_ = nullptr; } LeaveCriticalSection(&handler_stack_critical_section_); @@ -352,7 +357,7 @@ ExceptionHandler::~ExceptionHandler() { // deadlock if the exception handler is destroyed while executing code // inside DllMain. is_shutdown_ = true; - ReleaseSemaphore(handler_start_semaphore_, 1, NULL); + ReleaseSemaphore(handler_start_semaphore_, 1, nullptr); const int kWaitForHandlerThreadMs = 60000; WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs); #else @@ -360,7 +365,7 @@ ExceptionHandler::~ExceptionHandler() { #endif // BREAKPAD_NO_TERMINATE_THREAD CloseHandle(handler_thread_); - handler_thread_ = NULL; + handler_thread_ = nullptr; DeleteCriticalSection(&handler_critical_section_); CloseHandle(handler_start_semaphore_); CloseHandle(handler_finish_semaphore_); @@ -385,8 +390,8 @@ bool ExceptionHandler::RequestUpload(DWORD crash_id) { DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) { ExceptionHandler* self = reinterpret_cast(lpParameter); assert(self); - assert(self->handler_start_semaphore_ != NULL); - assert(self->handler_finish_semaphore_ != NULL); + assert(self->handler_start_semaphore_ != nullptr); + assert(self->handler_finish_semaphore_ != nullptr); for (;;) { if (WaitForSingleObject(self->handler_start_semaphore_, INFINITE) == @@ -403,7 +408,7 @@ DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) { } // Allow the requesting thread to proceed. - ReleaseSemaphore(self->handler_finish_semaphore_, 1, NULL); + ReleaseSemaphore(self->handler_finish_semaphore_, 1, nullptr); } } @@ -504,9 +509,9 @@ LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) { success = current_handler->WriteMinidumpWithException( GetCurrentThreadId(), exinfo, - NULL); + nullptr); } else { - success = current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL); + success = current_handler->WriteMinidumpOnHandlerThread(exinfo, nullptr); } } @@ -704,14 +709,14 @@ bool ExceptionHandler::WriteMinidumpOnHandlerThread( // There isn't much we can do if the handler thread // was not successfully created. - if (handler_thread_ == NULL) { + if (handler_thread_ == nullptr) { LeaveCriticalSection(&handler_critical_section_); return false; } // The handler thread should only be created when the semaphores are valid. - assert(handler_start_semaphore_ != NULL); - assert(handler_finish_semaphore_ != NULL); + assert(handler_start_semaphore_ != nullptr); + assert(handler_finish_semaphore_ != nullptr); // Set up data to be passed in to the handler thread. requesting_thread_id_ = GetCurrentThreadId(); @@ -719,7 +724,7 @@ bool ExceptionHandler::WriteMinidumpOnHandlerThread( assertion_ = assertion; // This causes the handler thread to call WriteMinidumpWithException. - ReleaseSemaphore(handler_start_semaphore_, 1, NULL); + ReleaseSemaphore(handler_start_semaphore_, 1, nullptr); // Wait until WriteMinidumpWithException is done and collect its return value. WaitForSingleObject(handler_finish_semaphore_, INFINITE); @@ -727,8 +732,8 @@ bool ExceptionHandler::WriteMinidumpOnHandlerThread( // Clean up. requesting_thread_id_ = 0; - exception_info_ = NULL; - assertion_ = NULL; + exception_info_ = nullptr; + assertion_ = nullptr; LeaveCriticalSection(&handler_critical_section_); @@ -756,10 +761,10 @@ bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) { if (IsOutOfProcess()) { return WriteMinidumpWithException(GetCurrentThreadId(), exinfo, - NULL); + nullptr); } - bool success = WriteMinidumpOnHandlerThread(exinfo, NULL); + bool success = WriteMinidumpOnHandlerThread(exinfo, nullptr); UpdateNextID(); return success; } @@ -769,8 +774,8 @@ bool ExceptionHandler::WriteMinidump(const wstring& dump_path, MinidumpCallback callback, void* callback_context, MINIDUMP_TYPE dump_type) { - ExceptionHandler handler(dump_path, NULL, callback, callback_context, - HANDLER_NONE, dump_type, (HANDLE)NULL, NULL); + ExceptionHandler handler(dump_path, nullptr, callback, callback_context, + HANDLER_NONE, dump_type, (HANDLE)nullptr, nullptr); return handler.WriteMinidump(); } @@ -783,7 +788,7 @@ bool ExceptionHandler::WriteMinidumpForChild(HANDLE child, MINIDUMP_TYPE dump_type) { EXCEPTION_RECORD ex; CONTEXT ctx; - EXCEPTION_POINTERS exinfo = { NULL, NULL }; + EXCEPTION_POINTERS exinfo = { nullptr, nullptr }; // As documented on MSDN, on failure SuspendThread returns (DWORD) -1 const DWORD kFailedToSuspendThread = static_cast(-1); DWORD last_suspend_count = kFailedToSuspendThread; @@ -794,7 +799,7 @@ bool ExceptionHandler::WriteMinidumpForChild(HANDLE child, child_blamed_thread); // This thread may have died already, so not opening the handle is a // non-fatal error. - if (child_thread_handle != NULL) { + if (child_thread_handle != nullptr) { last_suspend_count = SuspendThread(child_thread_handle); if (last_suspend_count != kFailedToSuspendThread) { ctx.ContextFlags = CONTEXT_ALL; @@ -812,12 +817,12 @@ bool ExceptionHandler::WriteMinidumpForChild(HANDLE child, } } - ExceptionHandler handler(dump_path, NULL, callback, callback_context, - HANDLER_NONE, dump_type, (HANDLE)NULL, NULL); + ExceptionHandler handler(dump_path, nullptr, callback, callback_context, + HANDLER_NONE, dump_type, (HANDLE)nullptr, nullptr); bool success = handler.WriteMinidumpWithExceptionForProcess( child_blamed_thread, - exinfo.ExceptionRecord ? &exinfo : NULL, - NULL, child, false); + exinfo.ExceptionRecord ? &exinfo : nullptr, + nullptr, child, false); if (last_suspend_count != kFailedToSuspendThread) { ResumeThread(child_thread_handle); @@ -827,7 +832,7 @@ bool ExceptionHandler::WriteMinidumpForChild(HANDLE child, if (callback) { success = callback(handler.dump_path_c_, handler.next_minidump_id_c_, - callback_context, NULL, NULL, success); + callback_context, nullptr, nullptr, success); } return success; @@ -920,10 +925,10 @@ bool ExceptionHandler::WriteMinidumpWithExceptionForProcess( HANDLE dump_file = CreateFile(next_minidump_path_c_, GENERIC_WRITE, 0, // no sharing - NULL, + nullptr, CREATE_NEW, // fail if exists FILE_ATTRIBUTE_NORMAL, - NULL); + nullptr); if (dump_file != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION except_info; except_info.ThreadId = requesting_thread_id; @@ -1026,7 +1031,7 @@ bool ExceptionHandler::WriteMinidumpWithExceptionForProcess( GetProcessId(process), dump_file, dump_type_, - exinfo ? &except_info : NULL, + exinfo ? &except_info : nullptr, &user_streams, &callback) == TRUE); @@ -1046,14 +1051,27 @@ void ExceptionHandler::UpdateNextID() { next_minidump_id_ = GUIDString::GUIDToWString(&id); next_minidump_id_c_ = next_minidump_id_.c_str(); - wchar_t minidump_path[MAX_PATH]; - swprintf(minidump_path, MAX_PATH, L"%s\\%s.dmp", - dump_path_c_, next_minidump_id_c_); + const size_t dump_path_c_len = wcslen(dump_path_c_); + const size_t next_minidump_id_c_len = wcslen(next_minidump_id_c_); + // 1 for backslash + 4 for ".dmp" + 1 for NUL + const size_t minidump_path_len = + dump_path_c_len + 1 + next_minidump_id_c_len + 4 + 1; + std::vector minidump_path(minidump_path_len); + const int written = + swprintf(minidump_path.data(), minidump_path_len, L"%s\\%s.dmp", + dump_path_c_, next_minidump_id_c_); + if (written < 0 || static_cast(written) >= minidump_path.size()) { + // `swprintf` either encountered an encoding error or truncation. + // Let's reset the `next`-members and exit early to not cause overwriting. + next_minidump_path_.clear(); + next_minidump_path_c_ = nullptr; + return; + } // remove when VC++7.1 is no longer supported - minidump_path[MAX_PATH - 1] = L'\0'; + minidump_path.back() = L'\0'; - next_minidump_path_ = minidump_path; + next_minidump_path_.assign(minidump_path.data()); next_minidump_path_c_ = next_minidump_path_.c_str(); } diff --git a/src/client/windows/handler/exception_handler.gyp b/src/client/windows/handler/exception_handler.gyp deleted file mode 100644 index c5733277d..000000000 --- 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 eb5adaac5..37ee68aaa 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. // @@ -66,12 +65,12 @@ #pragma warning(disable:4530) #include +#include #include #include #include "client/windows/common/ipc_protocol.h" #include "client/windows/crash_generation/crash_generation_client.h" -#include "common/scoped_ptr.h" #include "google_breakpad/common/minidump_format.h" namespace google_breakpad { @@ -275,7 +274,9 @@ class ExceptionHandler { } // Returns whether out-of-process dump generation is used or not. - bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; } + bool IsOutOfProcess() const { + return crash_generation_client_.get() != nullptr; + } // Calling RegisterAppMemory(p, len) causes len bytes starting // at address p to be copied to the minidump when a crash happens. @@ -386,7 +387,7 @@ class ExceptionHandler { MinidumpCallback callback_; void* callback_context_; - scoped_ptr crash_generation_client_; + std::unique_ptr crash_generation_client_; // The directory in which a minidump will be written, set by the dump_path // argument to the constructor, or set_dump_path. diff --git a/src/client/windows/sender/crash_report_sender.cc b/src/client/windows/sender/crash_report_sender.cc index 7fc644839..1433bd722 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. // @@ -30,6 +29,10 @@ // Disable exception handler warnings. #pragma warning( disable : 4530 ) +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "client/windows/sender/crash_report_sender.h" @@ -69,7 +72,7 @@ ReportResult CrashReportSender::SendCrashReport( int http_response = 0; bool result = HTTPUpload::SendMultipartPostRequest( - url, parameters, files, NULL, report_code, + url, parameters, files, nullptr, report_code, &http_response); if (result) { @@ -132,7 +135,7 @@ int CrashReportSender::OpenCheckpointFile(const wchar_t* mode, FILE** fd) { return _wfopen_s(fd, checkpoint_file_.c_str(), mode); #else *fd = _wfopen(checkpoint_file_.c_str(), mode); - if (*fd == NULL) { + if (*fd == nullptr) { return errno; } return 0; 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 dc8583a0a..000000000 --- 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 e6055857c..758adbb4d 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. // 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 32f78f2b9..737c817c9 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/windows/tests/crash_generation_app/abstract_class.h" namespace google_breakpad { 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 e3f2a4f37..c996a216c 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 0d837e521..7bc22286e 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. // @@ -30,6 +29,10 @@ // crash_generation_app.cpp : Defines the entry point for the application. // +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/windows/tests/crash_generation_app/crash_generation_app.h" #include @@ -59,7 +62,7 @@ const DWORD kEditBoxStyles = WS_CHILD | const size_t kMaximumLineLength = 256; // CS to access edit control in a thread safe way. -static CRITICAL_SECTION* cs_edit = NULL; +static CRITICAL_SECTION* cs_edit = nullptr; // Edit control. static HWND client_status_edit_box; @@ -79,8 +82,8 @@ static CustomInfoEntry kCustomInfoEntries[] = { CustomInfoEntry(L"ver", L"1.0"), }; -static ExceptionHandler* handler = NULL; -static CrashGenerationServer* crash_server = NULL; +static ExceptionHandler* handler = nullptr; +static CrashGenerationServer* crash_server = nullptr; // Registers the window class. // @@ -99,7 +102,7 @@ ATOM MyRegisterClass(HINSTANCE instance) { wcex.hInstance = instance; wcex.hIcon = LoadIcon(instance, MAKEINTRESOURCE(IDI_CRASHGENERATIONAPP)); - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP); wcex.lpszClassName = window_class; @@ -121,10 +124,10 @@ BOOL InitInstance(HINSTANCE instance, int command_show) { 0, CW_USEDEFAULT, 0, - NULL, - NULL, + nullptr, + nullptr, instance, - NULL); + nullptr); if (!wnd) { return FALSE; @@ -285,33 +288,33 @@ void CrashServerStart() { std::wstring dump_path = L"C:\\Dumps\\"; if (_wmkdir(dump_path.c_str()) && (errno != EEXIST)) { - MessageBoxW(NULL, L"Unable to create dump directory", L"Dumper", MB_OK); + MessageBoxW(nullptr, L"Unable to create dump directory", L"Dumper", MB_OK); return; } crash_server = new CrashGenerationServer(kPipeName, - NULL, + nullptr, ShowClientConnected, - NULL, + nullptr, ShowClientCrashed, - NULL, + nullptr, ShowClientExited, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, true, &dump_path); if (!crash_server->Start()) { - MessageBoxW(NULL, L"Unable to start server", L"Dumper", MB_OK); + MessageBoxW(nullptr, L"Unable to start server", L"Dumper", MB_OK); delete crash_server; - crash_server = NULL; + crash_server = nullptr; } } void CrashServerStop() { delete crash_server; - crash_server = NULL; + crash_server = nullptr; } void DerefZeroCrash() { @@ -320,7 +323,7 @@ void DerefZeroCrash() { } void InvalidParamCrash() { - printf(NULL); + printf(nullptr); } void PureCallCrash() { @@ -329,7 +332,7 @@ void PureCallCrash() { void RequestDump() { if (!handler->WriteMinidump()) { - MessageBoxW(NULL, L"Dump request failed", L"Dumper", MB_OK); + MessageBoxW(nullptr, L"Dump request failed", L"Dumper", MB_OK); } kCustomInfoEntries[1].set_value(L"1.1"); } @@ -404,16 +407,16 @@ LRESULT CALLBACK WndProc(HWND wnd, break; case WM_CREATE: client_status_edit_box = CreateWindow(TEXT("EDIT"), - NULL, + nullptr, kEditBoxStyles, 0, 0, 0, 0, wnd, - NULL, + nullptr, instance, - NULL); + nullptr); break; case WM_SIZE: // Make the edit control the size of the window's client area. @@ -484,9 +487,9 @@ int APIENTRY _tWinMain(HINSTANCE instance, // failures and instead let the code handle it. _CrtSetReportMode(_CRT_ASSERT, 0); handler = new ExceptionHandler(L"C:\\dumps\\", - NULL, + nullptr, google_breakpad::ShowDumpResults, - NULL, + nullptr, ExceptionHandler::HANDLER_ALL, MiniDumpNormal, kPipeName, @@ -511,7 +514,7 @@ int APIENTRY _tWinMain(HINSTANCE instance, // Main message loop. MSG msg; - while (GetMessage(&msg, NULL, 0, 0)) { + while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, accel_table, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); 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 3ce307da0..000000000 --- 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 4d3bb6eb2..1d1deea4b 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 8c7f6570a..e91208267 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 768f8fd8c..000000000 --- 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 09f2dd200..cc117040b 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. // @@ -28,6 +27,10 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "client/windows/crash_generation/crash_generation_server.h" #include "client/windows/common/ipc_protocol.h" @@ -58,15 +61,15 @@ class CrashGenerationServerTest : public ::testing::Test { public: CrashGenerationServerTest() : crash_generation_server_(kPipeName, - NULL, + nullptr, CallOnClientConnected, &mock_callbacks_, CallOnClientDumpRequested, &mock_callbacks_, CallOnClientExited, &mock_callbacks_, CallOnClientUploadRequested, &mock_callbacks_, false, - NULL), + nullptr), thread_id_(0), - exception_pointers_(NULL) { + exception_pointers_(nullptr) { memset(&assert_info_, 0, sizeof(assert_info_)); } @@ -103,10 +106,10 @@ class CrashGenerationServerTest : public ::testing::Test { HANDLE pipe = CreateFile(kPipeName, kPipeDesiredAccess, 0, - NULL, + nullptr, OPEN_EXISTING, kPipeFlagsAndAttributes, - NULL); + nullptr); if (pipe == INVALID_HANDLE_VALUE) { ASSERT_EQ(ERROR_PIPE_BUSY, GetLastError()); @@ -117,16 +120,16 @@ class CrashGenerationServerTest : public ::testing::Test { pipe = CreateFile(kPipeName, kPipeDesiredAccess, 0, - NULL, + nullptr, OPEN_EXISTING, kPipeFlagsAndAttributes, - NULL); + nullptr); } ASSERT_NE(pipe, INVALID_HANDLE_VALUE); DWORD mode = kPipeMode; - ASSERT_TRUE(SetNamedPipeHandleState(pipe, &mode, NULL, NULL)); + ASSERT_TRUE(SetNamedPipeHandleState(pipe, &mode, nullptr, nullptr)); DoFaultyClient(fault_type, pipe); @@ -174,9 +177,9 @@ class CrashGenerationServerTest : public ::testing::Test { &exception_pointers_, &assert_info_, custom_info, - NULL, - NULL, - NULL); + nullptr, + nullptr, + nullptr); DWORD bytes_count = 0; @@ -185,7 +188,7 @@ class CrashGenerationServerTest : public ::testing::Test { fault_type == TRUNCATE_REGISTRATION ? sizeof(msg) / 2 : sizeof(msg), &bytes_count, - NULL)); + nullptr)); if (fault_type == CLOSE_AFTER_REGISTRATION) { return; @@ -199,7 +202,7 @@ class CrashGenerationServerTest : public ::testing::Test { sizeof(google_breakpad::ProtocolMessage) / 2 : sizeof(google_breakpad::ProtocolMessage), &bytes_count, - NULL)) { + nullptr)) { switch (fault_type) { case TRUNCATE_REGISTRATION: case RESPONSE_BUFFER_TOO_SMALL: @@ -223,7 +226,7 @@ class CrashGenerationServerTest : public ::testing::Test { SEND_INVALID_ACK ? sizeof(ack_msg) : sizeof(ack_msg) / 2, &bytes_count, - NULL)); + nullptr)); return; } diff --git a/src/client/windows/unittests/dump_analysis.cc b/src/client/windows/unittests/dump_analysis.cc index 0bb8f6c46..5dd3dc338 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -35,52 +38,52 @@ #include "client/windows/unittests/dump_analysis.h" // NOLINT DumpAnalysis::~DumpAnalysis() { - if (dump_file_view_ != NULL) { + if (dump_file_view_ != nullptr) { EXPECT_TRUE(::UnmapViewOfFile(dump_file_view_)); ::CloseHandle(dump_file_mapping_); - dump_file_mapping_ = NULL; + dump_file_mapping_ = nullptr; } - if (dump_file_handle_ != NULL) { + if (dump_file_handle_ != nullptr) { ::CloseHandle(dump_file_handle_); - dump_file_handle_ = NULL; + dump_file_handle_ = nullptr; } } void DumpAnalysis::EnsureDumpMapped() { - if (dump_file_view_ == NULL) { + if (dump_file_view_ == nullptr) { dump_file_handle_ = ::CreateFile(dump_file_.c_str(), GENERIC_READ, 0, - NULL, + nullptr, OPEN_EXISTING, 0, - NULL); - ASSERT_TRUE(dump_file_handle_ != NULL); - ASSERT_TRUE(dump_file_mapping_ == NULL); + nullptr); + ASSERT_TRUE(dump_file_handle_ != nullptr); + ASSERT_TRUE(dump_file_mapping_ == nullptr); dump_file_mapping_ = ::CreateFileMapping(dump_file_handle_, - NULL, + nullptr, PAGE_READONLY, 0, 0, - NULL); - ASSERT_TRUE(dump_file_mapping_ != NULL); + nullptr); + ASSERT_TRUE(dump_file_mapping_ != nullptr); dump_file_view_ = ::MapViewOfFile(dump_file_mapping_, FILE_MAP_READ, 0, 0, 0); - ASSERT_TRUE(dump_file_view_ != NULL); + ASSERT_TRUE(dump_file_view_ != nullptr); } } bool DumpAnalysis::HasTebs() const { - MINIDUMP_THREAD_LIST* thread_list = NULL; + MINIDUMP_THREAD_LIST* thread_list = nullptr; size_t thread_list_size = GetStream(ThreadListStream, &thread_list); - if (thread_list_size > 0 && thread_list != NULL) { + if (thread_list_size > 0 && thread_list != nullptr) { for (ULONG i = 0; i < thread_list->NumberOfThreads; ++i) { if (!HasMemory(thread_list->Threads[i].Teb)) return false; @@ -94,12 +97,12 @@ bool DumpAnalysis::HasTebs() const { } bool DumpAnalysis::HasPeb() const { - MINIDUMP_THREAD_LIST* thread_list = NULL; + MINIDUMP_THREAD_LIST* thread_list = nullptr; size_t thread_list_size = GetStream(ThreadListStream, &thread_list); - if (thread_list_size > 0 && thread_list != NULL && + if (thread_list_size > 0 && thread_list != nullptr && thread_list->NumberOfThreads > 0) { - FakeTEB* teb = NULL; + FakeTEB* teb = nullptr; if (!HasMemory(thread_list->Threads[0].Teb, &teb)) return false; @@ -110,13 +113,13 @@ bool DumpAnalysis::HasPeb() const { } bool DumpAnalysis::HasStream(ULONG stream_number) const { - void* stream = NULL; + void* stream = nullptr; size_t stream_size = GetStreamImpl(stream_number, &stream); - return stream_size > 0 && stream != NULL; + return stream_size > 0 && stream != nullptr; } size_t DumpAnalysis::GetStreamImpl(ULONG stream_number, void** stream) const { - MINIDUMP_DIRECTORY* directory = NULL; + MINIDUMP_DIRECTORY* directory = nullptr; ULONG memory_list_size = 0; BOOL ret = ::MiniDumpReadDumpStream(dump_file_view_, stream_number, @@ -130,9 +133,9 @@ size_t DumpAnalysis::GetStreamImpl(ULONG stream_number, void** stream) const { bool DumpAnalysis::HasMemoryImpl(const void* addr_in, size_t structuresize, void** structure) const { uintptr_t address = reinterpret_cast(addr_in); - MINIDUMP_MEMORY_LIST* memory_list = NULL; + MINIDUMP_MEMORY_LIST* memory_list = nullptr; size_t memory_list_size = GetStream(MemoryListStream, &memory_list); - if (memory_list_size > 0 && memory_list != NULL) { + if (memory_list_size > 0 && memory_list != nullptr) { for (ULONG i = 0; i < memory_list->NumberOfMemoryRanges; ++i) { MINIDUMP_MEMORY_DESCRIPTOR& descr = memory_list->MemoryRanges[i]; const uintptr_t range_start = @@ -143,7 +146,7 @@ bool DumpAnalysis::HasMemoryImpl(const void* addr_in, size_t structuresize, address + structuresize < range_end) { // The start address falls in the range, and the end address is // in bounds, return a pointer to the structure if requested. - if (structure != NULL) + if (structure != nullptr) *structure = RVA_TO_ADDR(dump_file_view_, descr.Memory.Rva); return true; @@ -154,9 +157,9 @@ bool DumpAnalysis::HasMemoryImpl(const void* addr_in, size_t structuresize, // We didn't find the range in a MINIDUMP_MEMORY_LIST, so maybe this // is a full dump using MINIDUMP_MEMORY64_LIST with all the memory at the // end of the dump file. - MINIDUMP_MEMORY64_LIST* memory64_list = NULL; + MINIDUMP_MEMORY64_LIST* memory64_list = nullptr; memory_list_size = GetStream(Memory64ListStream, &memory64_list); - if (memory_list_size > 0 && memory64_list != NULL) { + if (memory_list_size > 0 && memory64_list != nullptr) { // Keep track of where the current descriptor maps to. RVA64 curr_rva = memory64_list->BaseRva; for (ULONG i = 0; i < memory64_list->NumberOfMemoryRanges; ++i) { @@ -169,7 +172,7 @@ bool DumpAnalysis::HasMemoryImpl(const void* addr_in, size_t structuresize, address + structuresize < range_end) { // The start address falls in the range, and the end address is // in bounds, return a pointer to the structure if requested. - if (structure != NULL) + if (structure != nullptr) *structure = RVA_TO_ADDR(dump_file_view_, curr_rva); return true; diff --git a/src/client/windows/unittests/dump_analysis.h b/src/client/windows/unittests/dump_analysis.h index 6cef48d81..87116b902 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. // @@ -41,8 +40,10 @@ struct FakeTEB { class DumpAnalysis { public: explicit DumpAnalysis(const std::wstring& file_path) - : dump_file_(file_path), dump_file_view_(NULL), dump_file_mapping_(NULL), - dump_file_handle_(NULL) { + : dump_file_(file_path), + dump_file_view_(nullptr), + dump_file_mapping_(nullptr), + dump_file_handle_(nullptr) { EnsureDumpMapped(); } ~DumpAnalysis(); @@ -60,15 +61,15 @@ class DumpAnalysis { bool HasTebs() const; bool HasPeb() const; bool HasMemory(ULONG64 address) const { - return HasMemory(address, NULL); + return HasMemory(address, nullptr); } bool HasMemory(const void* address) const { - return HasMemory(address, NULL); + return HasMemory(address, nullptr); } template - bool HasMemory(ULONG64 address, StructureType** structure = NULL) const { + bool HasMemory(ULONG64 address, StructureType** structure = nullptr) const { // We can't cope with 64 bit addresses for now. if (address > 0xFFFFFFFFUL) return false; @@ -77,7 +78,8 @@ class DumpAnalysis { } template - bool HasMemory(const void* addr_in, StructureType** structure = NULL) const { + bool HasMemory(const void* addr_in, + StructureType** structure = nullptr) const { return HasMemoryImpl(addr_in, sizeof(StructureType), reinterpret_cast(structure)); } diff --git a/src/client/windows/unittests/exception_handler_death_test.cc b/src/client/windows/unittests/exception_handler_death_test.cc index 04034e8d4..5d456a7df 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. // @@ -27,12 +26,18 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include #include #include #include #include #include +#include #include #include "breakpad_googletest_includes.h" @@ -89,7 +94,7 @@ void ExceptionHandlerDeathTest::SetUp() { assert(false); } StringCchPrintfW(temp_path_, MAX_PATH, L"%s%s", temp_path, test_name_wide); - CreateDirectory(temp_path_, NULL); + CreateDirectory(temp_path_, nullptr); } BOOL DoesPathExist(const TCHAR* path_name) { @@ -124,18 +129,18 @@ TEST_F(ExceptionHandlerDeathTest, InProcTest) { // the semantics of the exception handler being inherited/not // inherited across CreateProcess(). ASSERT_TRUE(DoesPathExist(temp_path_)); - scoped_ptr exc( + std::unique_ptr exc( new google_breakpad::ExceptionHandler( temp_path_, - NULL, + nullptr, &MinidumpWrittenCallback, - NULL, + nullptr, google_breakpad::ExceptionHandler::HANDLER_ALL)); // Disable GTest SEH handler testing::DisableExceptionHandlerInScope disable_exception_handler; - int* i = NULL; + int* i = nullptr; ASSERT_DEATH((*i)++, kSuccessIndicator); } @@ -149,32 +154,32 @@ void clientDumpCallback(void* dump_context, void ExceptionHandlerDeathTest::DoCrashAccessViolation( const OutOfProcGuarantee out_of_proc_guarantee) { - scoped_ptr exc; + std::unique_ptr exc; if (out_of_proc_guarantee == OUT_OF_PROC_GUARANTEED) { google_breakpad::CrashGenerationClient* client = new google_breakpad::CrashGenerationClient(kPipeName, MiniDumpNormal, - NULL); // custom_info + nullptr); // custom_info ASSERT_TRUE(client->Register()); exc.reset(new google_breakpad::ExceptionHandler( temp_path_, - NULL, // filter - NULL, // callback - NULL, // callback_context + nullptr, // filter + nullptr, // callback + nullptr, // callback_context google_breakpad::ExceptionHandler::HANDLER_ALL, client)); } else { ASSERT_TRUE(out_of_proc_guarantee == OUT_OF_PROC_BEST_EFFORT); exc.reset(new google_breakpad::ExceptionHandler( temp_path_, - NULL, // filter - NULL, // callback - NULL, // callback_context + nullptr, // filter + nullptr, // callback + nullptr, // callback_context google_breakpad::ExceptionHandler::HANDLER_ALL, MiniDumpNormal, kPipeName, - NULL)); // custom_info + nullptr)); // custom_info } // Disable GTest SEH handler @@ -184,7 +189,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 = nullptr; printf("%d\n", (*i)++); } @@ -200,8 +205,8 @@ TEST_F(ExceptionHandlerDeathTest, OutOfProcTest) { ASSERT_TRUE(DoesPathExist(temp_path_)); std::wstring dump_path(temp_path_); google_breakpad::CrashGenerationServer server( - kPipeName, NULL, NULL, NULL, &clientDumpCallback, NULL, NULL, NULL, NULL, - NULL, true, &dump_path); + kPipeName, nullptr, nullptr, nullptr, &clientDumpCallback, nullptr, + nullptr, nullptr, nullptr, nullptr, true, &dump_path); // This HAS to be EXPECT_, because when this test case is executed in the // child process, the server registration will fail due to the named pipe @@ -223,8 +228,8 @@ TEST_F(ExceptionHandlerDeathTest, OutOfProcGuaranteedTest) { ASSERT_TRUE(DoesPathExist(temp_path_)); std::wstring dump_path(temp_path_); google_breakpad::CrashGenerationServer server( - kPipeName, NULL, NULL, NULL, &clientDumpCallback, NULL, NULL, NULL, NULL, - NULL, true, &dump_path); + kPipeName, nullptr, nullptr, nullptr, &clientDumpCallback, nullptr, + nullptr, nullptr, nullptr, nullptr, true, &dump_path); // This HAS to be EXPECT_, because when this test case is executed in the // child process, the server registration will fail due to the named pipe @@ -239,7 +244,7 @@ TEST_F(ExceptionHandlerDeathTest, InvalidParameterTest) { using google_breakpad::ExceptionHandler; ASSERT_TRUE(DoesPathExist(temp_path_)); - ExceptionHandler handler(temp_path_, NULL, NULL, NULL, + ExceptionHandler handler(temp_path_, nullptr, nullptr, nullptr, ExceptionHandler::HANDLER_INVALID_PARAMETER); // Disable the message box for assertions @@ -247,7 +252,7 @@ TEST_F(ExceptionHandlerDeathTest, InvalidParameterTest) { // Call with a bad argument. The invalid parameter will be swallowed // and a dump will be generated, the process will exit(0). - ASSERT_EXIT(printf(NULL), ::testing::ExitedWithCode(0), ""); + ASSERT_EXIT(printf(nullptr), ::testing::ExitedWithCode(0), ""); } @@ -273,7 +278,7 @@ TEST_F(ExceptionHandlerDeathTest, PureVirtualCallTest) { using google_breakpad::ExceptionHandler; ASSERT_TRUE(DoesPathExist(temp_path_)); - ExceptionHandler handler(temp_path_, NULL, NULL, NULL, + ExceptionHandler handler(temp_path_, nullptr, nullptr, nullptr, ExceptionHandler::HANDLER_PURECALL); // Disable the message box for assertions @@ -311,12 +316,12 @@ wstring find_minidump_in_directory(const wstring& directory) { TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemory) { ASSERT_TRUE(DoesPathExist(temp_path_)); - scoped_ptr exc( + std::unique_ptr exc( new google_breakpad::ExceptionHandler( temp_path_, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, google_breakpad::ExceptionHandler::HANDLER_ALL)); // Disable GTest SEH handler @@ -327,7 +332,7 @@ TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemory) { const int kOffset = kMemorySize / 2; // This crashes with SIGILL on x86/x86-64/arm. const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; - char* memory = reinterpret_cast(VirtualAlloc(NULL, + char* memory = reinterpret_cast(VirtualAlloc(nullptr, kMemorySize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)); @@ -403,12 +408,12 @@ TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemory) { TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemoryMinBound) { ASSERT_TRUE(DoesPathExist(temp_path_)); - scoped_ptr exc( + std::unique_ptr exc( new google_breakpad::ExceptionHandler( temp_path_, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, google_breakpad::ExceptionHandler::HANDLER_ALL)); // Disable GTest SEH handler @@ -424,7 +429,7 @@ TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemoryMinBound) { const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; // Get some executable memory. Specifically, reserve two pages, // but only commit the second. - char* all_memory = reinterpret_cast(VirtualAlloc(NULL, + char* all_memory = reinterpret_cast(VirtualAlloc(nullptr, kPageSize * 2, MEM_RESERVE, PAGE_NOACCESS)); @@ -496,12 +501,12 @@ TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemoryMinBound) { TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemoryMaxBound) { ASSERT_TRUE(DoesPathExist(temp_path_)); - scoped_ptr exc( + std::unique_ptr exc( new google_breakpad::ExceptionHandler( temp_path_, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, google_breakpad::ExceptionHandler::HANDLER_ALL)); // Disable GTest SEH handler @@ -516,7 +521,7 @@ TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemoryMaxBound) { const int kOffset = kPageSize - sizeof(instructions); // Get some executable memory. Specifically, reserve two pages, // but only commit the first. - char* memory = reinterpret_cast(VirtualAlloc(NULL, + char* memory = reinterpret_cast(VirtualAlloc(nullptr, kPageSize * 2, MEM_RESERVE, PAGE_NOACCESS)); diff --git a/src/client/windows/unittests/exception_handler_nesting_test.cc b/src/client/windows/unittests/exception_handler_nesting_test.cc index e24bd18b6..5b6420b3e 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -133,7 +136,7 @@ void DoCrash(const char* message) { fprintf(stderr, "%s", message); fflush(stderr); } - int* i = NULL; + int* i = nullptr; (*i)++; ASSERT_TRUE(false); @@ -153,23 +156,23 @@ void InstallExceptionHandlerAndCrash(bool install_filter, (filter_return_value ? &CrashHandlerFilter : &CrashHandlerFilter) : - NULL, + nullptr, install_callback ? (callback_return_value ? &MinidumpWrittenCallback : &MinidumpWrittenCallback) : - NULL, - NULL, // callback_context + nullptr, + nullptr, // callback_context google_breakpad::ExceptionHandler::HANDLER_EXCEPTION); // Disable GTest SEH handler testing::DisableExceptionHandlerInScope disable_exception_handler; - DoCrash(NULL); + DoCrash(nullptr); } TEST(AssertDeathSanity, Simple) { - ASSERT_DEATH(DoCrash(NULL), ""); + ASSERT_DEATH(DoCrash(nullptr), ""); } TEST(AssertDeathSanity, Regex) { @@ -261,7 +264,7 @@ TEST(ExceptionHandlerNesting, Skip_From_Inner_Filter) { temp_path, &CrashHandlerFilter, &MinidumpWrittenCallback, - NULL, // callback_context + nullptr, // callback_context google_breakpad::ExceptionHandler::HANDLER_EXCEPTION); ASSERT_DEATH( @@ -285,7 +288,7 @@ TEST(ExceptionHandlerNesting, Skip_From_Inner_Callback) { temp_path, &CrashHandlerFilter, &MinidumpWrittenCallback, - NULL, // callback_context + nullptr, // callback_context google_breakpad::ExceptionHandler::HANDLER_EXCEPTION); ASSERT_DEATH( @@ -310,7 +313,7 @@ TEST(ExceptionHandlerNesting, Handled_By_Inner_Handler) { temp_path, &CrashHandlerFilter, &MinidumpWrittenCallback, - NULL, // callback_context + nullptr, // callback_context google_breakpad::ExceptionHandler::HANDLER_EXCEPTION); ASSERT_DEATH( diff --git a/src/client/windows/unittests/exception_handler_test.cc b/src/client/windows/unittests/exception_handler_test.cc index 51196ca06..9ebc93fdc 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. // @@ -27,8 +26,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "client/windows/unittests/exception_handler_test.h" +#include #include #include #include @@ -127,7 +131,7 @@ void ExceptionHandlerTest::SetUp() { assert(false); } StringCchPrintfW(temp_path_, MAX_PATH, L"%s%s", temp_path, test_name_wide); - CreateDirectory(temp_path_, NULL); + CreateDirectory(temp_path_, nullptr); } void ExceptionHandlerTest::TearDown() { @@ -176,9 +180,9 @@ bool ExceptionHandlerTest::DumpCallback(const wchar_t* dump_path, void ExceptionHandlerTest::DoCrashInvalidParameter() { google_breakpad::ExceptionHandler* exc = new google_breakpad::ExceptionHandler( - temp_path_, NULL, NULL, NULL, + temp_path_, nullptr, nullptr, nullptr, google_breakpad::ExceptionHandler::HANDLER_INVALID_PARAMETER, - kFullDumpType, kPipeName, NULL); + kFullDumpType, kPipeName, nullptr); // Disable the message box for assertions _CrtSetReportMode(_CRT_ASSERT, 0); @@ -187,7 +191,7 @@ void ExceptionHandlerTest::DoCrashInvalidParameter() { // if it's not true we'll still get an error rather than the crash // being expected. ASSERT_TRUE(exc->IsOutOfProcess()); - printf(NULL); + printf(nullptr); } @@ -208,9 +212,9 @@ struct PureVirtualCall : public PureVirtualCallBase { void ExceptionHandlerTest::DoCrashPureVirtualCall() { google_breakpad::ExceptionHandler* exc = new google_breakpad::ExceptionHandler( - temp_path_, NULL, NULL, NULL, + temp_path_, nullptr, nullptr, nullptr, google_breakpad::ExceptionHandler::HANDLER_PURECALL, - kFullDumpType, kPipeName, NULL); + kFullDumpType, kPipeName, nullptr); // Disable the message box for assertions _CrtSetReportMode(_CRT_ASSERT, 0); @@ -235,8 +239,8 @@ TEST_F(ExceptionHandlerTest, InvalidParameterMiniDumpTest) { ASSERT_TRUE(DoesPathExist(temp_path_)); wstring dump_path(temp_path_); google_breakpad::CrashGenerationServer server( - kPipeName, NULL, NULL, NULL, ClientDumpCallback, NULL, NULL, NULL, NULL, - NULL, true, &dump_path); + kPipeName, nullptr, nullptr, nullptr, ClientDumpCallback, nullptr, + nullptr, nullptr, nullptr, nullptr, true, &dump_path); ASSERT_TRUE(dump_file.empty() && full_dump_file.empty()); @@ -307,8 +311,8 @@ TEST_F(ExceptionHandlerTest, PureVirtualCallMiniDumpTest) { ASSERT_TRUE(DoesPathExist(temp_path_)); wstring dump_path(temp_path_); google_breakpad::CrashGenerationServer server( - kPipeName, NULL, NULL, NULL, ClientDumpCallback, NULL, NULL, NULL, NULL, - NULL, true, &dump_path); + kPipeName, nullptr, nullptr, nullptr, ClientDumpCallback, nullptr, + nullptr, nullptr, nullptr, nullptr, true, &dump_path); ASSERT_TRUE(dump_file.empty() && full_dump_file.empty()); @@ -374,9 +378,9 @@ TEST_F(ExceptionHandlerTest, PureVirtualCallMiniDumpTest) { // some expected structures. TEST_F(ExceptionHandlerTest, WriteMinidumpTest) { ExceptionHandler handler(temp_path_, - NULL, + nullptr, DumpCallback, - NULL, + nullptr, ExceptionHandler::HANDLER_ALL); // Disable GTest SEH handler @@ -412,9 +416,9 @@ TEST_F(ExceptionHandlerTest, AdditionalMemory) { } ExceptionHandler handler(temp_path_, - NULL, + nullptr, DumpCallback, - NULL, + nullptr, ExceptionHandler::HANDLER_ALL); // Disable GTest SEH handler @@ -466,9 +470,9 @@ TEST_F(ExceptionHandlerTest, AdditionalMemoryRemove) { } ExceptionHandler handler(temp_path_, - NULL, + nullptr, DumpCallback, - NULL, + nullptr, ExceptionHandler::HANDLER_ALL); // Disable GTest SEH handler diff --git a/src/client/windows/unittests/exception_handler_test.h b/src/client/windows/unittests/exception_handler_test.h index ef973e539..9d4e44e41 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 82641125c..1fe52f5cc 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -65,12 +68,12 @@ class MinidumpTest: public testing::Test { virtual void SetUp() { // Make sure URLMon isn't loaded into our process. - ASSERT_EQ(NULL, ::GetModuleHandle(L"urlmon.dll")); + ASSERT_EQ(nullptr, ::GetModuleHandle(L"urlmon.dll")); // Then load and unload it to ensure we have something to // stock the unloaded module list with. HMODULE urlmon = ::LoadLibrary(L"urlmon.dll"); - ASSERT_TRUE(urlmon != NULL); + ASSERT_TRUE(urlmon != nullptr); ASSERT_TRUE(::FreeLibrary(urlmon)); } @@ -92,7 +95,7 @@ class MinidumpTest: public testing::Test { EXCEPTION_RECORD ex_record = { STATUS_ACCESS_VIOLATION, // ExceptionCode 0, // ExceptionFlags - NULL, // ExceptionRecord; + nullptr, // ExceptionRecord; reinterpret_cast(static_cast(0xCAFEBABE)), // ExceptionAddress; 2, // NumberParameters; { EXCEPTION_WRITE_FAULT, reinterpret_cast(this) } @@ -109,7 +112,7 @@ class MinidumpTest: public testing::Test { ::GetCurrentThreadId(), ::GetCurrentThreadId(), &ex_ptrs, - NULL, + nullptr, static_cast(flags), TRUE); generator.GenerateDumpFile(&dump_file_); @@ -132,7 +135,7 @@ bool HasFileInfo(const std::wstring& file_path) { const wchar_t* path = file_path.c_str(); DWORD length = ::GetFileVersionInfoSize(path, &dummy); if (length == 0) - return NULL; + return nullptr; void* data = calloc(length, 1); if (!data) @@ -143,7 +146,7 @@ bool HasFileInfo(const std::wstring& file_path) { return false; } - void* translate = NULL; + void* translate = nullptr; UINT page_count; BOOL query_result = VerQueryValue( data, @@ -164,14 +167,14 @@ TEST_F(MinidumpTest, Version) { ImagehlpApiVersion(); HMODULE dbg_help = ::GetModuleHandle(L"dbghelp.dll"); - ASSERT_TRUE(dbg_help != NULL); + ASSERT_TRUE(dbg_help != nullptr); wchar_t dbg_help_file[1024] = {}; ASSERT_TRUE(::GetModuleFileName(dbg_help, dbg_help_file, sizeof(dbg_help_file) / sizeof(*dbg_help_file))); - ASSERT_TRUE(HasFileInfo(std::wstring(dbg_help_file)) != NULL); + ASSERT_TRUE(HasFileInfo(std::wstring(dbg_help_file)) != nullptr); // LOG(INFO) << "DbgHelp.dll version: " << file_info->file_version(); } diff --git a/src/client/windows/unittests/testing.gyp b/src/client/windows/unittests/testing.gyp deleted file mode 100644 index 0f9f944c2..000000000 --- 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 e6f0c672f..80e4c8355 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 4324629df..02d2db26c 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 cd9290215..28882445a 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 185124364..f7ff97743 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 9c27ef022..021ec90d0 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 85373fd2a..aa17c731f 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 b86e2cd78..2664e8012 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. // @@ -54,9 +53,9 @@ namespace { char* breakpad_mkdtemp(char* path) { - if (path == NULL) { + if (path == nullptr) { errno = EINVAL; - return NULL; + return nullptr; } // 'path' must be terminated with six 'X' @@ -67,23 +66,23 @@ char* breakpad_mkdtemp(char* path) { if (static_cast(path_end - path) < kSuffixLen || memcmp(path_end - kSuffixLen, kSuffix, kSuffixLen) != 0) { errno = EINVAL; - return NULL; + return nullptr; } // If 'path' contains a directory separator, check that it exists to // avoid looping later. char* sep = strrchr(path, '/'); - if (sep != NULL) { + if (sep != nullptr) { struct stat st; int ret; *sep = '\0'; // temporarily zero-terminate the dirname. ret = stat(path, &st); *sep = '/'; // restore full path. if (ret < 0) - return NULL; + return nullptr; if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; - return NULL; + return nullptr; } } @@ -98,11 +97,11 @@ char* breakpad_mkdtemp(char* path) { return path; // Success if (errno != EEXIST) - return NULL; + return nullptr; } assert(errno == EEXIST); - return NULL; + return nullptr; } } // namespace diff --git a/src/common/android/testing/pthread_fixes.h b/src/common/android/testing/pthread_fixes.h index b0a3d82e4..f9caee938 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. // @@ -54,8 +53,8 @@ int pthread_barrier_init(pthread_barrier_t* barrier, const void* /* barrier_attr */, unsigned count) { barrier->count = count; - pthread_mutex_init(&barrier->mutex, NULL); - pthread_cond_init(&barrier->cond, NULL); + pthread_mutex_init(&barrier->mutex, nullptr); + pthread_cond_init(&barrier->cond, nullptr); return 0; } diff --git a/src/common/basictypes.h b/src/common/basictypes.h index 9426c1f6c..26b997d08 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. // @@ -30,14 +29,6 @@ #ifndef COMMON_BASICTYPES_H_ #define COMMON_BASICTYPES_H_ -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#ifndef DISALLOW_COPY_AND_ASSIGN -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) -#endif // DISALLOW_COPY_AND_ASSIGN - namespace google_breakpad { // Used to explicitly mark the return value of a function as unused. If you are @@ -45,7 +36,7 @@ namespace google_breakpad { // that has been marked with __attribute__((warn_unused_result)), wrap it with // this. Example: // -// scoped_ptr my_var = ...; +// std::unique_ptr my_var = ...; // if (TakeOwnership(my_var.get()) == SUCCESS) // ignore_result(my_var.release()); // diff --git a/src/common/byte_cursor.h b/src/common/byte_cursor.h index 28bb8e767..8033e9db1 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. // @@ -219,7 +218,7 @@ class ByteCursor { *pointer = here_; here_ += size; } else { - *pointer = NULL; + *pointer = nullptr; } return *this; } diff --git a/src/common/byte_cursor_unittest.cc b/src/common/byte_cursor_unittest.cc index 45e6f2b4b..69b31d3f8 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. // @@ -32,6 +31,10 @@ // byte_cursor_unittest.cc: Unit tests for google_breakpad::ByteBuffer // and google_breakpad::ByteCursor. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -730,7 +733,7 @@ TEST(Strings, PointTo) { EXPECT_EQ(data + 0, received1); EXPECT_EQ(data + 3, received2); EXPECT_EQ(data + 6, received3); - EXPECT_EQ(NULL, received4); + EXPECT_EQ(nullptr, received4); } TEST(Strings, CString) { diff --git a/src/common/common.gyp b/src/common/common.gyp deleted file mode 100644 index c1dbb0feb..000000000 --- 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/convert_UTF.cc b/src/common/convert_UTF.cc index 4a5df1eb2..60a0d7aa9 100644 --- a/src/common/convert_UTF.cc +++ b/src/common/convert_UTF.cc @@ -55,6 +55,10 @@ See the header file "ConvertUTF.h" for complete documentation. ------------------------------------------------------------------------ */ +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "convert_UTF.h" #ifdef CVTUTF_DEBUG #include @@ -293,15 +297,15 @@ ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sou case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - BP_FALLTHROUGH; + [[fallthrough]]; case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - BP_FALLTHROUGH; + [[fallthrough]]; case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - BP_FALLTHROUGH; + [[fallthrough]]; case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); } @@ -334,10 +338,10 @@ Boolean isLegalUTF8(const UTF8 *source, int length) { /* Everything else falls through when "true"... */ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - BP_FALLTHROUGH; + [[fallthrough]]; case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - BP_FALLTHROUGH; + [[fallthrough]]; case 2: if ((a = (*--srcptr)) > 0xBF) return false; @@ -349,7 +353,7 @@ Boolean isLegalUTF8(const UTF8 *source, int length) { case 0xF4: if (a > 0x8F) return false; break; default: if (a < 0x80) return false; } - BP_FALLTHROUGH; + [[fallthrough]]; case 1: if (*source >= 0x80 && *source < 0xC2) return false; } if (*source > 0xF4) return false; @@ -395,12 +399,12 @@ ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourc */ switch (extraBytesToRead) { /* remember, illegal UTF-8 */ - case 5: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + case 5: ch += *source++; ch <<= 6; [[fallthrough]]; /* remember, illegal UTF-8 */ - case 4: ch += *source++; ch <<= 6; BP_FALLTHROUGH; - case 3: ch += *source++; ch <<= 6; BP_FALLTHROUGH; - case 2: ch += *source++; ch <<= 6; BP_FALLTHROUGH; - case 1: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + case 4: ch += *source++; ch <<= 6; [[fallthrough]]; + case 3: ch += *source++; ch <<= 6; [[fallthrough]]; + case 2: ch += *source++; ch <<= 6; [[fallthrough]]; + case 1: ch += *source++; ch <<= 6; [[fallthrough]]; case 0: ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; @@ -489,15 +493,15 @@ ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sou case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - BP_FALLTHROUGH; + [[fallthrough]]; case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - BP_FALLTHROUGH; + [[fallthrough]]; case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - BP_FALLTHROUGH; + [[fallthrough]]; case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); } @@ -530,11 +534,11 @@ ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourc * The cases all fall through. See "Note A" below. */ switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; BP_FALLTHROUGH; - case 4: ch += *source++; ch <<= 6; BP_FALLTHROUGH; - case 3: ch += *source++; ch <<= 6; BP_FALLTHROUGH; - case 2: ch += *source++; ch <<= 6; BP_FALLTHROUGH; - case 1: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + case 5: ch += *source++; ch <<= 6; [[fallthrough]]; + case 4: ch += *source++; ch <<= 6; [[fallthrough]]; + case 3: ch += *source++; ch <<= 6; [[fallthrough]]; + case 2: ch += *source++; ch <<= 6; [[fallthrough]]; + case 1: ch += *source++; ch <<= 6; [[fallthrough]]; case 0: ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; diff --git a/src/common/dwarf/bytereader-inl.h b/src/common/dwarf/bytereader-inl.h index 448be2376..210264840 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,7 +34,7 @@ #include #include -namespace dwarf2reader { +namespace google_breakpad { inline uint8_t ByteReader::ReadOneByte(const uint8_t* buffer) const { return buffer[0]; @@ -176,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 ac5064a77..eea6850d6 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. // @@ -26,17 +26,22 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include #include "common/dwarf/bytereader-inl.h" #include "common/dwarf/bytereader.h" +#include "common/memory_allocator.h" -namespace dwarf2reader { +namespace google_breakpad { ByteReader::ByteReader(enum Endianness endian) - :offset_reader_(NULL), address_reader_(NULL), endian_(endian), + :offset_reader_(nullptr), address_reader_(nullptr), endian_(endian), address_size_(0), offset_size_(0), have_section_base_(), have_text_base_(), have_data_base_(), have_function_base_() { } @@ -128,7 +133,7 @@ uint64_t ByteReader::ReadEncodedPointer(const uint8_t* buffer, // Now find the offset from that aligned address to buffer. uint64_t offset = skew + (buffer - buffer_base_); // Round up to the next boundary. - uint64_t aligned = (offset + AddressSize() - 1) & -AddressSize(); + uint64_t aligned = PageAllocator::AlignUp(offset, AddressSize()); // Convert back to a pointer. const uint8_t* aligned_buffer = buffer_base_ + (aligned - skew); // Finally, store the length and actually fetch the pointer. @@ -247,4 +252,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 5d7a9a7fb..761eaf688 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 @@ -315,6 +315,6 @@ class ByteReader { 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 3d7924b9c..a5eb0da53 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,11 @@ // Original author: Jim Blandy -// bytereader_unittest.cc: Unit tests for dwarf2reader::ByteReader +// bytereader_unittest.cc: Unit tests for google_breakpad::ByteReader + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif #include @@ -41,10 +44,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; @@ -91,279 +94,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 +383,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 +393,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 +405,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 +415,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 +425,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 +435,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 +447,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 +459,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 +469,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 +479,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 +489,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 +501,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 +513,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 +529,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 +544,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 +559,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 +570,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 +619,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 +644,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 +652,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 +660,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 +668,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 +677,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 +686,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 +695,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 +704,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 858fd5618..773fd250f 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. // @@ -32,14 +31,16 @@ // cfi_assembler.cc: Implementation of google_breakpad::CFISection class. // See cfi_assembler.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/dwarf/cfi_assembler.h" #include #include namespace google_breakpad { - -using dwarf2reader::DwarfPointerEncoding; CFISection& CFISection::CIEHeader(uint64_t code_alignment_factor, int data_alignment_factor, @@ -115,10 +116,10 @@ CFISection& CFISection::FDEHeader(Label cie_pointer, 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; + entry_length_ = nullptr; in_fde_ = false; return *this; } @@ -127,24 +128,24 @@ CFISection& CFISection::EncodedPointer(uint64_t address, DwarfPointerEncoding encoding, 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 +154,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 +162,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 d60ecc9e2..c707632d4 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,11 +92,11 @@ 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), - encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) { + pointer_encoding_(DW_EH_PE_absptr), + encoded_pointer_bases_(), entry_length_(nullptr), in_fde_(false) { // The 'start', 'Here', and 'Mark' members of a CFISection all refer // to section offsets. start() = 0; diff --git a/src/common/dwarf/dwarf2diehandler.cc b/src/common/dwarf/dwarf2diehandler.cc index f5a0683ed..1c95ad20c 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. // @@ -31,6 +31,10 @@ // dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class. // See dwarf2diehandler.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -39,7 +43,7 @@ #include "common/dwarf/dwarf2diehandler.h" #include "common/using_std_string.h" -namespace dwarf2reader { +namespace google_breakpad { DIEDispatcher::~DIEDispatcher() { while (!die_handlers_.empty()) { @@ -60,7 +64,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() ? nullptr : &die_handlers_.top(); // Does this call indicate that we're done receiving the parent's // attributes' values? If so, call its EndAttributes member function. @@ -72,7 +76,7 @@ bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) { parent->handler_->Finish(); if (parent->handler_ != root_handler_) delete parent->handler_; - parent->handler_ = NULL; + parent->handler_ = nullptr; return false; } } @@ -86,7 +90,7 @@ bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) { else // No parent handler means we're not interested in any of our // children. - handler = NULL; + handler = nullptr; } else { // This is the root DIE. For a non-root DIE, the parent's handler // decides whether to visit it, but the root DIE has no parent @@ -95,7 +99,7 @@ bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) { if (root_handler_->StartRootDIE(offset, tag)) handler = root_handler_; else - handler = NULL; + handler = nullptr; } // Push a handler stack entry for this new handler. As an @@ -110,7 +114,7 @@ bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) { die_handlers_.push(entry); } - return handler != NULL; + return handler != nullptr; } void DIEDispatcher::EndDIE(uint64_t offset) { @@ -196,4 +200,4 @@ void DIEDispatcher::ProcessAttributeSignature(uint64_t 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 028a6d119..14be55acc 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: @@ -245,7 +245,7 @@ class DIEHandler { // // The default definition skips all children. virtual DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag) { - return NULL; + return nullptr; } // When we are done processing a DIE, we call this member function. @@ -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 @@ -361,5 +364,5 @@ class DIEDispatcher: public Dwarf2Handler { 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 552c3d11d..a52f2ab72 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. // @@ -32,6 +32,10 @@ // dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -53,12 +57,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: @@ -339,7 +343,7 @@ TEST(Dwarf2DIEHandler, FindAndSkipChildren) { EXPECT_CALL(mock_root_handler, FindChildHandler(0x97412be24875de9dLL, (DwarfTag) 0x505a068b)) - .WillOnce(Return((DIEHandler*) NULL)); + .WillOnce(Return((DIEHandler*) nullptr)); // Third child DIE. EXPECT_CALL(mock_root_handler, diff --git a/src/common/dwarf/dwarf2enums.h b/src/common/dwarf/dwarf2enums.h index e36225854..f1c995f92 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 @@ -580,10 +580,10 @@ enum DwarfSectionId { DW_SECT_TYPES = 2, DW_SECT_ABBREV = 3, DW_SECT_LINE = 4, - DW_SECT_LOC = 5, + DW_SECT_LOCLISTS = 5, DW_SECT_STR_OFFSETS = 6, - DW_SECT_MACINFO = 7, - DW_SECT_MACRO = 8 + DW_SECT_MACRO = 7, + DW_SECT_RNGLISTS = 8 }; // Source languages. These are values for DW_AT_language. @@ -740,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 1a9a451f3..4977dcda7 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,15 +28,22 @@ // CFI reader author: Jim Blandy -// 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif #include "common/dwarf/dwarf2reader.h" +#include #include #include #include +#include +#include #include #include #include @@ -51,7 +58,7 @@ #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) { @@ -62,6 +69,11 @@ const SectionMap::const_iterator GetSectionByName(const SectionMap& std::string macho_name("__"); macho_name += name + 1; iter = sections.find(macho_name); + + // .debug_str_offsets is alternatively named .debug_str_offs, so try both + if (iter == sections.end() && std::string(name) == ".debug_str_offsets") { + return GetSectionByName(sections, ".debug_str_offs"); + } return iter; } @@ -70,14 +82,15 @@ CompilationUnit::CompilationUnit(const string& path, ByteReader* reader, Dwarf2Handler* handler) : path_(path), offset_from_section_start_(offset), reader_(reader), sections_(sections), handler_(handler), abbrevs_(), - string_buffer_(NULL), string_buffer_length_(0), - 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), + string_buffer_(nullptr), string_buffer_length_(0), + line_string_buffer_(nullptr), line_string_buffer_length_(0), + str_offsets_buffer_(nullptr), str_offsets_buffer_length_(0), + addr_buffer_(nullptr), addr_buffer_length_(0), is_split_dwarf_(false), is_type_unit_(false), dwo_id_(0), dwo_name_(), - skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0), - str_offsets_base_(0), have_checked_for_dwp_(false), dwp_path_(), - dwp_byte_reader_(), dwp_reader_() {} + skeleton_dwo_id_(0), addr_base_(0), + str_offsets_base_(0), have_checked_for_dwp_(false), + should_process_split_dwarf_(false), low_pc_(0), + has_source_line_info_(false), source_line_offset_(0) {} // Initialize a compilation unit from a .dwo or .dwp file. // In this case, we need the .debug_addr section from the @@ -86,16 +99,10 @@ CompilationUnit::CompilationUnit(const string& path, // the executable file, and call it as if we were still // processing the original compilation unit. -void CompilationUnit::SetSplitDwarf(const uint8_t* addr_buffer, - uint64_t addr_buffer_length, - uint64_t addr_base, - uint64_t ranges_base, +void CompilationUnit::SetSplitDwarf(uint64_t addr_base, uint64_t dwo_id) { is_split_dwarf_ = true; - addr_buffer_ = addr_buffer; - addr_buffer_length_ = addr_buffer_length; addr_base_ = addr_base; - ranges_base_ = ranges_base; skeleton_dwo_id_ = dwo_id; } @@ -129,10 +136,13 @@ void CompilationUnit::ReadAbbrevs() { 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; @@ -170,9 +180,17 @@ void CompilationUnit::ReadAbbrevs() { value); abbrev.attributes.push_back(abbrev_attr); } - assert(abbrev.number == abbrevs_->size()); - abbrevs_->push_back(abbrev); + abbrevs_->push_back(std::move(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. @@ -274,8 +292,8 @@ const uint8_t* CompilationUnit::SkipAttribute(const uint8_t* start, case DW_FORM_sec_offset: return start + reader_->OffsetSize(); } - fprintf(stderr,"Unhandled form type"); - return NULL; + fprintf(stderr,"Unhandled form type 0x%x\n", form); + return nullptr; } // Read the abbreviation offset from a compilation unit header. @@ -358,7 +376,7 @@ void CompilationUnit::ReadHeader() { break; case DW_UT_type: case DW_UT_split_type: - is_type_unit_ = true; + is_type_unit_ = true; headerptr += ReadTypeSignature(headerptr); headerptr += ReadTypeOffset(headerptr); break; @@ -384,7 +402,13 @@ uint64_t CompilationUnit::Start() { // Set up our buffer buffer_ = iter->second.first + offset_from_section_start_; - buffer_length_ = iter->second.second - offset_from_section_start_; + if (is_split_dwarf_) { + iter = GetSectionByName(sections_, ".debug_info_offset"); + assert(iter != sections_.end()); + buffer_length_ = iter->second.second; + } else { + buffer_length_ = iter->second.second - offset_from_section_start_; + } // Read the header ReadHeader(); @@ -418,6 +442,12 @@ uint64_t CompilationUnit::Start() { string_buffer_length_ = iter->second.second; } + iter = GetSectionByName(sections_, ".debug_line"); + if (iter != sections_.end()) { + line_buffer_ = iter->second.first; + line_buffer_length_ = iter->second.second; + } + // Set the line string section if we have one. iter = GetSectionByName(sections_, ".debug_line_str"); if (iter != sections_.end()) { @@ -440,15 +470,18 @@ uint64_t CompilationUnit::Start() { } // Now that we have our abbreviations, start processing DIE's. - ProcessDIEs(); + if (!ProcessDIEs()) { + // If ProcessDIEs fails return 0, ourlength must be non-zero + // as it is equal to header_.length + (12 or 4) + return 0; + } // If this is a skeleton compilation unit generated with split DWARF, // and the client needs the full debug info, we need to find the full // compilation unit in a .dwo or .dwp file. - if (!is_split_dwarf_ - && dwo_name_ != NULL - && handler_->NeedSplitDebugInfo()) - ProcessSplitDwarf(); + should_process_split_dwarf_ = + !is_split_dwarf_ && dwo_name_ != nullptr && + handler_->NeedSplitDebugInfo(); return ourlength; } @@ -456,8 +489,14 @@ uint64_t CompilationUnit::Start() { 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_buffer_ + str_offsets_base_ + str_index * reader_->OffsetSize(); + str_offsets_table_after_header + str_index * reader_->OffsetSize(); + const uint64_t offset = reader_->ReadOffset(offset_ptr); if (offset >= string_buffer_length_) { return; @@ -467,11 +506,12 @@ void CompilationUnit::ProcessFormStringIndex( ProcessAttributeString(dieoffset, attr, form, str); } -// Special function for pre-processing the DW_AT_str_offsets_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 attribute before attempting to read -// any string attribute in the compile unit. -const uint8_t* CompilationUnit::ProcessStrOffsetBaseAttribute( +// 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; @@ -483,8 +523,8 @@ const uint8_t* CompilationUnit::ProcessStrOffsetBaseAttribute( form = static_cast(reader_->ReadUnsignedLEB128(start, &len)); start += len; - return ProcessStrOffsetBaseAttribute(dieoffset, start, attr, form, - implicit_const); + return ProcessOffsetBaseAttribute(dieoffset, start, attr, form, + implicit_const); case DW_FORM_flag_present: return start; @@ -516,11 +556,12 @@ const uint8_t* CompilationUnit::ProcessStrOffsetBaseAttribute( // This is the important one here! case DW_FORM_sec_offset: - if (attr == dwarf2reader::DW_AT_str_offsets_base) - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadOffset(start)); + if (attr == DW_AT_str_offsets_base || + attr == DW_AT_addr_base) + ProcessAttributeUnsigned(dieoffset, attr, form, + reader_->ReadOffset(start)); else - reader_->ReadOffset(start); + reader_->ReadOffset(start); return start + reader_->OffsetSize(); case DW_FORM_ref1: @@ -539,10 +580,10 @@ const uint8_t* CompilationUnit::ProcessStrOffsetBaseAttribute( // offset size. assert(header_.version >= 2); if (header_.version == 2) { - reader_->ReadAddress(start); + reader_->ReadAddress(start); return start + reader_->AddressSize(); } else if (header_.version >= 3) { - reader_->ReadOffset(start); + reader_->ReadOffset(start); return start + reader_->OffsetSize(); } break; @@ -618,8 +659,8 @@ const uint8_t* CompilationUnit::ProcessStrOffsetBaseAttribute( reader_->ReadUnsignedLEB128(start, &len); return start + len; } - fprintf(stderr, "Unhandled form type\n"); - return NULL; + fprintf(stderr,"Unhandled form type 0x%x\n", form); + return nullptr; } // If one really wanted, you could merge SkipAttribute and @@ -760,7 +801,7 @@ const uint8_t* CompilationUnit::ProcessAttribute( return start + datalen + len; } case DW_FORM_strp: { - assert(string_buffer_ != NULL); + assert(string_buffer_ != nullptr); const uint64_t offset = reader_->ReadOffset(start); assert(string_buffer_ + offset < string_buffer_ + string_buffer_length_); @@ -770,7 +811,7 @@ const uint8_t* CompilationUnit::ProcessAttribute( return start + reader_->OffsetSize(); } case DW_FORM_line_strp: { - assert(line_string_buffer_ != NULL); + assert(line_string_buffer_ != nullptr); const uint64_t offset = reader_->ReadOffset(start); assert(line_string_buffer_ + offset < @@ -851,25 +892,27 @@ const uint8_t* CompilationUnit::ProcessAttribute( return start + len; } fprintf(stderr, "Unhandled form type\n"); - return NULL; + return nullptr; } 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. If it does, that attribute must be found - // and processed before trying to process the other attributes; otherwise - // the string values will all come out incorrect. - if (abbrev.tag == DW_TAG_compile_unit && header_.version == 5) { + // 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 || + abbrev.tag == DW_TAG_skeleton_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 = ProcessStrOffsetBaseAttribute(dieoffset_copy, start_copy, - i->attr_, i->form_, - i->value_); + i != abbrev.attributes.end(); + i++) { + start_copy = ProcessOffsetBaseAttribute(dieoffset_copy, start_copy, + i->attr_, i->form_, + i->value_); } } @@ -885,13 +928,13 @@ const uint8_t* CompilationUnit::ProcessDIE(uint64_t dieoffset, if (abbrev.tag == DW_TAG_compile_unit && is_split_dwarf_ && dwo_id_ != skeleton_dwo_id_) { - return NULL; + return nullptr; } return start; } -void CompilationUnit::ProcessDIEs() { +bool CompilationUnit::ProcessDIEs() { const uint8_t* dieptr = after_header_; size_t len; @@ -907,7 +950,7 @@ void CompilationUnit::ProcessDIEs() { lengthstart += 4; std::stack 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. @@ -922,19 +965,42 @@ void CompilationUnit::ProcessDIEs() { if (abbrev_num == 0) { if (die_stack.size() == 0) // If it is padding, then we are done with the compilation unit's DIEs. - return; + return true; const uint64_t offset = die_stack.top(); die_stack.pop(); handler_->EndDIE(offset); continue; } + // Abbrev > abbrev_.size() indicates a corruption in the dwarf file. + if (abbrev_num > abbrevs_->size()) { + fprintf(stderr, "An invalid abbrev was referenced %" PRIu64 " / %zu. " + "Stopped procesing following DIEs in this CU.", abbrev_num, + abbrevs_->size()); + return false; + } + const Abbrev& abbrev = abbrevs_->at(static_cast(abbrev_num)); 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) { @@ -943,6 +1009,7 @@ void CompilationUnit::ProcessDIEs() { handler_->EndDIE(absolute_offset); } } + return true; } // Check for a valid ELF file and return the Address size. @@ -955,66 +1022,69 @@ inline int GetElfWidth(const ElfReader& elf) { return 0; } -void CompilationUnit::ProcessSplitDwarf() { +bool CompilationUnit::ProcessSplitDwarf(std::string& split_file, + SectionMap& sections, + ByteReader& split_byte_reader, + uint64_t& cu_offset) { + if (!should_process_split_dwarf_) + return false; struct stat statbuf; + bool found_in_dwp = false; if (!have_checked_for_dwp_) { // Look for a .dwp file in the same directory as the executable. have_checked_for_dwp_ = true; string dwp_suffix(".dwp"); - dwp_path_ = path_ + dwp_suffix; - if (stat(dwp_path_.c_str(), &statbuf) != 0) { + std::string dwp_path = path_ + dwp_suffix; + if (stat(dwp_path.c_str(), &statbuf) != 0) { // Fall back to a split .debug file in the same directory. string debug_suffix(".debug"); - dwp_path_ = path_; + dwp_path = path_; size_t found = path_.rfind(debug_suffix); - if (found + debug_suffix.length() == path_.length()) - dwp_path_ = dwp_path_.replace(found, debug_suffix.length(), dwp_suffix); + if (found != string::npos && + found + debug_suffix.length() == path_.length()) + dwp_path = dwp_path.replace(found, debug_suffix.length(), dwp_suffix); } - if (stat(dwp_path_.c_str(), &statbuf) == 0) { - ElfReader* elf = new ElfReader(dwp_path_); - int width = GetElfWidth(*elf); + if (stat(dwp_path.c_str(), &statbuf) == 0) { + split_elf_reader_ = std::make_unique(dwp_path); + int width = GetElfWidth(*split_elf_reader_.get()); if (width != 0) { - dwp_byte_reader_.reset(new ByteReader(reader_->GetEndianness())); - dwp_byte_reader_->SetAddressSize(width); - dwp_reader_.reset(new DwpReader(*dwp_byte_reader_, elf)); + split_byte_reader = ByteReader(reader_->GetEndianness()); + split_byte_reader.SetAddressSize(width); + dwp_reader_ = std::make_unique(split_byte_reader, + split_elf_reader_.get()); dwp_reader_->Initialize(); - } else { - delete elf; + // If we have a .dwp file, read the debug sections for the requested CU. + dwp_reader_->ReadDebugSectionsForCU(dwo_id_, §ions); + if (!sections.empty()) { + SectionMap::const_iterator cu_iter = + GetSectionByName(sections, ".debug_info_offset"); + SectionMap::const_iterator debug_info_iter = + GetSectionByName(sections, ".debug_info"); + assert(cu_iter != sections.end()); + assert(debug_info_iter != sections.end()); + cu_offset = cu_iter->second.first - debug_info_iter->second.first; + found_in_dwp = true; + split_file = dwp_path; + } } } } - bool found_in_dwp = false; - if (dwp_reader_) { - // If we have a .dwp file, read the debug sections for the requested CU. - SectionMap sections; - dwp_reader_->ReadDebugSectionsForCU(dwo_id_, §ions); - if (!sections.empty()) { - found_in_dwp = true; - CompilationUnit dwp_comp_unit(dwp_path_, sections, 0, - dwp_byte_reader_.get(), handler_); - dwp_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, addr_base_, - ranges_base_, dwo_id_); - dwp_comp_unit.Start(); - } - } if (!found_in_dwp) { // If no .dwp file, try to open the .dwo file. if (stat(dwo_name_, &statbuf) == 0) { - ElfReader elf(dwo_name_); - int width = GetElfWidth(elf); + split_elf_reader_ = std::make_unique(dwo_name_); + int width = GetElfWidth(*split_elf_reader_.get()); if (width != 0) { - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(width); - SectionMap sections; - ReadDebugSectionsFromDwo(&elf, §ions); - CompilationUnit dwo_comp_unit(dwo_name_, sections, 0, &reader, - handler_); - dwo_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, - addr_base_, ranges_base_, dwo_id_); - dwo_comp_unit.Start(); + split_byte_reader = ByteReader(ENDIANNESS_LITTLE); + split_byte_reader.SetAddressSize(width); + ReadDebugSectionsFromDwo(split_elf_reader_.get(), §ions); + if (!sections.empty()) { + split_file = dwo_name_; + } } } } + return !split_file.empty(); } void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader, @@ -1032,7 +1102,7 @@ void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader, size_t section_size; const char* section_data = elf_reader->GetSectionByName(dwo_name, §ion_size); - if (section_data != NULL) + if (section_data != nullptr) sections->insert(std::make_pair( base_name, std::make_pair( reinterpret_cast(section_data), @@ -1042,21 +1112,17 @@ void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader, DwpReader::DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader) : elf_reader_(elf_reader), byte_reader_(byte_reader), - cu_index_(NULL), cu_index_size_(0), string_buffer_(NULL), + cu_index_(nullptr), cu_index_size_(0), string_buffer_(nullptr), string_buffer_size_(0), version_(0), ncolumns_(0), nunits_(0), - nslots_(0), phash_(NULL), pindex_(NULL), shndx_pool_(NULL), - offset_table_(NULL), size_table_(NULL), abbrev_data_(NULL), - abbrev_size_(0), info_data_(NULL), info_size_(0), - str_offsets_data_(NULL), str_offsets_size_(0) {} - -DwpReader::~DwpReader() { - if (elf_reader_) delete elf_reader_; -} + nslots_(0), phash_(nullptr), pindex_(nullptr), shndx_pool_(nullptr), + offset_table_(nullptr), size_table_(nullptr), abbrev_data_(nullptr), + abbrev_size_(0), info_data_(nullptr), info_size_(0), + str_offsets_data_(nullptr), str_offsets_size_(0) {} void DwpReader::Initialize() { cu_index_ = elf_reader_->GetSectionByName(".debug_cu_index", &cu_index_size_); - if (cu_index_ == NULL) { + if (cu_index_ == nullptr) { return; } // The .debug_str.dwo section is shared by all CUs in the file. @@ -1092,6 +1158,8 @@ void DwpReader::Initialize() { info_data_ = elf_reader_->GetSectionByName(".debug_info.dwo", &info_size_); str_offsets_data_ = elf_reader_->GetSectionByName(".debug_str_offsets.dwo", &str_offsets_size_); + rnglist_data_ = + elf_reader_->GetSectionByName(".debug_rnglists.dwo", &rnglist_size_); if (size_table_ >= cu_index_ + cu_index_size_) { version_ = 0; } @@ -1192,13 +1260,24 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, } else if (section_id == DW_SECT_INFO) { sections->insert(std::make_pair( ".debug_info", - std::make_pair(reinterpret_cast (info_data_) - + offset, size))); + std::make_pair(reinterpret_cast(info_data_), 0))); + // .debug_info_offset will points the buffer for the CU with given + // dwo_id. + sections->insert(std::make_pair( + ".debug_info_offset", + std::make_pair( + reinterpret_cast(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 (str_offsets_data_) + offset, size))); + } else if (section_id == DW_SECT_RNGLISTS) { + sections->insert(std::make_pair( + ".debug_rnglists", + std::make_pair( + reinterpret_cast(rnglist_data_) + offset, + size))); } } sections->insert(std::make_pair( @@ -1259,7 +1338,7 @@ LineInfo::LineInfo(const uint8_t* buffer, uint64_t buffer_length, string_buffer_length_ = string_buffer_length; line_string_buffer_length_ = line_string_buffer_length; #endif - header_.std_opcode_lengths = NULL; + header_.std_opcode_lengths = nullptr; } uint64_t LineInfo::Start() { @@ -1698,7 +1777,7 @@ bool LineInfo::ProcessOneOpcode(ByteReader* reader, oplen += templen; if (handler) { - handler->DefineFile(filename, -1, static_cast(dirindex), + handler->DefineFile(filename, -1, static_cast(dirindex), mod_time, filelength); } } @@ -1753,14 +1832,14 @@ void LineInfo::ReadLines() { size_t oplength; bool add_row = ProcessOneOpcode(reader_, handler_, header_, lineptr, &lsm, &oplength, (uintptr)-1, - NULL); + nullptr); if (add_row) { if (have_pending_line) handler_->AddLine(pending_address, lsm.address - pending_address, 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; @@ -1776,54 +1855,6 @@ void LineInfo::ReadLines() { after_header_ = lengthstart + header_.total_length; } -bool RangeListReader::SetRangesBase(uint64_t offset) { - // Versions less than 5 don't use ranges base. - if (cu_info_->version_ < 5) { - return true; - } - // Length may not be 12 bytes, but if 12 bytes aren't available - // at this point, then the header is too short. - if (offset + 12 >= cu_info_->size_) { - return false; - } - // The length of this CU's contribution. - uint64_t cu_length = reader_->ReadFourBytes(cu_info_->buffer_ + offset); - offset += 4; - if (cu_length == 0xffffffffUL) { - cu_length = reader_->ReadEightBytes(cu_info_->buffer_ + offset); - offset += 8; - } - - // Truncating size here results in correctly ignoring everything not from - // this cu from here on out. - cu_info_->size_ = offset + cu_length; - - // Check for the rest of the header in advance. - if (offset + 8 >= cu_info_->size_) { - return false; - } - // Version. Can only read version 5. - if (reader_->ReadTwoBytes(cu_info_->buffer_ + offset) != 5) { - return false; - } - offset += 2; - // Address size - if (reader_->ReadOneByte(cu_info_->buffer_ + offset) != - reader_->AddressSize()) { - return false; - } - offset += 1; - // Segment selectors are unsupported - if (reader_->ReadOneByte(cu_info_->buffer_ + offset) != 0) { - return false; - } - offset += 1; - offset_entry_count_ = reader_->ReadFourBytes(cu_info_->buffer_ + offset); - offset += 4; - offset_array_ = offset; - return true; -} - bool RangeListReader::ReadRanges(enum DwarfForm form, uint64_t data) { if (form == DW_FORM_sec_offset) { if (cu_info_->version_ <= 4) { @@ -1832,15 +1863,17 @@ bool RangeListReader::ReadRanges(enum DwarfForm form, uint64_t data) { return ReadDebugRngList(data); } } else if (form == DW_FORM_rnglistx) { - SetRangesBase(cu_info_->ranges_base_); - if (data >= offset_entry_count_) { - return false; + if (cu_info_->ranges_base_ == 0) { + // In split dwarf, there's no DW_AT_rnglists_base attribute, range_base + // will just be the first byte after the header. + cu_info_->ranges_base_ = reader_->OffsetSize() == 4? 12: 20; } - uint64_t index_offset = reader_->AddressSize() * data; + offset_array_ = cu_info_->ranges_base_; + uint64_t index_offset = reader_->OffsetSize() * data; uint64_t range_list_offset = - reader_->ReadAddress(cu_info_->buffer_ + offset_array_ + index_offset); + reader_->ReadOffset(cu_info_->buffer_ + offset_array_ + index_offset); - return ReadDebugRngList(range_list_offset); + return ReadDebugRngList(offset_array_ + range_list_offset); } return false; } @@ -1988,7 +2021,7 @@ class CallFrameInfo::UndefinedRule: public CallFrameInfo::Rule { // 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(&rhs); - return (our_rhs != NULL); + return (our_rhs != nullptr); } Rule* Copy() const { return new UndefinedRule(*this); } }; @@ -2005,7 +2038,7 @@ class CallFrameInfo::SameValueRule: public CallFrameInfo::Rule { // 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(&rhs); - return (our_rhs != NULL); + return (our_rhs != nullptr); } Rule* Copy() const { return new SameValueRule(*this); } }; @@ -2129,8 +2162,8 @@ class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule { // A map from register numbers to rules. class CallFrameInfo::RuleMap { public: - RuleMap() : cfa_rule_(NULL) { } - RuleMap(const RuleMap& rhs) : cfa_rule_(NULL) { *this = rhs; } + RuleMap() : cfa_rule_(nullptr) { } + RuleMap(const RuleMap& rhs) : cfa_rule_(nullptr) { *this = rhs; } ~RuleMap() { Clear(); } RuleMap& operator=(const RuleMap& rhs); @@ -2190,7 +2223,7 @@ CallFrameInfo::Rule* CallFrameInfo::RuleMap::RegisterRule(int reg) const { if (it != registers_.end()) return it->second->Copy(); else - return NULL; + return nullptr; } void CallFrameInfo::RuleMap::SetRegisterRule(int reg, Rule* rule) { @@ -2271,7 +2304,7 @@ bool CallFrameInfo::RuleMap::HandleTransitionTo( // Remove all register rules and clear cfa_rule_. void CallFrameInfo::RuleMap::Clear() { delete cfa_rule_; - cfa_rule_ = NULL; + cfa_rule_ = nullptr; for (RuleByNumber::iterator it = registers_.begin(); it != registers_.end(); it++) delete it->second; @@ -2287,7 +2320,7 @@ class CallFrameInfo::State { State(ByteReader* reader, Handler* handler, Reporter* reporter, uint64_t address) : reader_(reader), handler_(handler), reporter_(reporter), - address_(address), entry_(NULL), cursor_(NULL) { } + address_(address), entry_(nullptr), cursor_(nullptr) { } // Interpret instructions from CIE, save the resulting rule set for // DW_CFA_restore instructions, and return true. On error, report @@ -2298,7 +2331,7 @@ class CallFrameInfo::State { // report the problem to reporter_ and return false. bool InterpretFDE(const FDE& fde); - private: + private: // The operands of a CFI instruction, for ParseOperands. struct Operands { unsigned register_number; // A register number. @@ -2559,19 +2592,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; @@ -2752,23 +2785,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; } @@ -2852,7 +2894,7 @@ bool CallFrameInfo::ReadEntryPrologue(const uint8_t* cursor, Entry* entry) { entry->offset = cursor - buffer_; entry->start = cursor; entry->kind = kUnknown; - entry->end = NULL; + entry->end = nullptr; // Read the initial length. This sets reader_'s offset size. size_t length_size; @@ -2872,7 +2914,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, @@ -2914,11 +2956,11 @@ 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; - entry->cie = NULL; + entry->cie = nullptr; return true; } @@ -3142,7 +3184,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 @@ -3180,7 +3222,7 @@ bool CallFrameInfo::ReadFDEFields(FDE* fde) { return true; } - + bool CallFrameInfo::Start() { const uint8_t* buffer_end = buffer_ + buffer_length_; const uint8_t* cursor; @@ -3237,7 +3279,7 @@ bool CallFrameInfo::Start() { reporter_->CIEPointerOutOfRange(fde.offset, fde.id); continue; } - + CIE cie; // Parse this FDE's CIE header. @@ -3276,7 +3318,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) { @@ -3463,4 +3505,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 3ff3e07b6..bd2e4d2e9 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. // @@ -56,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; @@ -277,14 +277,12 @@ class RangeListReader { RangeListReader(ByteReader* reader, CURangesInfo* cu_info, RangeListHandler* handler) : reader_(reader), cu_info_(cu_info), handler_(handler), - offset_array_(0), offset_entry_count_(0) { } + offset_array_(0) { } // Read ranges from cu_info as specified by form and data. bool ReadRanges(enum DwarfForm form, uint64_t data); private: - bool SetRangesBase(uint64_t base); - // Read dwarf4 .debug_ranges at offset. bool ReadDebugRanges(uint64_t offset); // Read dwarf5 .debug_rngslist at offset. @@ -316,7 +314,6 @@ class RangeListReader { CURangesInfo* cu_info_; RangeListHandler* handler_; uint64_t offset_array_; - uint64_t offset_entry_count_; }; // This class is the main interface between the reader and the @@ -472,8 +469,7 @@ class CompilationUnit { // compilation unit. We also inherit the Dwarf2Handler from // the executable file, and call it as if we were still // processing the original compilation unit. - void SetSplitDwarf(const uint8_t* addr_buffer, uint64_t addr_buffer_length, - uint64_t addr_base, uint64_t ranges_base, uint64_t dwo_id); + void SetSplitDwarf(uint64_t addr_base, uint64_t dwo_id); // Begin reading a Dwarf2 compilation unit, and calling the // callbacks in the Dwarf2Handler @@ -484,6 +480,36 @@ class CompilationUnit { // start of the next compilation unit, if there is one. uint64_t Start(); + // Process the actual debug information in a split DWARF file. + bool ProcessSplitDwarf(std::string& split_file, + SectionMap& sections, + ByteReader& split_byte_reader, + uint64_t& cu_offset); + + const uint8_t* GetAddrBuffer() { return addr_buffer_; } + + uint64_t GetAddrBufferLen() { return addr_buffer_length_; } + + uint64_t GetAddrBase() { return addr_base_; } + + uint64_t GetLowPC() { return low_pc_; } + + uint64_t GetDWOID() { return dwo_id_; } + + const uint8_t* GetLineBuffer() { return line_buffer_; } + + uint64_t GetLineBufferLen() { return line_buffer_length_; } + + const uint8_t* GetLineStrBuffer() { return line_string_buffer_; } + + uint64_t GetLineStrBufferLen() { return line_string_buffer_length_; } + + bool HasSourceLineInfo() { return has_source_line_info_; } + + uint64_t GetSourceLineOffset() { return source_line_offset_; } + + bool ShouldProcessSplitDwarf() { return should_process_split_dwarf_; } + private: // This struct represents a single DWARF2/3 abbreviation @@ -541,13 +567,13 @@ class CompilationUnit { enum DwarfForm form, uint64_t implicit_const); - // Special version of ProcessAttribute, for finding str_offsets_base in - // DW_TAG_compile_unit, for DWARF v5. - const uint8_t* ProcessStrOffsetBaseAttribute(uint64_t dieoffset, - const uint8_t* start, - enum DwarfAttribute attr, - 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 @@ -568,14 +594,12 @@ class CompilationUnit { 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; + else if (attr == DW_AT_low_pc) { + low_pc_ = data; } - // TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5, - // that base will apply to DW_AT_ranges attributes in the - // skeleton CU as well as in the .dwo/.dwp files. - else if (attr == DW_AT_ranges && is_split_dwarf_) { - data += ranges_base_; + else if (attr == DW_AT_stmt_list) { + has_source_line_info_ = true; + source_line_offset_ = data; } handler_->ProcessAttributeUnsigned(offset, attr, form, data); } @@ -640,7 +664,7 @@ class CompilationUnit { } // Processes all DIEs for this compilation unit - void ProcessDIEs(); + bool ProcessDIEs(); // Skips the die with attributes specified in ABBREV starting at // START, and return the new place to position the stream to. @@ -650,9 +674,6 @@ class CompilationUnit { // new place to position the stream to. const uint8_t* SkipAttribute(const uint8_t* start, enum DwarfForm form); - // Process the actual debug information in a split DWARF file. - void ProcessSplitDwarf(); - // Read the debug sections from a .dwo file. void ReadDebugSectionsFromDwo(ElfReader* elf_reader, SectionMap* sections); @@ -661,7 +682,7 @@ class CompilationUnit { const string path_; // Offset from section start is the offset of this compilation unit - // from the beginning of the .debug_info section. + // from the beginning of the .debug_info/.debug_info.dwo section. uint64_t offset_from_section_start_; // buffer is the buffer for our CU, starting at .debug_info + offset @@ -691,7 +712,7 @@ class CompilationUnit { const uint8_t* string_buffer_; uint64_t string_buffer_length_; - // Similarly for .debug_line_string. + // Similarly for .debug_line_str. const uint8_t* line_string_buffer_; uint64_t line_string_buffer_length_; @@ -705,6 +726,10 @@ class CompilationUnit { const uint8_t* addr_buffer_; uint64_t addr_buffer_length_; + // .debug_line section buffer and length. + const uint8_t* line_buffer_; + uint64_t line_buffer_length_; + // Flag indicating whether this compilation unit is part of a .dwo // or .dwp file. If true, we are reading this unit because a // skeleton compilation unit in an executable file had a @@ -733,10 +758,6 @@ class CompilationUnit { // from the skeleton CU. uint64_t skeleton_dwo_id_; - // 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_; @@ -746,14 +767,20 @@ class CompilationUnit { // True if we have already looked for a .dwp file. bool have_checked_for_dwp_; - // Path to the .dwp file. - string dwp_path_; - - // ByteReader for the DWP file. - std::unique_ptr dwp_byte_reader_; + // ElfReader for the dwo/dwo file. + std::unique_ptr split_elf_reader_; // DWP reader. - std::unique_ptr dwp_reader_; + std::unique_ptr dwp_reader_; + + bool should_process_split_dwarf_; + + // The value of the DW_AT_low_pc attribute, if any. + uint64_t low_pc_; + + // The value of DW_AT_stmt_list attribute if any. + bool has_source_line_info_; + uint64_t source_line_offset_; }; // A Reader for a .dwp file. Supports the fetching of DWARF debug @@ -773,8 +800,6 @@ class DwpReader { public: DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader); - ~DwpReader(); - // Read the CU index and initialize data members. void Initialize(); @@ -842,6 +867,8 @@ class DwpReader { size_t info_size_; const char* str_offsets_data_; size_t str_offsets_size_; + const char* rnglist_data_; + size_t rnglist_size_; }; // This class is a reader for DWARF's Call Frame Information. CFI @@ -882,11 +909,11 @@ class DwpReader { // // For example, here is a complete (uncompressed) table describing the // function above: -// +// // insn cfa r0 r1 ... ra // ======================================= // func+0: sp cfa[0] -// func+1: sp+16 cfa[0] +// func+1: sp+16 cfa[0] // func+2: sp+16 cfa[-4] cfa[0] // func+11: sp+20 cfa[-4] cfa[0] // func+21: sp+20 cfa[0] @@ -920,7 +947,7 @@ class DwpReader { // save them, caller-saves registers are probably dead in the caller // anyway, so compilers usually don't generate CFA for caller-saves // registers.) -// +// // - Exactly where the CFA points is a matter of convention that // depends on the architecture and ABI in use. In the example, the // CFA is the value the stack pointer had upon entry to the @@ -941,7 +968,7 @@ class DwpReader { // reduces the size of the data by mentioning only the addresses and // columns at which changes take place. So for the above, DWARF CFI // data would only actually mention the following: -// +// // insn cfa r0 r1 ... ra // ======================================= // func+0: sp cfa[0] @@ -949,7 +976,7 @@ class DwpReader { // func+2: cfa[-4] // func+11: sp+20 // func+21: r0 -// func+22: sp +// func+22: sp // // In fact, this is the way the parser reports CFI to the consumer: as // a series of statements of the form, "At address X, column Y changed @@ -1067,7 +1094,7 @@ class CallFrameInfo { // handling are described here, rather poorly: // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html - // + // // 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 @@ -1100,7 +1127,7 @@ class CallFrameInfo { // The start of this entry in the buffer. const uint8_t* start; - + // Which kind of entry this is. // // We want to be able to use this for error reporting even while we're @@ -1134,13 +1161,13 @@ class CallFrameInfo { struct CIE: public Entry { uint8_t version; // CFI data version number string augmentation; // vendor format extension markers - uint64_t code_alignment_factor; // scale for code address adjustments + uint64_t code_alignment_factor; // scale for code address adjustments int data_alignment_factor; // scale for stack pointer adjustments unsigned return_address_register; // which register holds the return addr // True if this CIE includes Linux C++ ABI 'z' augmentation data. bool has_z_augmentation; - + // Parsed 'z' augmentation data. These are meaningful only if // has_z_augmentation is true. bool has_z_lsda; // The 'z' augmentation included 'L'. @@ -1194,7 +1221,7 @@ class CallFrameInfo { class ValExpressionRule; class RuleMap; class State; - + // Parse the initial length and id of a CFI entry, either a CIE, an FDE, // or a .eh_frame end-of-data mark. CURSOR points to the beginning of the // data to parse. On success, populate ENTRY as appropriate, and return @@ -1281,7 +1308,7 @@ class CallFrameInfo::Handler { // Immediately after a call to Entry, the handler should assume that // the rule for each callee-saves register is "unchanged" --- that // is, that the register still has the value it had in the caller. - // + // // If a *Rule function returns true, we continue processing this entry's // instructions. If a *Rule function returns false, we stop evaluating // instructions, and skip to the next entry. Either way, we call End @@ -1335,6 +1362,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. @@ -1467,13 +1497,13 @@ class CallFrameInfo::Reporter { // The instruction at INSN_OFFSET in the entry at OFFSET, of kind // KIND, establishes a rule that cites the CFA, but we have not // established a CFA rule yet. - virtual void NoCFARule(uint64_t offset, CallFrameInfo::EntryKind kind, + virtual void NoCFARule(uint64_t offset, CallFrameInfo::EntryKind kind, uint64_t insn_offset); // The instruction at INSN_OFFSET in the entry at OFFSET, of kind // KIND, is a DW_CFA_restore_state instruction, but the stack of // saved states is empty. - virtual void EmptyStateStack(uint64_t offset, CallFrameInfo::EntryKind kind, + virtual void EmptyStateStack(uint64_t offset, CallFrameInfo::EntryKind kind, uint64_t insn_offset); // The DW_CFA_remember_state instruction at INSN_OFFSET in the entry @@ -1481,7 +1511,7 @@ class CallFrameInfo::Reporter { // rule, whereas the current state does have a CFA rule. This is // bogus input, which the CallFrameInfo::Handler interface doesn't // (and shouldn't) have any way to report. - virtual void ClearingCFARule(uint64_t offset, CallFrameInfo::EntryKind kind, + virtual void ClearingCFARule(uint64_t offset, CallFrameInfo::EntryKind kind, uint64_t insn_offset); protected: @@ -1492,6 +1522,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 8e5d68b4c..ce92f1698 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,8 +28,13 @@ // Original author: Jim Blandy -// dwarf2reader_cfi_unittest.cc: Unit tests for dwarf2reader::CallFrameInfo +// dwarf2reader_cfi_unittest.cc: Unit tests for google_breakpad::CallFrameInfo +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include #include #include @@ -72,11 +76,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; @@ -114,6 +118,7 @@ class MockCallFrameInfoHandler: public CallFrameInfo::Handler { MOCK_METHOD3(ValExpressionRule, bool(uint64_t address, int reg, 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()); @@ -306,7 +311,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); @@ -763,7 +768,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 +793,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 { @@ -823,10 +828,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 +849,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 +871,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 +891,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 +911,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 +932,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 +952,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 +969,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 +990,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 +1007,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 +1024,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 +1040,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 +1063,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 +1079,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 +1094,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 +1108,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 +1122,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 +1137,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 +1152,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 +1175,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 +1191,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 +1212,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 +1226,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 +1243,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 +1270,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 +1326,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 +1376,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 +1438,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 +1501,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 +1524,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 +1541,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 +1568,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 +1585,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 +1606,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 +1659,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 +1677,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 +1694,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 +1717,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 +1734,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 +1757,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 +1775,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 +1800,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 +1826,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 +1844,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 +1869,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 +1895,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 +1912,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 +1936,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 +1961,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 +1978,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 +2002,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 +2028,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 +2046,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 +2073,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 +2117,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 { @@ -2142,11 +2149,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 +2179,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 +2194,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 +2235,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 +2264,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 +2283,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 +2313,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 +2342,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) diff --git a/src/common/dwarf/dwarf2reader_die_unittest.cc b/src/common/dwarf/dwarf2reader_die_unittest.cc index 3ff26f85e..2eb663370 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,8 +28,13 @@ // Original author: Jim Blandy -// dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit +// dwarf2reader_die_unittest.cc: Unit tests for google_breakpad::CompilationUnit +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include #include #include @@ -51,16 +55,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; @@ -168,9 +172,9 @@ 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(); @@ -178,7 +182,7 @@ TEST_P(DwarfHeader, Header) { info.set_endianness(GetParam().endianness); info.Header(GetParam().version, abbrev_table, GetParam().address_size, - dwarf2reader::DW_UT_compile) + 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 @@ -191,10 +195,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(_)) @@ -210,9 +214,9 @@ TEST_P(DwarfHeader, Header) { TEST_P(DwarfHeader, TypeUnitHeader) { Label abbrev_table = abbrevs.Here(); int version = 5; - abbrevs.Abbrev(1, dwarf2reader::DW_TAG_type_unit, - dwarf2reader::DW_children_yes) - .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string) + 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(); @@ -220,7 +224,7 @@ TEST_P(DwarfHeader, TypeUnitHeader) { info.set_endianness(GetParam().endianness); info.Header(version, abbrev_table, GetParam().address_size, - dwarf2reader::DW_UT_type) + 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 @@ -234,10 +238,10 @@ TEST_P(DwarfHeader, TypeUnitHeader) { version)) .WillOnce(Return(true)); // If the type unit is handled properly, these calls will be skipped. - EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_type_unit)) + EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_type_unit)) .Times(0); - 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")) .Times(0); EXPECT_CALL(handler, EndDIE(_)) @@ -291,7 +295,7 @@ struct DwarfFormsFixture: public DIEFixture { 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(); @@ -300,7 +304,7 @@ struct DwarfFormsFixture: public DIEFixture { info.set_format_size(params.format_size); info.set_endianness(params.endianness); info.Header(params.version, abbrev_table, params.address_size, - dwarf2reader::DW_UT_compile) + google_breakpad::DW_UT_compile) .ULEB128(1); // abbrev code } @@ -330,7 +334,8 @@ struct DwarfFormsFixture: public DIEFixture { uint64_t offset=0) { ByteReader byte_reader(params.endianness == kLittleEndian ? ENDIANNESS_LITTLE : ENDIANNESS_BIG); - CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader, &handler); + CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader, + &handler); EXPECT_EQ(offset + parser.Start(), info_contents.size()); } @@ -342,9 +347,9 @@ struct DwarfForms: public DwarfFormsFixture, public TestWithParam { }; 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; @@ -355,9 +360,9 @@ 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()); @@ -371,19 +376,19 @@ TEST_P(DwarfForms, strx1) { return; } Label abbrev_table = abbrevs.Here(); - abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit, - dwarf2reader::DW_children_no) - .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_strx1) - .Attribute(dwarf2reader::DW_AT_low_pc, dwarf2reader::DW_FORM_addr) - .Attribute(dwarf2reader::DW_AT_str_offsets_base, - dwarf2reader::DW_FORM_sec_offset) + 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, - dwarf2reader::DW_UT_compile) + google_breakpad::DW_UT_compile) .ULEB128(1) // abbrev index .D8(2); // string index @@ -435,13 +440,13 @@ TEST_P(DwarfForms, strx1) { } - ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit); - EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strx1, + 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(_, dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, + EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr, value)) .InSequence(s) .WillOnce(Return()); @@ -453,13 +458,13 @@ TEST_P(DwarfForms, strx1) { 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()); @@ -471,7 +476,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)) @@ -480,7 +485,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()); @@ -492,14 +497,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()); @@ -511,7 +516,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; @@ -524,7 +529,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()); @@ -536,14 +541,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()); @@ -555,13 +560,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()); @@ -579,13 +584,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()); @@ -599,23 +604,23 @@ TEST_P(DwarfForms, implicit_const) { const uint64_t implicit_constant_value = 0x1234; // Create the abbreviation table. Label abbrev_table = abbrevs.Here(); - abbrevs.Abbrev(1, (DwarfTag) 0x253e7b2b, dwarf2reader::DW_children_no) + abbrevs.Abbrev(1, (DwarfTag) 0x253e7b2b, google_breakpad::DW_children_no) .Attribute((DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_implicit_const) + 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, - dwarf2reader::DW_UT_compile) + google_breakpad::DW_UT_compile) .ULEB128(1); // abbrev code info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b); EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_implicit_const, + google_breakpad::DW_FORM_implicit_const, implicit_constant_value)) .InSequence(s) .WillOnce(Return()); @@ -653,15 +658,15 @@ INSTANTIATE_TEST_SUITE_P( DwarfHeaderParams(kBigEndian, 8, 4, 4, 1), DwarfHeaderParams(kBigEndian, 8, 4, 8, 1))); -class MockRangeListHandler: public dwarf2reader::RangeListHandler { +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 dwarf2reader::RangeListReader; - using dwarf2reader::DW_FORM_sec_offset; + using google_breakpad::RangeListReader; + using google_breakpad::DW_FORM_sec_offset; // Create a dwarf4 .debug_ranges section. google_breakpad::test_assembler::Section ranges(kBigEndian); @@ -688,7 +693,7 @@ TEST(RangeList, Dwarf4ReadRangeList) { cu_info.size_ = section_contents.size(); MockRangeListHandler handler; - dwarf2reader::RangeListReader range_list_reader(&byte_reader, &cu_info, + google_breakpad::RangeListReader range_list_reader(&byte_reader, &cu_info, &handler); EXPECT_CALL(handler, AddRange(2, 3)); EXPECT_CALL(handler, AddRange(4, 5)); @@ -698,20 +703,23 @@ TEST(RangeList, Dwarf4ReadRangeList) { section_offset)); } -TEST(RangeList, Dwarf5ReadRangeList) { - using dwarf2reader::RangeListReader; - using dwarf2reader::DW_RLE_base_addressx; - using dwarf2reader::DW_RLE_startx_endx; - using dwarf2reader::DW_RLE_startx_length; - using dwarf2reader::DW_RLE_offset_pair; - using dwarf2reader::DW_RLE_end_of_list; - using dwarf2reader::DW_RLE_base_address; - using dwarf2reader::DW_RLE_offset_pair; - using dwarf2reader::DW_RLE_start_end; - using dwarf2reader::DW_RLE_start_length; - using dwarf2reader::DW_RLE_end_of_list; - using dwarf2reader::DW_FORM_sec_offset; - using dwarf2reader::DW_FORM_rnglistx; +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; @@ -722,49 +730,83 @@ TEST(RangeList, Dwarf5ReadRangeList) { assert(addr.GetContents(&addr_contents)); // .debug_rnglists is the dwarf 5 section. - Section rnglists; - rnglists.set_endianness(kBigEndian); - std::string padding_offset = "padding offset"; - rnglists.Append(padding_offset); - const uint64_t ranges_base = rnglists.Size(); - - // Header - Label section_size; - rnglists.Append(kBigEndian, 4, section_size); - rnglists.D16(5); // Version - rnglists.D8(4); // Address size - rnglists.D8(0); // Segment selector size - rnglists.D32(2); // Offset entry count + 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; - rnglists.Append(kBigEndian, 4, range0); + rnglists1.Append(kBigEndian, 4, range0); Label range1; - rnglists.Append(kBigEndian, 4, range1); + rnglists1.Append(kBigEndian, 4, range1); - // Range 0 (will be read via DW_AT_ranges, DW_FORM_sec_offset). - range0 = rnglists.Size(); - rnglists.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 - rnglists.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // (2, 3) - rnglists.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // (4, 5) - rnglists.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // (6, 7) - rnglists.D8(DW_RLE_end_of_list); + // 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 = rnglists.Size(); - rnglists.D8(DW_RLE_base_address).D32(8); // base_addr = 8 - rnglists.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // (9, 10) - rnglists.D8(DW_RLE_start_end).D32(10).D32(11); // (10, 11) - rnglists.D8(DW_RLE_start_length).D32(12).ULEB128(1); // (12, 13) - rnglists.D8(DW_RLE_end_of_list); - section_size = rnglists.Size(); - std::string rnglists_contents; - assert(rnglists.GetContents(&rnglists_contents)); + 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; - // Only set the fields that matter for dwarf 4. cu_info.version_ = 5; cu_info.base_address_ = 1; - cu_info.ranges_base_ = ranges_base; + cu_info.ranges_base_ = ranges_base_1; cu_info.buffer_ = reinterpret_cast(rnglists_contents.data()); cu_info.size_ = rnglists_contents.size(); @@ -772,12 +814,13 @@ TEST(RangeList, Dwarf5ReadRangeList) { reinterpret_cast(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; - dwarf2reader::RangeListReader range_list_reader(&byte_reader, &cu_info, - &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)); @@ -785,9 +828,142 @@ TEST(RangeList, Dwarf5ReadRangeList) { EXPECT_CALL(handler, AddRange(10, 11)); EXPECT_CALL(handler, AddRange(12, 13)); EXPECT_CALL(handler, Finish()).Times(2); - EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_rnglistx, 1)); - EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, - range0.Value())); + 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(rnglists_contents.data()); + cu_info.size_ = rnglists_contents.size(); + cu_info.addr_buffer_ = + reinterpret_cast(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_rnglistx, 2)); + 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 index 37df73a16..7de627d3c 100644 --- a/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc +++ b/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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,11 @@ // Original author: Sterling Augustine -// dwarf2reader_lineinfo_unittest.cc: Unit tests for dwarf2reader::LineInfo +// dwarf2reader_lineinfo_unittest.cc: Unit tests for google_breakpad::LineInfo + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif #include #include @@ -49,7 +52,7 @@ using testing::Sequence; using testing::Test; using testing::_; -using namespace dwarf2reader; +using namespace google_breakpad; namespace { diff --git a/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc b/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc index 8c93e2759..12b27e686 100644 --- a/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc +++ b/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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,10 @@ // information generated when with splitting optimizations such as // -fsplit-machine-functions (clang) -freorder-blocks-and-partition (gcc). +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -44,7 +47,7 @@ #include "google_breakpad/common/breakpad_types.h" using testing::_; -using namespace dwarf2reader; +using namespace google_breakpad; namespace { diff --git a/src/common/dwarf/dwarf2reader_test_common.h b/src/common/dwarf/dwarf2reader_test_common.h index 5076cb6cd..1c45d527a 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 @@ -87,7 +86,7 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section { D8(header_type); // DW_UT_compile, DW_UT_type, etc. D8(address_size); SectionOffset(abbrev_offset); - if (header_type == dwarf2reader::DW_UT_type) { + if (header_type == google_breakpad::DW_UT_type) { uint64_t dummy_type_signature = 0xdeadbeef; uint64_t dummy_type_offset = 0x2b; D64(dummy_type_signature); @@ -122,10 +121,10 @@ 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|, diff --git a/src/common/dwarf/elf_reader.cc b/src/common/dwarf/elf_reader.cc index bbfdba680..7669895b9 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) // @@ -30,6 +30,10 @@ #define _GNU_SOURCE // needed for pread() #endif +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -41,6 +45,7 @@ #include #include #include +#include #include // TODO(saugustine): Add support for compressed debug. // Also need to add configure tests for zlib. @@ -106,9 +111,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 ElfReaderImpl; @@ -182,10 +193,10 @@ class Elf64 { template class ElfSectionReader { public: - ElfSectionReader(const char* name, const string& path, int fd, + ElfSectionReader(const char* cname, const string& path, int fd, const typename ElfArch::Shdr& section_header) - : contents_aligned_(NULL), - contents_(NULL), + : contents_aligned_(nullptr), + contents_(nullptr), header_(section_header) { // Back up to the beginning of the page we're interested in. const size_t additional = header_.sh_offset % getpagesize(); @@ -196,21 +207,32 @@ class ElfSectionReader { // to process its contents. if (header_.sh_type == SHT_NOBITS || header_.sh_size == 0) return; - contents_aligned_ = mmap(NULL, size_aligned_, PROT_READ, MAP_SHARED, + // 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(nullptr, size_aligned_, PROT_READ, MAP_SHARED, fd, offset_aligned); // Set where the offset really should begin. contents_ = reinterpret_cast(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". } ~ElfSectionReader() { - if (contents_aligned_ != NULL) + if (contents_aligned_ != nullptr) munmap(contents_aligned_, size_aligned_); else delete[] contents_; @@ -252,14 +274,14 @@ class SymbolIterator { SymbolIterator(ElfReaderImpl* reader, typename ElfArch::Word section_type) : symbol_section_(reader->GetSectionByType(section_type)), - string_section_(NULL), + string_section_(nullptr), num_symbols_in_section_(0), symbol_within_section_(0) { // If this section type doesn't exist, leave // num_symbols_in_section_ as zero, so this iterator is already // done(). - if (symbol_section_ != NULL) { + if (symbol_section_ != nullptr) { num_symbols_in_section_ = symbol_section_->header().sh_size / symbol_section_->header().sh_entsize; @@ -291,7 +313,7 @@ class SymbolIterator { const char* GetSymbolName() const { int name_offset = GetSymbol()->st_name; if (name_offset == 0) - return NULL; + return nullptr; return string_section_->GetOffset(name_offset); } @@ -329,9 +351,9 @@ class ElfReaderImpl { explicit ElfReaderImpl(const string& path, int fd) : path_(path), fd_(fd), - section_headers_(NULL), - program_headers_(NULL), - opd_section_(NULL), + section_headers_(nullptr), + program_headers_(nullptr), + opd_section_(nullptr), base_for_text_(0), plts_supported_(false), plt_code_size_(0), @@ -347,8 +369,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; @@ -387,17 +409,17 @@ class ElfReaderImpl { 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"; + if (error != nullptr) *error = "Could not read header"; return false; } if (memcmp(header, ELFMAG, SELFMAG) != 0) { - if (error != NULL) *error = "Missing ELF magic"; + if (error != nullptr) *error = "Missing ELF magic"; return false; } if (header[EI_CLASS] != ElfArch::kElfClass) { - if (error != NULL) *error = "Different word size"; + if (error != nullptr) *error = "Different word size"; return false; } @@ -407,7 +429,7 @@ class ElfReaderImpl { else if (header[EI_DATA] == ELFDATA2MSB) endian = __BIG_ENDIAN; if (endian != __BYTE_ORDER) { - if (error != NULL) *error = "Different byte order"; + if (error != nullptr) *error = "Different byte order"; return false; } @@ -454,7 +476,7 @@ class ElfReaderImpl { for (SymbolIterator it(this, section_type); !it.done(); it.Next()) { const char* name = it.GetSymbolName(); - if (name == NULL) + if (name == nullptr) continue; const typename ElfArch::Sym* sym = it.GetSymbol(); if (CanUseSymbol(name, sym)) { @@ -698,7 +720,7 @@ class ElfReaderImpl { return GetSection(k); } } - return NULL; + return nullptr; } // Return the name of section "shndx". Returns NULL if the section @@ -711,11 +733,11 @@ class ElfReaderImpl { // "size". Returns NULL if the section is not found. const char* GetSectionContentsByIndex(int shndx, size_t* size) { const ElfSectionReader* section = GetSection(shndx); - if (section != NULL) { + if (section != nullptr) { *size = section->section_size(); return section->contents(); } - return NULL; + return nullptr; } // Return a pointer to the first section of the given name by @@ -729,17 +751,17 @@ class ElfReaderImpl { // table, so reverse the direction of iteration. int shndx = is_dwp_ ? GetNumSections() - k - 1 : k; const char* name = GetSectionName(section_headers_[shndx].sh_name); - if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) { + if (name != nullptr && ElfReader::SectionNamesMatch(section_name, name)) { const ElfSectionReader* section = GetSection(shndx); - if (section == NULL) { - return NULL; + if (section == nullptr) { + return nullptr; } else { *size = section->section_size(); return section->contents(); } } } - return NULL; + return nullptr; } // This is like GetSectionContentsByName() but it returns a lot of extra @@ -752,10 +774,10 @@ class ElfReaderImpl { // table, so reverse the direction of iteration. int shndx = is_dwp_ ? GetNumSections() - k - 1 : k; const char* name = GetSectionName(section_headers_[shndx].sh_name); - if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) { + if (name != nullptr && ElfReader::SectionNamesMatch(section_name, name)) { const ElfSectionReader* section = GetSection(shndx); - if (section == NULL) { - return NULL; + if (section == nullptr) { + return nullptr; } else { info->type = section->header().sh_type; info->flags = section->header().sh_flags; @@ -770,7 +792,7 @@ class ElfReaderImpl { } } } - return NULL; + return nullptr; } // p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD @@ -797,9 +819,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; } @@ -857,10 +881,10 @@ class ElfReaderImpl { const char* GetSectionName(typename ElfArch::Word sh_name) { const ElfSectionReader* shstrtab = GetSection(GetStringTableIndex()); - if (shstrtab != NULL) { + if (shstrtab != nullptr) { return shstrtab->GetOffset(sh_name); } - return NULL; + return nullptr; } // Return an ElfSectionReader for the given section. The reader will @@ -874,10 +898,10 @@ class ElfReaderImpl { else name = GetSectionNameByIndex(num); ElfSectionReader*& reader = sections_[num]; - if (reader == NULL) + if (reader == nullptr) reader = new ElfSectionReader(name, path_, fd_, section_headers_[num]); - return reader; + return reader->contents() ? reader : nullptr; } // Parse out the overall header information from the file and assert @@ -929,14 +953,14 @@ class ElfReaderImpl { program_headers_ = new typename ElfArch::Phdr[GetNumProgramHeaders()]; // Presize the sections array for efficiency. - sections_.resize(GetNumSections(), NULL); + sections_.resize(GetNumSections(), nullptr); return true; } // Given the "value" of a function descriptor return the address of the // function (i.e. the dereferenced value). Otherwise return "value". uint64_t AdjustPPC64FunctionDescriptorSymbolValue(uint64_t value) { - if (opd_section_ != NULL && + if (opd_section_ != nullptr && opd_info_.addr <= value && value < opd_info_.addr + opd_info_.size) { uint64_t offset = value - opd_info_.addr; @@ -1027,7 +1051,7 @@ class ElfReaderImpl { }; ElfReader::ElfReader(const string& path) - : path_(path), fd_(-1), impl32_(NULL), impl64_(NULL) { + : path_(path), fd_(-1), impl32_(nullptr), impl64_(nullptr) { // linux 2.6.XX kernel can show deleted files like this: // /var/run/nscd/dbYLJYaE (deleted) // and the kernel-supplied vdso and vsyscall mappings like this: @@ -1046,9 +1070,9 @@ ElfReader::ElfReader(const string& path) ElfReader::~ElfReader() { if (fd_ != -1) close(fd_); - if (impl32_ != NULL) + if (impl32_ != nullptr) delete impl32_; - if (impl64_ != NULL) + if (impl64_ != nullptr) delete impl64_; } @@ -1066,7 +1090,7 @@ template static bool IsElfFile(const int fd, const string& path) { if (fd < 0) return false; - if (!ElfReaderImpl::IsArchElfFile(fd, NULL)) { + if (!ElfReaderImpl::IsArchElfFile(fd, nullptr)) { // No error message here. IsElfFile gets called many times. return false; } @@ -1149,13 +1173,14 @@ uint64_t ElfReader::VaddrOfFirstLoadSegment() { } const char* ElfReader::GetSectionName(int shndx) { - if (shndx < 0 || static_cast(shndx) >= GetNumSections()) return NULL; + if (shndx < 0 || static_cast(shndx) >= GetNumSections()) + return nullptr; if (IsElf32File()) { return GetImpl32()->GetSectionNameByIndex(shndx); } else if (IsElf64File()) { return GetImpl64()->GetSectionNameByIndex(shndx); } else { - return NULL; + return nullptr; } } @@ -1175,7 +1200,7 @@ const char* ElfReader::GetSectionByIndex(int shndx, size_t* size) { } else if (IsElf64File()) { return GetImpl64()->GetSectionContentsByIndex(shndx, size); } else { - return NULL; + return nullptr; } } @@ -1186,7 +1211,7 @@ const char* ElfReader::GetSectionByName(const string& section_name, } else if (IsElf64File()) { return GetImpl64()->GetSectionContentsByName(section_name, size); } else { - return NULL; + return nullptr; } } @@ -1197,15 +1222,19 @@ const char* ElfReader::GetSectionInfoByName(const string& section_name, } else if (IsElf64File()) { return GetImpl64()->GetSectionInfoByName(section_name, info); } else { - return NULL; + return nullptr; } } -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; } @@ -1221,14 +1250,14 @@ bool ElfReader::IsDynamicSharedObject() { } ElfReaderImpl* ElfReader::GetImpl32() { - if (impl32_ == NULL) { + if (impl32_ == nullptr) { impl32_ = new ElfReaderImpl(path_, fd_); } return impl32_; } ElfReaderImpl* ElfReader::GetImpl64() { - if (impl64_ == NULL) { + if (impl64_ == nullptr) { impl64_ = new ElfReaderImpl(path_, fd_); } return impl64_; @@ -1240,11 +1269,11 @@ ElfReaderImpl* ElfReader::GetImpl64() { template static bool IsNonStrippedELFBinaryImpl(const string& path, const int fd, bool debug_only) { - if (!ElfReaderImpl::IsArchElfFile(fd, NULL)) return false; + if (!ElfReaderImpl::IsArchElfFile(fd, nullptr)) return false; ElfReaderImpl elf_reader(path, fd); return debug_only ? elf_reader.HasDebugSections() - : (elf_reader.GetSectionByType(SHT_SYMTAB) != NULL); + : (elf_reader.GetSectionByType(SHT_SYMTAB) != nullptr); } // Helper for the IsNon[Debug]StrippedELFBinary functions. @@ -1271,4 +1300,4 @@ bool ElfReader::IsNonStrippedELFBinary(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 0aa922855..a6dec7555 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 +#include #include #include "common/dwarf/types.h" @@ -24,7 +25,7 @@ using std::vector; using std::pair; -namespace dwarf2reader { +namespace google_breakpad { class SymbolMap; class Elf32; @@ -145,7 +146,8 @@ class ElfReader { // 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. @@ -162,6 +164,6 @@ class ElfReader { ElfReaderImpl* 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 6b9a92a3f..39c24c8cb 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. // @@ -29,22 +29,24 @@ // This is a client for the dwarf2reader to extract function and line // information from the debug info. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include #include +#include #include #include #include "common/dwarf/functioninfo.h" #include "common/dwarf/bytereader.h" -#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* files, std::vector* dirs, @@ -162,7 +164,7 @@ void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64_t offset, GetSectionByName(sections_, ".debug_line"); assert(iter != sections_.end()); - scoped_ptr lireader(new LineInfo(iter->second.first + data, + std::unique_ptr lireader(new LineInfo(iter->second.first + data, iter->second.second - data, reader_, linehandler_)); lireader->Start(); @@ -227,4 +229,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 5c733c6d5..4139564cf 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 @@ -124,7 +124,7 @@ class CUFunctionInfoHandler: public Dwarf2Handler { offset_to_funcinfo_(offset_to_funcinfo), address_to_funcinfo_(address_to_funcinfo), linehandler_(linehandler), sections_(sections), - reader_(reader), current_function_info_(NULL) { } + reader_(reader), current_function_info_(nullptr) { } virtual ~CUFunctionInfoHandler() { } @@ -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 fc301c763..1797e3bc5 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 + +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 23412d0ea..b14d7a3ee 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 eb19c1326..c6325bd78 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,15 @@ // Implementation of google_breakpad::DwarfCFIToModule. // See dwarf_cfi_to_module.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + +#include #include +#include #include "common/dwarf_cfi_to_module.h" @@ -142,17 +149,40 @@ vector DwarfCFIToModule::RegisterNames::MIPS() { sizeof(kRegisterNames) / sizeof(kRegisterNames[0])); } +vector DwarfCFIToModule::RegisterNames::RISCV() { + static const char *const names[] = { + "pc", "ra", "sp", "gp", "tp", "t0", "t1", "t2", + "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", + "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" + }; + + return MakeVector(names, sizeof(names) / sizeof(names[0])); +} + bool DwarfCFIToModule::Entry(size_t offset, uint64_t address, uint64_t length, 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(); entry_->address = address; entry_->size = length; entry_offset_ = offset; @@ -184,9 +214,7 @@ 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, @@ -261,11 +289,14 @@ bool DwarfCFIToModule::ValExpressionRule(uint64_t address, int reg, } 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," diff --git a/src/common/dwarf_cfi_to_module.h b/src/common/dwarf_cfi_to_module.h index 35bdb5fd5..19297db93 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 #include +#include #include #include "common/module.h" @@ -52,7 +52,6 @@ namespace google_breakpad { -using dwarf2reader::CallFrameInfo; using google_breakpad::Module; using std::set; using std::vector; @@ -115,13 +114,16 @@ class DwarfCFIToModule: public CallFrameInfo::Handler { // MIPS. static vector MIPS(); + // RISC-V. + static vector RISCV(); + private: // Given STRINGS, an array of C strings with SIZE elements, return an // equivalent vector. static vector 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 @@ -133,9 +135,9 @@ class DwarfCFIToModule: public CallFrameInfo::Handler { DwarfCFIToModule(Module* module, const vector& 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, @@ -153,6 +155,8 @@ class DwarfCFIToModule: public CallFrameInfo::Handler { const string& expression); virtual bool End(); + virtual string Architecture(); + private: // Return the name to use for register REG. string RegisterName(int i); @@ -170,7 +174,7 @@ class DwarfCFIToModule: public CallFrameInfo::Handler { Reporter* reporter_; // The current entry we're constructing. - Module::StackFrameEntry* entry_; + std::unique_ptr 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 58c3cca3a..52653ec6e 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. // @@ -31,6 +30,10 @@ // dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -304,3 +307,15 @@ TEST(RegisterNames, X86_64) { EXPECT_EQ("$rsp", names[7]); EXPECT_EQ("$rip", names[16]); } + +TEST(RegisterNames, RISCV) { + vector names = DwarfCFIToModule::RegisterNames::RISCV(); + + EXPECT_EQ("pc", names[0]); + EXPECT_EQ("t6", names[31]); + EXPECT_EQ("f0", names[32]); + EXPECT_EQ("f31", names[63]); + EXPECT_EQ("v0", names[96]); + EXPECT_EQ("v31", names[127]); +} + diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc index 95e793578..c58181d71 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. // @@ -36,6 +35,10 @@ #define __STDC_FORMAT_MACROS #endif /* __STDC_FORMAT_MACROS */ +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/dwarf_cu_to_module.h" #include @@ -44,11 +47,12 @@ #include #include +#include #include #include +#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 +62,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 +83,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 AbstractOriginByOffset; @@ -101,31 +105,16 @@ typedef map 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, 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 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 forward_ref_die_to_func; }; DwarfCUToModule::FileContext::FileContext(const string& filename, @@ -138,6 +127,10 @@ DwarfCUToModule::FileContext::FileContext(const string& filename, } DwarfCUToModule::FileContext::~FileContext() { + for (std::vector::iterator i = uncompressed_sections_.begin(); + i != uncompressed_sections_.end(); ++i) { + delete[] *i; + } } void DwarfCUToModule::FileContext::AddSectionToSectionMap( @@ -145,11 +138,17 @@ void DwarfCUToModule::FileContext::AddSectionToSectionMap( 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,19 +169,23 @@ 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) + CUContext(FileContext* file_context_arg, + WarningReporter* reporter_arg, + RangesHandler* ranges_handler_arg, + uint64_t low_pc, + uint64_t addr_base) : version(0), file_context(file_context_arg), reporter(reporter_arg), ranges_handler(ranges_handler_arg), language(Language::CPlusPlus), - low_pc(0), + low_pc(low_pc), high_pc(0), - ranges_form(dwarf2reader::DW_FORM_sec_offset), + ranges_form(DW_FORM_sec_offset), ranges_data(0), ranges_base(0), - str_offsets_base(0) { } + addr_base(addr_base), + str_offsets_base(0) {} ~CUContext() { for (vector::iterator it = functions.begin(); @@ -214,7 +217,7 @@ struct DwarfCUToModule::CUContext { uint64_t high_pc; // Ranges for this CU are read according to this form. - enum dwarf2reader::DwarfForm ranges_form; + enum DwarfForm ranges_form; uint64_t ranges_data; // Offset into .debug_rngslists where this CU's ranges are stored. @@ -231,24 +234,24 @@ struct DwarfCUToModule::CUContext { // Collect all the data from the CU that a RangeListReader needs to read a // range. bool AssembleRangeListInfo( - dwarf2reader::RangeListReader::CURangesInfo* info) { - const dwarf2reader::SectionMap& section_map + 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"); - dwarf2reader::SectionMap::const_iterator map_entry - = dwarf2reader::GetSectionByName(section_map, section_name); + 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) { - dwarf2reader::SectionMap::const_iterator map_entry - = dwarf2reader::GetSectionByName(section_map, ".debug_addr"); + SectionMap::const_iterator map_entry + = GetSectionByName(section_map, ".debug_addr"); if (map_entry == section_map.end()) { return false; } @@ -266,9 +269,8 @@ struct DwarfCUToModule::CUContext { // Destroying this destroys all the functions this vector points to. vector 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 forward_ref_die_to_func; + // A map of function pointers to the its forward specification DIE's offset. + map spec_function_offsets; }; // Information about the context of a particular DIE. This is for @@ -285,11 +287,11 @@ 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 @@ -300,8 +302,10 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler { parent_context_(parent_context), offset_(offset), declaration_(false), - specification_(NULL), - forward_ref_die_offset_(0) { } + specification_(nullptr), + no_specification(false), + abstract_origin_(nullptr), + 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. @@ -330,20 +334,15 @@ 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(); + // + // On return, if has_qualified_name is non-NULL, *has_qualified_name is set to + // true if the DIE includes a fully-qualified name, false otherwise. + StringView ComputeQualifiedName(bool* has_qualified_name); 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_; @@ -353,23 +352,35 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler { // Otherwise, this is NULL. 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( @@ -377,7 +388,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; } } @@ -387,7 +398,7 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference( enum DwarfForm form, uint64_t data) { switch (attr) { - case dwarf2reader::DW_AT_specification: { + case DW_AT_specification: { FileContext* file_context = cu_context_->file_context; if (file_context->IsUnhandledInterCUReference( data, cu_context_->reporter->cu_offset())) { @@ -407,44 +418,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::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) { 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 case Language::kDontDemangle: - demangled_name_.clear(); - raw_name_ = AddStringToPool(data); + demangled_name_ = StringView(); + raw_name_ = cu_context_->file_context->module_->AddStringToPool(data); break; } break; @@ -453,11 +473,12 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString( } } -string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { +StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName( + bool* has_qualified_name) { // 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_; @@ -466,37 +487,52 @@ 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) { + if (has_qualified_name) { + // dSYMs built with -gmlt do not include the DW_AT_linkage_name + // with the unmangled symbol, but rather include it in the + // LC_SYMTAB STABS, which end up in the externs of the module. + // + // Remember this so the Module can copy over the extern name later. + *has_qualified_name = false; + } + // 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; + } + } else { + if (has_qualified_name) { + *has_qualified_name = true; + } } // 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 @@ -513,18 +549,256 @@ 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& 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_lexical_block DIEs. +class DwarfCUToModule::LexicalBlockHandler : public GenericDIEHandler { + public: + LexicalBlockHandler(CUContext* cu_context, + uint64_t offset, + int inline_nest_level, + vector>& inlines) + : GenericDIEHandler(cu_context, nullptr, offset), + inline_nest_level_(inline_nest_level), + inlines_(inlines) {} + + DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag); + bool EndAttributes() { return true; } + void Finish(); + + private: + 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>& inlines_; + // A vector of child inlines. + vector> child_inlines_; +}; + +// 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>& 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), + has_range_data_(false), + 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_; + bool has_range_data_; + // 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>& inlines_; + // A vector of child inlines. + vector> 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: + has_range_data_ = true; + 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_); + case DW_TAG_lexical_block: + return new LexicalBlockHandler(cu_context_, offset, + inline_nest_level_ + 1, child_inlines_); + default: + return nullptr; + } } +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(""); + } + return true; +} + +void DwarfCUToModule::InlineHandler::Finish() { + vector ranges; + + if (!has_range_data_) { + 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); + + Module::InlineOriginMap& inline_origin_map = + cu_context_->file_context->module_ + ->inline_origin_maps[cu_context_->file_context->filename_]; + inline_origin_map.SetReference(specification_offset_, specification_offset_); + Module::InlineOrigin* origin = + inline_origin_map.GetOrCreateInlineOrigin(specification_offset_, name_); + unique_ptr 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)); +} + +DIEHandler* DwarfCUToModule::LexicalBlockHandler::FindChildHandler( + uint64_t offset, + enum DwarfTag tag) { + switch (tag) { + case DW_TAG_inlined_subroutine: + return new InlineHandler(cu_context_, nullptr, offset, inline_nest_level_, + child_inlines_); + case DW_TAG_lexical_block: + return new LexicalBlockHandler(cu_context_, offset, inline_nest_level_, + child_inlines_); + default: + return nullptr; + } +} + +void DwarfCUToModule::LexicalBlockHandler::Finish() { + // Insert child inlines inside the lexical block into the inline vector from + // parent as if the block does not exit. + inlines_.insert(inlines_.end(), + std::make_move_iterator(child_inlines_.begin()), + std::make_move_iterator(child_inlines_.end())); +} + +// 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_form_(dwarf2reader::DW_FORM_sec_offset), ranges_data_(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), + has_qualified_name_(false), + has_range_data_(false) {} void ProcessAttributeUnsigned(enum DwarfAttribute attr, enum DwarfForm form, @@ -532,23 +806,24 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { 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. DwarfForm ranges_form_; // DW_FORM_sec_offset or DW_FORM_rnglistx - uint64_t ranges_data_; // DW_AT_ranges - const AbstractOrigin* abstract_origin_; + uint64_t ranges_data_; // DW_AT_ranges bool inline_; + vector> child_inlines_; + bool handle_inline_; + bool has_qualified_name_; + bool has_range_data_; + DIEContext child_context_; // A context for our children. }; void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( @@ -559,18 +834,18 @@ 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: + case DW_AT_ranges: + has_range_data_ = true; ranges_data_ = data; ranges_form_ = form; break; - default: GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data); break; @@ -585,56 +860,47 @@ 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_); + case DW_TAG_lexical_block: + if (handle_inline_) + return new LexicalBlockHandler(cu_context_, offset, 0, child_inlines_); default: - GenericDIEHandler::ProcessAttributeReference(attr, form, data); - break; + return nullptr; } } bool DwarfCUToModule::FuncHandler::EndAttributes() { // Compute our name, and record a specification, if appropriate. - name_ = ComputeQualifiedName(); + name_ = ComputeQualifiedName(&has_qualified_name_); 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& 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 ranges; @@ -642,20 +908,23 @@ 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_data_) { + if (!has_range_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 && - high_pc_form_ != dwarf2reader::DW_FORM_addrx && - high_pc_form_ != dwarf2reader::DW_FORM_addrx1 && - high_pc_form_ != dwarf2reader::DW_FORM_addrx2 && - high_pc_form_ != dwarf2reader::DW_FORM_addrx3 && - high_pc_form_ != dwarf2reader::DW_FORM_addrx4) { + 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_; } @@ -664,7 +933,7 @@ void DwarfCUToModule::FuncHandler::Finish() { } else { RangesHandler* ranges_handler = cu_context_->ranges_handler; if (ranges_handler) { - dwarf2reader::RangeListReader::CURangesInfo cu_info; + RangeListReader::CURangesInfo cu_info; if (cu_context_->AssembleRangeListInfo(&cu_info)) { if (!ranges_handler->ReadRanges(ranges_form_, ranges_data_, &cu_info, &ranges)) { @@ -677,85 +946,83 @@ void DwarfCUToModule::FuncHandler::Finish() { } } + StringView name_omitted = + cu_context_->file_context->module_->AddStringToPool(""); + 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 = ""; - } - + 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 func(new Module::Function(name, low_pc_)); + std::unique_ptr func(new Module::Function(name, low_pc_)); func->ranges = ranges; func->parameter_size = 0; + // If the name was unqualified, prefer the Extern name if there's a mismatch + // (the Extern name will be fully-qualified in that case). + func->prefer_extern_name = !has_qualified_name_; if (func->address) { // If the function address is zero this is a sign that this function // 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_; + Module::InlineOriginMap& inline_origin_map = + cu_context_->file_context->module_ + ->inline_origin_maps[cu_context_->file_context->filename_]; + inline_origin_map.SetReference(offset_, offset); + inline_origin_map.GetOrCreateInlineOrigin(offset_, name); + } +} bool DwarfCUToModule::NamedScopeHandler::EndAttributes() { - child_context_.name = ComputeQualifiedName(); + child_context_.name = ComputeQualifiedName(nullptr); + 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; + return nullptr; } } @@ -814,7 +1081,7 @@ void DwarfCUToModule::WarningReporter::UncoveredFunction( 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) { @@ -863,12 +1130,22 @@ void DwarfCUToModule::WarningReporter::MissingRanges() { DwarfCUToModule::DwarfCUToModule(FileContext* file_context, LineToModuleHandler* line_reader, RangesHandler* ranges_handler, - WarningReporter* reporter) - : line_reader_(line_reader), - cu_context_(new CUContext(file_context, reporter, ranges_handler)), + WarningReporter* reporter, + bool handle_inline, + uint64_t low_pc, + uint64_t addr_base, + bool has_source_line_info, + uint64_t source_line_offset) + : RootDIEHandler(handle_inline), + line_reader_(line_reader), + cu_context_(new CUContext(file_context, + reporter, + ranges_handler, + low_pc, + addr_base)), child_context_(new DIEContext()), - has_source_line_info_(false) { -} + has_source_line_info_(has_source_line_info), + source_line_offset_(source_line_offset) {} DwarfCUToModule::~DwarfCUToModule() { } @@ -877,7 +1154,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(data)); break; default: @@ -889,34 +1166,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(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: + case DW_AT_ranges: cu_context_->ranges_data = data; cu_context_->ranges_form = form; break; - case dwarf2reader::DW_AT_rnglists_base: + case DW_AT_rnglists_base: cu_context_->ranges_base = data; break; - case dwarf2reader::DW_AT_addr_base: - case dwarf2reader::DW_AT_GNU_addr_base: + case DW_AT_addr_base: + case DW_AT_GNU_addr_base: cu_context_->addr_base = data; break; - case dwarf2reader::DW_AT_str_offsets_base: + case DW_AT_str_offsets_base: cu_context_->str_offsets_base = data; break; - default: break; } @@ -924,12 +1200,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: @@ -941,41 +1217,42 @@ 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; + return nullptr; } } 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; @@ -991,22 +1268,22 @@ 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& section_map + const SectionMap& section_map = cu_context_->file_context->section_map(); - dwarf2reader::SectionMap::const_iterator map_entry - = dwarf2reader::GetSectionByName(section_map, ".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; @@ -1022,14 +1299,14 @@ void DwarfCUToModule::ReadSourceLines(uint64_t offset) { // 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 = dwarf2reader::GetSectionByName(section_map, ".debug_str"); + 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 = dwarf2reader::GetSectionByName(section_map, ".debug_line_str"); + 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; @@ -1038,7 +1315,7 @@ void DwarfCUToModule::ReadSourceLines(uint64_t offset) { 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_); + cu_context_->file_context->module_, &lines_, &files_); } namespace { @@ -1117,12 +1394,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 = nullptr; // 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 = nullptr; + const Module::Line* last_line_cited = nullptr; // Prepare a sorted list of ranges with range-to-function mapping vector sorted_ranges; @@ -1148,12 +1425,12 @@ void DwarfCUToModule::AssignLinesToFunctions() { line = &*line_it; current = std::min(range->address, line->address); } else if (line_it != lines_.end()) { - range = NULL; + range = nullptr; line = &*line_it; current = line->address; } else if (range_it != sorted_ranges.end()) { range = &*range_it; - line = NULL; + line = nullptr; current = range->address; } else { return; @@ -1284,12 +1561,12 @@ void DwarfCUToModule::AssignLinesToFunctions() { && next_transition >= range_it->address && !within(*range_it, next_transition)) range_it++; - range = (range_it != sorted_ranges.end()) ? &(*range_it) : NULL; + range = (range_it != sorted_ranges.end()) ? &(*range_it) : nullptr; while (line_it != lines_.end() && next_transition >= line_it->address && !within(*line_it, next_transition)) line_it++; - line = (line_it != lines_.end()) ? &*line_it : NULL; + line = (line_it != lines_.end()) ? &*line_it : nullptr; // We must make progress. assert(next_transition > current); @@ -1297,6 +1574,16 @@ void DwarfCUToModule::AssignLinesToFunctions() { } } +void DwarfCUToModule::AssignFilesToInlines() { + // Assign File* to Inlines inside this CU. + auto assignFile = [this](unique_ptr& 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 @@ -1315,10 +1602,18 @@ void DwarfCUToModule::Finish() { // 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. @@ -1339,8 +1634,8 @@ bool DwarfCUToModule::StartCompilationUnit(uint64_t offset, 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 - || tag == dwarf2reader::DW_TAG_skeleton_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 386d62817..90adde1ca 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. // @@ -41,30 +40,26 @@ #include +#include #include +#include #include "common/language.h" #include "common/module.h" #include "common/dwarf/dwarf2diehandler.h" #include "common/dwarf/dwarf2reader.h" -#include "common/scoped_ptr.h" #include "common/using_std_string.h" 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, @@ -88,10 +83,14 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { 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; @@ -110,7 +109,7 @@ 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_; @@ -119,7 +118,8 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { const bool handle_inter_cu_refs_; // Inter-compilation unit data used internally by the handlers. - scoped_ptr file_private_; + std::unique_ptr file_private_; + std::vector uncompressed_sections_; }; // An abstract base class for handlers that handle DWARF range lists for @@ -132,14 +132,14 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { // Called when finishing a function to populate the function's ranges. // The entries are read according to the form and data. virtual bool ReadRanges( - enum dwarf2reader::DwarfForm form, uint64_t data, - dwarf2reader::RangeListReader::CURangesInfo* cu_info, + enum DwarfForm form, uint64_t data, + RangeListReader::CURangesInfo* cu_info, vector* 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: @@ -161,7 +161,8 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { uint64_t string_section_length, const uint8_t* line_string_section, uint64_t line_string_length, - Module* module, vector* lines) = 0; + Module* module, vector* lines, + map* files) = 0; }; // The interface DwarfCUToModule uses to report warnings. The member @@ -253,16 +254,78 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { void UncoveredHeading(); }; + class NullWarningReporter : public WarningReporter { + public: + NullWarningReporter(const string& filename, uint64_t cu_offset) + : WarningReporter(filename, cu_offset) {} + + // Set the name of the compilation unit we're processing to NAME. + void SetCUName(const string& name) {} + + // Accessor and setter for uncovered_warnings_enabled_. + // UncoveredFunction and UncoveredLine only report a problem if that is + // true. By default, these warnings are disabled, because those + // conditions occur occasionally in healthy code. + void set_uncovered_warnings_enabled(bool value) {} + + // A DW_AT_specification in the DIE at OFFSET refers to a DIE we + // haven't processed yet, or that wasn't marked as a declaration, + // at TARGET. + void UnknownSpecification(uint64_t offset, uint64_t target) {} + + // A DW_AT_abstract_origin in the DIE at OFFSET refers to a DIE we + // haven't processed yet, or that wasn't marked as inline, at TARGET. + void UnknownAbstractOrigin(uint64_t offset, uint64_t target) {} + + // We were unable to find the DWARF section named SECTION_NAME. + void MissingSection(const string& section_name) {} + + // The CU's DW_AT_stmt_list offset OFFSET is bogus. + void BadLineInfoOffset(uint64_t offset) {} + + // FUNCTION includes code covered by no line number data. + void UncoveredFunction(const Module::Function& function) {} + + // Line number NUMBER in LINE_FILE, of length LENGTH, includes code + // covered by no function. + 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 + // link. + void UnnamedFunction(uint64_t offset) {} + + // __cxa_demangle() failed to demangle INPUT. + 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. + void UnhandledInterCUReference(uint64_t offset, uint64_t target) {} + + // The DW_AT_ranges at offset is malformed (truncated or outside of the + // .debug_ranges section's bound). + void MalformedRangeList(uint64_t offset) {} + + // A DW_AT_ranges attribute was encountered but the no .debug_ranges + // section was found. + void MissingRanges() {} + }; + // 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); + WarningReporter* reporter, + bool handle_inline = false, + uint64_t low_pc = 0, + uint64_t addr_base = 0, + bool has_source_line_info = false, + uint64_t source_line_offset = 0); ~DwarfCUToModule(); void ProcessAttributeSigned(enum DwarfAttribute attr, @@ -294,6 +357,8 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { struct Specification; class GenericDIEHandler; class FuncHandler; + class LexicalBlockHandler; + class InlineHandler; class NamedScopeHandler; // A map from section offsets to specifications. @@ -314,6 +379,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 @@ -324,10 +391,10 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { LineToModuleHandler* line_reader_; // This compilation unit's context. - scoped_ptr cu_context_; + std::unique_ptr cu_context_; // A context for our children. - scoped_ptr child_context_; + std::unique_ptr child_context_; // True if this compilation unit has source line information. bool has_source_line_info_; @@ -340,6 +407,9 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { // during parsing. Then, in Finish, we call AssignLinesToFunctions // to dole them out to the appropriate functions. vector lines_; + + // The map from file index to File* in this CU. + std::map 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 cd037ad99..d073c87a0 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. // @@ -31,6 +30,10 @@ // dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -44,12 +47,11 @@ 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; @@ -68,12 +70,13 @@ using ::testing::ValuesIn; class MockLineToModuleHandler: public DwarfCUToModule::LineToModuleHandler { public: MOCK_METHOD1(StartCompilationUnit, void(const string& compilation_dir)); - MOCK_METHOD8(ReadProgram, void(const uint8_t* program, uint64_t length, + 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* lines)); + Module* module, vector* lines, + std::map* files)); }; class MockWarningReporter: public DwarfCUToModule::WarningReporter { @@ -123,7 +126,8 @@ class CUFixtureBase { uint64_t string_section_length, const uint8_t* line_string_section, uint64_t line_string_section_length, - Module *module, vector* lines) { + Module *module, vector* lines, + std::map* files) { lines->insert(lines->end(), lines_->begin(), lines_->end()); } private: @@ -133,7 +137,7 @@ class CUFixtureBase { 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), @@ -156,7 +160,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. @@ -175,7 +179,7 @@ class CUFixtureBase { // 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; } @@ -191,7 +195,7 @@ 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 @@ -205,7 +209,8 @@ class CUFixtureBase { // 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); + uint64_t specification, + const char* name = nullptr); // 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 @@ -215,7 +220,7 @@ class CUFixtureBase { 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 @@ -240,7 +245,7 @@ class CUFixtureBase { void AbstractInstanceDIE(DIEHandler* parent, uint64_t offset, DwarfInline type, uint64_t specification, const string& name, - DwarfForm form = dwarf2reader::DW_FORM_data1); + 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 @@ -263,6 +268,10 @@ class CUFixtureBase { void TestFunction(int i, const string& name, Module::Address address, Module::Address size); + // Test that the I'th function (ordered by address) in the module + // this.module_ has the given prefer_extern_name. + void TestFunctionPreferExternName(int i, bool prefer_extern_name); + // Test that the number of source lines owned by the I'th function // in the module this.module_ is equal to EXPECTED. void TestLineCount(int i, size_t expected); @@ -279,7 +288,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. @@ -342,7 +351,7 @@ void CUFixtureBase::StartCU() { 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_ @@ -350,34 +359,34 @@ void CUFixtureBase::StartCU() { 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); @@ -399,18 +408,18 @@ void CUFixtureBase::ProcessStrangeAttributes( DIEHandler* CUFixtureBase::StartNamedDIE(DIEHandler* parent, DwarfTag tag, const string& name) { - dwarf2reader::DIEHandler* handler + google_breakpad::DIEHandler* handler = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag); if (!handler) - return NULL; - handler->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, + return nullptr; + handler->ProcessAttributeString(google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strp, name); ProcessStrangeAttributes(handler); if (!handler->EndAttributes()) { handler->Finish(); delete handler; - return NULL; + return nullptr; } return handler; @@ -420,53 +429,53 @@ DIEHandler* CUFixtureBase::StartSpecifiedDIE(DIEHandler* parent, DwarfTag tag, uint64_t specification, const char* name) { - dwarf2reader::DIEHandler* handler + google_breakpad::DIEHandler* handler = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag); if (!handler) - return NULL; + return nullptr; 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(); delete handler; - return NULL; + return nullptr; } return handler; } -void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler* parent, +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); - ASSERT_TRUE(func != NULL); - func->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, + google_breakpad::DW_TAG_subprogram); + ASSERT_TRUE(func != nullptr); + 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); @@ -479,19 +488,19 @@ void CUFixtureBase::DeclarationDIE(DIEHandler* parent, uint64_t offset, DwarfTag tag, const string& name, const string& mangled_name) { - dwarf2reader::DIEHandler* die = parent->FindChildHandler(offset, tag); - ASSERT_TRUE(die != NULL); + google_breakpad::DIEHandler* die = parent->FindChildHandler(offset, tag); + ASSERT_TRUE(die != nullptr); 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(); @@ -504,22 +513,22 @@ void CUFixtureBase::DefinitionDIE(DIEHandler* parent, 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, + ASSERT_TRUE(die != nullptr); + 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()); @@ -533,21 +542,21 @@ void CUFixtureBase::AbstractInstanceDIE(DIEHandler* parent, uint64_t specification, const string& name, DwarfForm form) { - dwarf2reader::DIEHandler* die - = parent->FindChildHandler(offset, dwarf2reader::DW_TAG_subprogram); - ASSERT_TRUE(die != NULL); + google_breakpad::DIEHandler* die + = parent->FindChildHandler(offset, google_breakpad::DW_TAG_subprogram); + ASSERT_TRUE(die != nullptr); 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()); @@ -560,23 +569,23 @@ void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler* parent, uint64_t origin, Module::Address address, Module::Address size) { - dwarf2reader::DIEHandler* func + google_breakpad::DIEHandler* func = parent->FindChildHandler(0x11c70f94c6e87ccdLL, - dwarf2reader::DW_TAG_subprogram); - ASSERT_TRUE(func != NULL); + google_breakpad::DW_TAG_subprogram); + ASSERT_TRUE(func != nullptr); 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()); @@ -611,6 +620,15 @@ void CUFixtureBase::TestFunction(int i, const string& name, EXPECT_EQ(0U, function->parameter_size); } +void CUFixtureBase::TestFunctionPreferExternName(int i, + bool prefer_extern_name) { + FillFunctions(); + ASSERT_LT((size_t)i, functions_.size()); + + Module::Function* function = functions_[i]; + EXPECT_EQ(prefer_extern_name, function->prefer_extern_name); +} + void CUFixtureBase::TestLineCount(int i, size_t expected) { FillFunctions(); ASSERT_LT((size_t) i, functions_.size()); @@ -664,7 +682,7 @@ TEST_F(SimpleCU, OneFunc) { StartCU(); DefineFunction(&root_handler_, "function1", - 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL); + 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, nullptr); root_handler_.Finish(); TestFunctionCount(1); @@ -680,8 +698,8 @@ TEST_F(SimpleCU, OneFuncHighPcIsLength) { StartCU(); DefineFunction6(&root_handler_, "function1", - 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL, - dwarf2reader::DW_FORM_udata); + 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, nullptr, + google_breakpad::DW_FORM_udata); root_handler_.Finish(); TestFunctionCount(1); @@ -707,17 +725,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"); - EXPECT_TRUE(class_A_handler != NULL); + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "class_A"); + EXPECT_TRUE(class_A_handler != nullptr); EXPECT_FALSE(class_A_handler ->FindChildHandler(0x02e55999b865e4e9ULL, - dwarf2reader::DW_TAG_lexical_block)); + google_breakpad::DW_TAG_lexical_block)); delete class_A_handler; } @@ -735,7 +753,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(); @@ -750,8 +768,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(); @@ -769,7 +787,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(); @@ -780,14 +798,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(); @@ -798,13 +813,11 @@ TEST_F(SimpleCU, UnknownAbstractOrigin) { } TEST_F(SimpleCU, UnnamedFunction) { - EXPECT_CALL(reporter_, UnnamedFunction(0xe34797c7e68590a8LL)) - .WillOnce(Return()); PushLine(0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, "line-file", 14044850); StartCU(); DefineFunction(&root_handler_, "", - 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, NULL); + 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, nullptr); root_handler_.Finish(); TestFunctionCount(1); @@ -881,10 +894,10 @@ TEST_P(FuncLinePairing, Pairing) { StartCU(); DefineFunction(&root_handler_, "function1", s.functions[0].start, - s.functions[0].end - s.functions[0].start, NULL); + s.functions[0].end - s.functions[0].start, nullptr); DefineFunction(&root_handler_, "function2", s.functions[1].start, - s.functions[1].end - s.functions[1].start, NULL); + s.functions[1].end - s.functions[1].start, nullptr); root_handler_.Finish(); TestFunctionCount(2); @@ -928,7 +941,7 @@ TEST_F(FuncLinePairing, FuncsNoLines) { StartCU(); DefineFunction(&root_handler_, "function1", 0x127da12ffcf5c51fULL, 0x1000U, - NULL); + nullptr); root_handler_.Finish(); TestFunctionCount(1); @@ -940,8 +953,8 @@ TEST_F(FuncLinePairing, GapThenFunction) { PushLine(10, 2, "line-file-1", 263008005); StartCU(); - DefineFunction(&root_handler_, "function1", 10, 2, NULL); - DefineFunction(&root_handler_, "function2", 20, 2, NULL); + DefineFunction(&root_handler_, "function1", 10, 2, nullptr); + DefineFunction(&root_handler_, "function2", 20, 2, nullptr); root_handler_.Finish(); TestFunctionCount(2); @@ -966,10 +979,10 @@ TEST_F(FuncLinePairing, GCCAlignmentStretch) { PushLine(20, 10, "line-file", 61661044); StartCU(); - DefineFunction(&root_handler_, "function1", 10, 5, NULL); + DefineFunction(&root_handler_, "function1", 10, 5, nullptr); // five-byte gap between functions, covered by line 63351048. // This should not elicit a warning. - DefineFunction(&root_handler_, "function2", 20, 10, NULL); + DefineFunction(&root_handler_, "function2", 20, 10, nullptr); root_handler_.Finish(); TestFunctionCount(2); @@ -990,8 +1003,10 @@ TEST_F(FuncLinePairing, LineAtEndOfAddressSpace) { EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); StartCU(); - DefineFunction(&root_handler_, "function1", 0xfffffffffffffff0ULL, 6, NULL); - DefineFunction(&root_handler_, "function2", 0xfffffffffffffffaULL, 5, NULL); + DefineFunction(&root_handler_, "function1", 0xfffffffffffffff0ULL, 6, + nullptr); + DefineFunction(&root_handler_, "function2", 0xfffffffffffffffaULL, 5, + nullptr); root_handler_.Finish(); TestFunctionCount(2); @@ -1011,7 +1026,7 @@ TEST_F(FuncLinePairing, WarnOnceFunc) { EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); StartCU(); - DefineFunction(&root_handler_, "function", 10, 11, NULL); + DefineFunction(&root_handler_, "function", 10, 11, nullptr); root_handler_.Finish(); TestFunctionCount(1); @@ -1028,8 +1043,8 @@ TEST_F(FuncLinePairing, WarnOnceLine) { EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); StartCU(); - DefineFunction(&root_handler_, "function1", 11, 1, NULL); - DefineFunction(&root_handler_, "function2", 13, 1, NULL); + DefineFunction(&root_handler_, "function1", 11, 1, nullptr); + DefineFunction(&root_handler_, "function2", 13, 1, nullptr); root_handler_.Finish(); TestFunctionCount(2); @@ -1045,24 +1060,24 @@ class CXXQualifiedNames: public CUFixtureBase, public TestWithParam { }; INSTANTIATE_TEST_SUITE_P(VersusEnclosures, CXXQualifiedNames, - Values(dwarf2reader::DW_TAG_class_type, - dwarf2reader::DW_TAG_structure_type, - dwarf2reader::DW_TAG_union_type, - dwarf2reader::DW_TAG_namespace)); + 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, "Enclosure"); - EXPECT_TRUE(enclosure_handler != NULL); - DefineFunction(enclosure_handler, "func_B", 10, 1, NULL); - DefineFunction(enclosure_handler, "func_C", 20, 1, NULL); + EXPECT_TRUE(enclosure_handler != nullptr); + DefineFunction(enclosure_handler, "func_B", 10, 1, nullptr); + DefineFunction(enclosure_handler, "func_C", 20, 1, nullptr); enclosure_handler->Finish(); delete enclosure_handler; root_handler_.Finish(); @@ -1075,18 +1090,18 @@ 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, + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace, "Namespace"); - EXPECT_TRUE(namespace_handler != NULL); + EXPECT_TRUE(namespace_handler != nullptr); DIEHandler* enclosure_handler = StartNamedDIE(namespace_handler, tag, "Enclosure"); - EXPECT_TRUE(enclosure_handler != NULL); - DefineFunction(enclosure_handler, "function", 10, 1, NULL); + EXPECT_TRUE(enclosure_handler != nullptr); + DefineFunction(enclosure_handler, "function", 10, 1, nullptr); enclosure_handler->Finish(); delete enclosure_handler; namespace_handler->Finish(); @@ -1098,22 +1113,22 @@ 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, + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace, "namespace_A"); - EXPECT_TRUE(namespace_handler != NULL); + EXPECT_TRUE(namespace_handler != nullptr); DIEHandler* struct_handler - = StartNamedDIE(namespace_handler, dwarf2reader::DW_TAG_structure_type, + = StartNamedDIE(namespace_handler, google_breakpad::DW_TAG_structure_type, "struct_B"); - EXPECT_TRUE(struct_handler != NULL); + EXPECT_TRUE(struct_handler != nullptr); DIEHandler* class_handler - = StartNamedDIE(struct_handler, dwarf2reader::DW_TAG_class_type, + = StartNamedDIE(struct_handler, google_breakpad::DW_TAG_class_type, "class_C"); - DefineFunction(class_handler, "function_D", 10, 1, NULL); + DefineFunction(class_handler, "function_D", 10, 1, nullptr); class_handler->Finish(); delete class_handler; struct_handler->Finish(); @@ -1127,19 +1142,19 @@ TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) { } struct LanguageAndQualifiedName { - dwarf2reader::DwarfLanguage language; + 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, nullptr } }; class QualifiedForLanguage @@ -1157,9 +1172,9 @@ TEST_P(QualifiedForLanguage, MemberFunction) { StartCU(); DIEHandler* class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "class_A"); - DefineFunction(class_handler, "function_B", 10, 1, NULL); + DefineFunction(class_handler, "function_B", 10, 1, nullptr); class_handler->Finish(); delete class_handler; root_handler_.Finish(); @@ -1181,9 +1196,9 @@ TEST_P(QualifiedForLanguage, MemberFunctionSignedLanguage) { StartCU(); DIEHandler* class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "class_A"); - DefineFunction(class_handler, "function_B", 10, 1, NULL); + DefineFunction(class_handler, "function_B", 10, 1, nullptr); class_handler->Finish(); delete class_handler; root_handler_.Finish(); @@ -1203,8 +1218,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(); @@ -1220,9 +1235,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(); @@ -1234,14 +1249,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(); @@ -1252,27 +1267,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 @@ -1284,12 +1299,12 @@ TEST_F(Specifications, MemberFunction) { StartCU(); DIEHandler* class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); + = 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(); @@ -1307,16 +1322,16 @@ TEST_F(Specifications, FunctionDeclarationParent) { StartCU(); { DIEHandler* class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "class_A"); - ASSERT_TRUE(class_handler != NULL); + ASSERT_TRUE(class_handler != nullptr); 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); @@ -1335,11 +1350,11 @@ TEST_F(Specifications, NamedScopeDeclarationParent) { StartCU(); { DIEHandler* space_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace, "space_A"); - ASSERT_TRUE(space_handler != NULL); + ASSERT_TRUE(space_handler != nullptr); 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; @@ -1347,11 +1362,11 @@ TEST_F(Specifications, NamedScopeDeclarationParent) { { DIEHandler* class_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, 0x419bb1d12f9a73a2ULL, "class-definition-name"); - ASSERT_TRUE(class_handler != NULL); + ASSERT_TRUE(class_handler != nullptr); DefineFunction(class_handler, "function", - 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, NULL); + 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, nullptr); class_handler->Finish(); delete class_handler; } @@ -1369,9 +1384,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(); @@ -1388,11 +1403,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); + ASSERT_TRUE(space_handler != nullptr); 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(); @@ -1409,7 +1424,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: @@ -1439,23 +1454,23 @@ TEST_F(Specifications, LongChain) { // class_G::class_H::func_I { DIEHandler* space_A_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + = 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, + = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_namespace, 0x2e111126496596e2ULL); DIEHandler* struct_C_handler - = StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type, + = 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(); @@ -1464,13 +1479,13 @@ TEST_F(Specifications, LongChain) { { DIEHandler* struct_D_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_structure_type, + = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_structure_type, 0x20cd423bf2a25a4cULL); DIEHandler* union_E_handler - = StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type, + = 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(); @@ -1479,13 +1494,13 @@ TEST_F(Specifications, LongChain) { { DIEHandler* union_F_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_union_type, + = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_union_type, 0xe25c84805aa58c32ULL); DIEHandler* class_G_handler - = StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type, + = 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(); @@ -1494,15 +1509,15 @@ TEST_F(Specifications, LongChain) { { DIEHandler* class_H_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + = 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(); @@ -1518,7 +1533,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"); @@ -1528,11 +1543,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(); } @@ -1541,13 +1556,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, + = 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(); @@ -1558,9 +1573,9 @@ 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(); @@ -1569,7 +1584,7 @@ TEST_F(Specifications, InterCU) { vector 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) { @@ -1577,7 +1592,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"); @@ -1587,11 +1602,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(); } @@ -1600,14 +1615,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, + = 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(); @@ -1618,11 +1633,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(); @@ -1631,13 +1645,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(); @@ -1648,8 +1660,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(); @@ -1664,19 +1676,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); @@ -1697,20 +1709,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(); @@ -1732,12 +1744,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(); @@ -1789,7 +1801,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 fe808c086..940ab2d69 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. // @@ -32,6 +31,10 @@ // dwarf_line_to_module.cc: Implementation of DwarfLineToModule class. // See dwarf_line_to_module.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -100,7 +103,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 +125,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 f80f1b070..c93a9bf50 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,16 +119,19 @@ 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* lines) + DwarfLineToModule(Module* module, + const string& compilation_dir, + vector* lines, + std::map* 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); @@ -167,12 +169,12 @@ class DwarfLineToModule: public dwarf2reader::LineInfoHandler { 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 90b6570d8..9eb1469fa 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. // @@ -31,6 +30,10 @@ // dwarf_line_to_module.cc: Unit tests for google_breakpad::DwarfLineToModule. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "breakpad_googletest_includes.h" @@ -45,7 +48,8 @@ using google_breakpad::Module; TEST(SimpleModule, One) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineFile("file1", 0x30bf0f27, 0, 0, 0); h.AddLine(0x6fd126fbf74f2680LL, 0x63c9a14cf556712bLL, 0x30bf0f27, @@ -66,7 +70,8 @@ TEST(SimpleModule, One) { TEST(SimpleModule, Many) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("directory1", 0x838299ab); h.DefineDir("directory2", 0xf85de023); @@ -126,7 +131,8 @@ TEST(SimpleModule, Many) { TEST(Filenames, Absolute) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("directory1", 1); h.DefineFile("/absolute", 1, 1, 0, 0); @@ -144,7 +150,8 @@ TEST(Filenames, Absolute) { TEST(Filenames, Relative) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("directory1", 1); h.DefineFile("relative", 1, 1, 0, 0); @@ -162,7 +169,8 @@ TEST(Filenames, Relative) { TEST(Filenames, StrangeFile) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("directory1", 1); h.DefineFile("", 1, 1, 0, 0); @@ -175,7 +183,8 @@ TEST(Filenames, StrangeFile) { TEST(Filenames, StrangeDirectory) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("", 1); h.DefineFile("file1", 1, 1, 0, 0); @@ -188,7 +197,8 @@ TEST(Filenames, StrangeDirectory) { TEST(Filenames, StrangeDirectoryAndFile) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("", 1); h.DefineFile("", 1, 1, 0, 0); @@ -203,7 +213,8 @@ TEST(Filenames, StrangeDirectoryAndFile) { TEST(Filenames, DirectoryZeroFileIsRelativeToCompilationDir) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "src/build", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "src/build", &lines, &cu_files); h.DefineDir("Dir", 1); h.DefineFile("File", 1, 0, 0, 0); @@ -219,7 +230,8 @@ TEST(Filenames, DirectoryZeroFileIsRelativeToCompilationDir) { TEST(Filenames, IncludeDirectoryRelativeToDirectoryZero) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "src/build", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "src/build", &lines, &cu_files); h.DefineDir("Dir", 1); h.DefineFile("File", 1, 1, 0, 0); @@ -235,7 +247,8 @@ TEST(Filenames, IncludeDirectoryRelativeToDirectoryZero) { TEST(Filenames, IncludeDirectoryAbsolute) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "src/build", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "src/build", &lines, &cu_files); h.DefineDir("/Dir", 1); h.DefineFile("File", 1, 1, 0, 0); @@ -251,7 +264,8 @@ TEST(Filenames, IncludeDirectoryAbsolute) { TEST(ModuleErrors, DirectoryZero) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("directory0", 0); // should be ignored h.DefineFile("relative", 1, 0, 0, 0); @@ -267,7 +281,8 @@ TEST(ModuleErrors, DirectoryZero) { TEST(ModuleErrors, BadFileNumber) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map 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 +296,8 @@ TEST(ModuleErrors, BadFileNumber) { TEST(ModuleErrors, BadDirectoryNumber) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("directory1", 1); h.DefineFile("baddirnumber1", 1, 2, 0, 0); // bad directory number @@ -296,7 +312,8 @@ TEST(ModuleErrors, BadDirectoryNumber) { TEST(ModuleErrors, EmptyLine) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineFile("filename1", 1, 0, 0, 0); h.AddLine(1, 0, 1, 0, 0); @@ -309,7 +326,8 @@ TEST(ModuleErrors, EmptyLine) { TEST(ModuleErrors, BigLine) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineFile("filename1", 1, 0, 0, 0); h.AddLine(0xffffffffffffffffULL, 2, 1, 0, 0); @@ -326,7 +344,8 @@ TEST(ModuleErrors, BigLine) { TEST(Omitted, DroppedThenGood) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map 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 +358,8 @@ TEST(Omitted, DroppedThenGood) { TEST(Omitted, GoodThenDropped) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map 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 +372,8 @@ TEST(Omitted, GoodThenDropped) { TEST(Omitted, Mix1) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map 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 +394,8 @@ TEST(Omitted, Mix1) { TEST(Omitted, Mix2) { Module m("name", "os", "architecture", "id"); vector lines; - DwarfLineToModule h(&m, "/", &lines); + std::map 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 3fecb5645..c40a5c3bc 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. // @@ -33,6 +32,10 @@ // dwarf_range_list_handler.cc: Implementation of DwarfRangeListHandler class. // See dwarf_range_list_handler.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "common/dwarf_range_list_handler.h" diff --git a/src/common/dwarf_range_list_handler.h b/src/common/dwarf_range_list_handler.h index 5db5d1e96..cb1b8b1e3 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,7 +48,7 @@ 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(vector* ranges) : ranges_(ranges) { } diff --git a/src/common/language.cc b/src/common/language.cc index 381c8bd4f..a1d17adec 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. // @@ -32,16 +31,21 @@ // language.cc: Subclasses and singletons for google_breakpad::Language. // See language.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/language.h" #include +#include #if !defined(__ANDROID__) #include #endif -#if defined(HAVE_RUST_DEMANGLE) -#include +#if defined(HAVE_RUSTC_DEMANGLE) +#include #endif #include @@ -88,7 +92,7 @@ class CPPLanguage: public Language { int status; char* demangled_c = - abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status); + abi::__cxa_demangle(mangled.c_str(), nullptr, nullptr, &status); DemangleResult result; if (status == 0) { @@ -178,13 +182,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 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. diff --git a/src/common/language.h b/src/common/language.h index 892ea862e..9ce8f1a68 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. // diff --git a/src/common/linux/breakpad_getcontext.S b/src/common/linux/breakpad_getcontext.S index 528dba7a9..286047bf5 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. // @@ -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 @@ -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 1418cde62..d64784d46 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. // @@ -30,10 +29,6 @@ #ifndef GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H #define GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H -#ifdef HAVE_CONFIG_H -#include -#endif - #ifndef HAVE_GETCONTEXT #include diff --git a/src/common/linux/breakpad_getcontext_unittest.cc b/src/common/linux/breakpad_getcontext_unittest.cc index a57bfedf9..5b340eb74 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. // @@ -30,6 +29,10 @@ // asm/sigcontext.h can't be included with signal.h on glibc or // musl, so only compare _libc_fpstate and _fpstate on Android. #if defined(__ANDROID__) && defined(__x86_64__) +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #endif @@ -114,6 +117,25 @@ TEST(AndroidUContext, GRegsOffset) { ASSERT_EQ(static_cast(MCONTEXT_FPC_CSR), offsetof(ucontext_t,uc_mcontext.fpc_csr)); +#elif defined(__riscv) + ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.__gregs[0])); + +#define CHECK_REG(x) \ + ASSERT_EQ(static_cast(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(MCONTEXT_FPREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.__fpregs)); + + ASSERT_EQ(static_cast(MCONTEXT_FPC_CSR), + offsetof(ucontext_t,uc_mcontext.__fpregs.__fcsr)); #elif defined(__x86_64__) COMPILE_ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), diff --git a/src/common/linux/crc32.cc b/src/common/linux/crc32.cc index 8df636ce4..cf386a24c 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/crc32.h" namespace google_breakpad { diff --git a/src/common/linux/crc32.h b/src/common/linux/crc32.h index e3d9db92b..7df469992 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 0514f5a2c..f0680a959 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. // @@ -32,6 +31,10 @@ // dump_symbols.cc: implement google_breakpad::WriteSymbolFile: // Find all the debugging info in a file and dump it as a Breakpad symbol file. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/dump_symbols.h" #include @@ -47,8 +50,12 @@ #include #include #include +#include +#ifdef HAVE_LIBZSTD +#include +#endif -#include +#include #include #include #include @@ -87,17 +94,16 @@ 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 using google_breakpad::StabsToModule; #endif -using google_breakpad::scoped_ptr; using google_breakpad::wasteful_vector; // Define AARCH64 ELF architecture if host machine does not include this define. @@ -105,6 +111,11 @@ using google_breakpad::wasteful_vector; #define EM_AARCH64 183 #endif +// Define ZStd compression if host machine does not include this define. +#ifndef ELFCOMPRESS_ZSTD +#define ELFCOMPRESS_ZSTD 2 +#endif + // // FDWrapper // @@ -139,7 +150,7 @@ class MmapWrapper { public: MmapWrapper() : is_set_(false) {} ~MmapWrapper() { - if (is_set_ && base_ != NULL) { + if (is_set_ && base_ != nullptr) { assert(size_ > 0); munmap(base_, size_); } @@ -152,7 +163,7 @@ class MmapWrapper { void release() { assert(is_set_); is_set_ = false; - base_ = NULL; + base_ = nullptr; size_ = 0; } @@ -228,46 +239,49 @@ 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(dwarf2reader::ByteReader* reader) : + DumperRangesHandler(google_breakpad::ByteReader* reader) : reader_(reader) { } bool ReadRanges( - enum dwarf2reader::DwarfForm form, uint64_t data, - dwarf2reader::RangeListReader::CURangesInfo* cu_info, + enum google_breakpad::DwarfForm form, uint64_t data, + google_breakpad::RangeListReader::CURangesInfo* cu_info, vector* ranges) { DwarfRangeListHandler handler(ranges); - dwarf2reader::RangeListReader range_list_reader(reader_, cu_info, + google_breakpad::RangeListReader range_list_reader(reader_, cu_info, &handler); return range_list_reader.ReadRanges(form, data); } private: - 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, + 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* lines) { - DwarfLineToModule handler(module, compilation_dir_, lines); - dwarf2reader::LineInfo parser(program, length, byte_reader_, + Module* module, + std::vector* lines, + std::map* 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, @@ -276,20 +290,140 @@ class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler { } private: string compilation_dir_; - dwarf2reader::ByteReader* byte_reader_; + google_breakpad::ByteReader* byte_reader_; }; +template +bool IsCompressedHeader(const typename ElfClass::Shdr* section) { + return (section->sh_flags & SHF_COMPRESSED) != 0; +} + +template +uint32_t GetCompressionHeader( + typename ElfClass::Chdr& compression_header, + const uint8_t* content, uint64_t size) { + const typename ElfClass::Chdr* header = + reinterpret_cast(content); + + if (size < sizeof (*header)) { + return 0; + } + + compression_header = *header; + return sizeof (*header); +} + +std::pair UncompressZlibSectionContents( + const uint8_t* compressed_buffer, uint64_t compressed_size, uint64_t uncompressed_size) { + google_breakpad::scoped_array uncompressed_buffer( + new uint8_t[uncompressed_size]); + + uLongf size = static_cast(uncompressed_size); + + int status = uncompress( + uncompressed_buffer.get(), &size, compressed_buffer, compressed_size); + + return status != Z_OK + ? std::make_pair(nullptr, 0) + : std::make_pair(uncompressed_buffer.release(), uncompressed_size); +} + +#ifdef HAVE_LIBZSTD +std::pair UncompressZstdSectionContents( + const uint8_t* compressed_buffer, uint64_t compressed_size,uint64_t uncompressed_size) { + + google_breakpad::scoped_array uncompressed_buffer(new uint8_t[uncompressed_size]); + size_t out_size = ZSTD_decompress(uncompressed_buffer.get(), uncompressed_size, + compressed_buffer, compressed_size); + if (ZSTD_isError(out_size)) { + return std::make_pair(nullptr, 0); + } + assert(out_size == uncompressed_size); + return std::make_pair(uncompressed_buffer.release(), uncompressed_size); +} +#endif + +std::pair UncompressSectionContents( + uint64_t compression_type, const uint8_t* compressed_buffer, + uint64_t compressed_size, uint64_t uncompressed_size) { + if (compression_type == ELFCOMPRESS_ZLIB) { + return UncompressZlibSectionContents(compressed_buffer, compressed_size, uncompressed_size); + } + +#ifdef HAVE_LIBZSTD + if (compression_type == ELFCOMPRESS_ZSTD) { + return UncompressZstdSectionContents(compressed_buffer, compressed_size, uncompressed_size); + } +#endif + + return std::make_pair(nullptr, 0); +} + +void StartProcessSplitDwarf(google_breakpad::CompilationUnit* reader, + Module* module, + google_breakpad::Endianness endianness, + bool handle_inter_cu_refs, + bool handle_inline) { + std::string split_file; + google_breakpad::SectionMap split_sections; + google_breakpad::ByteReader split_byte_reader(endianness); + uint64_t cu_offset = 0; + if (!reader->ProcessSplitDwarf(split_file, split_sections, split_byte_reader, + cu_offset)) + return; + DwarfCUToModule::FileContext file_context(split_file, module, + handle_inter_cu_refs); + for (auto section : split_sections) + file_context.AddSectionToSectionMap(section.first, section.second.first, + section.second.second); + // Because DWP/DWO file doesn't have .debug_addr/.debug_line/.debug_line_str, + // its debug info will refer to .debug_addr/.debug_line in the main binary. + if (file_context.section_map().find(".debug_addr") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_addr", reader->GetAddrBuffer(), + reader->GetAddrBufferLen()); + if (file_context.section_map().find(".debug_line") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line", reader->GetLineBuffer(), + reader->GetLineBufferLen()); + if (file_context.section_map().find(".debug_line_str") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line_str", + reader->GetLineStrBuffer(), + reader->GetLineStrBufferLen()); + + DumperRangesHandler ranges_handler(&split_byte_reader); + DumperLineToModule line_to_module(&split_byte_reader); + DwarfCUToModule::WarningReporter reporter(split_file, cu_offset); + DwarfCUToModule root_handler( + &file_context, &line_to_module, &ranges_handler, &reporter, handle_inline, + reader->GetLowPC(), reader->GetAddrBase(), reader->HasSourceLineInfo(), + reader->GetSourceLineOffset()); + google_breakpad::DIEDispatcher die_dispatcher(&root_handler); + google_breakpad::CompilationUnit split_reader( + split_file, file_context.section_map(), cu_offset, &split_byte_reader, + &die_dispatcher); + split_reader.SetSplitDwarf(reader->GetAddrBase(), reader->GetDWOID()); + split_reader.Start(); + // Normally, it won't happen unless we have transitive reference. + if (split_reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&split_reader, module, endianness, + handle_inter_cu_refs, handle_inline); + } +} + template 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, @@ -308,7 +442,31 @@ bool LoadDwarf(const string& dwarf_filename, section->sh_name; const uint8_t* contents = GetOffset(elf_header, section->sh_offset); - file_context.AddSectionToSectionMap(name, contents, section->sh_size); + uint64_t size = section->sh_size; + + if (!IsCompressedHeader(section)) { + file_context.AddSectionToSectionMap(name, contents, size); + continue; + } + + typename ElfClass::Chdr chdr; + + uint32_t compression_header_size = + GetCompressionHeader(chdr, contents, size); + + if (compression_header_size == 0 || chdr.ch_size == 0) { + continue; + } + + contents += compression_header_size; + size -= compression_header_size; + + std::pair uncompressed = + UncompressSectionContents(chdr.ch_type, 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 @@ -316,7 +474,7 @@ bool LoadDwarf(const string& dwarf_filename, // 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& debug_info_section = @@ -330,17 +488,26 @@ 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, &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, &die_dispatcher); // Process the entire compilation unit; get the offset of the next. - offset += reader.Start(); + uint64_t result = reader.Start(); + if (result == 0) { + return false; + } + offset += result; + // Start to process split dwarf file. + if (reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&reader, module, endianness, handle_inter_cu_refs, + handle_inline); + } } return true; } @@ -369,6 +536,9 @@ bool DwarfCFIRegisterNames(const typename ElfClass::Ehdr* elf_header, case EM_X86_64: *register_names = DwarfCFIToModule::RegisterNames::X86_64(); return true; + case EM_RISCV: + *register_names = DwarfCFIToModule::RegisterNames::RISCV(); + return true; default: return false; } @@ -394,8 +564,8 @@ 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 = @@ -405,7 +575,7 @@ bool LoadDwarfCFI(const string& dwarf_filename, // 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); @@ -417,11 +587,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(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(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 uncompressed = + UncompressSectionContents(chdr.ch_type, 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; } @@ -441,7 +644,7 @@ bool LoadELF(const string& obj_file, MmapWrapper* map_wrapper, obj_file.c_str(), strerror(errno)); return false; } - void* obj_base = mmap(NULL, st.st_size, + void* obj_base = mmap(nullptr, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, obj_fd, 0); if (obj_base == MAP_FAILED) { fprintf(stderr, "Failed to mmap ELF file '%s': %s\n", @@ -530,9 +733,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]); @@ -623,7 +826,7 @@ class LoadSymbolsInfo { string debuglink_file() const { return debuglink_file_; } - void set_debuglink_file(string file) { + void set_debuglink_file(const string& file) { debuglink_file_ = file; } @@ -679,8 +882,10 @@ bool LoadSymbols(const string& obj_file, const char* names_end = names + section_names->sh_size; bool found_debug_info_section = false; bool found_usable_info = false; + bool usable_info_parsed = 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 = @@ -693,8 +898,10 @@ bool LoadSymbols(const string& obj_file, found_debug_info_section = true; found_usable_info = true; info->LoadedSection(".stab"); - if (!LoadStabs(elf_header, stab_section, stabstr_section, - big_endian, module)) { + bool result = LoadStabs(elf_header, stab_section, stabstr_section, + big_endian, module); + usable_info_parsed = usable_info_parsed || result; + if (!result) { fprintf(stderr, "%s: \".stab\" section found, but failed to load" " STABS debugging information\n", obj_file.c_str()); } @@ -702,32 +909,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(".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(".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(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(".symtab", SHT_SYMTAB, @@ -785,9 +966,40 @@ 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(".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(".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"); + bool result = LoadDwarf(obj_file, elf_header, big_endian, + options.handle_inter_cu_refs, + options.symbol_data & INLINES, module); + usable_info_parsed = usable_info_parsed || result; + if (!result){ + 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 = @@ -885,7 +1097,7 @@ bool LoadSymbols(const string& obj_file, return false; } - return true; + return usable_info_parsed; } // Return the breakpad symbol file identifier for the architecture of @@ -905,7 +1117,9 @@ const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) { case EM_SPARC: return "sparc"; case EM_SPARCV9: return "sparcv9"; case EM_X86_64: return "x86_64"; - default: return NULL; + case EM_RISCV: return "riscv"; + case EM_NDS32: return "nds32"; + default: return nullptr; } } @@ -944,7 +1158,9 @@ template bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header, const string& obj_filename, const string& obj_os, - scoped_ptr& module) { + const string& module_id, + std::unique_ptr& module, + bool enable_multiple_field) { PageAllocator allocator; wasteful_vector identifier(&allocator, kDefaultBuildIdSize); if (!FileID::ElfFileIdentifierFromMappedFile(elf_header, identifier)) { @@ -966,14 +1182,19 @@ bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header, ? name_buf : google_breakpad::BaseName(obj_filename); - // Add an extra "0" at the end. PDB files on Windows have an 'age' - // number appended to the end of the file identifier; this isn't - // really used or necessary on other platforms, but be consistent. - string id = FileID::ConvertIdentifierToUUIDString(identifier) + "0"; + // Use the provided module_id + string id = module_id.empty() + // Add an extra "0" at the end. PDB files on Windows have an 'age' + // number appended to the end of the file identifier; this isn't + // really used or necessary on other platforms, but be consistent. + ? FileID::ConvertIdentifierToUUIDString(identifier) + "0" + : module_id; + // 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; } @@ -982,16 +1203,17 @@ template bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header, const string& obj_filename, const string& obj_os, + const string& module_id, const std::vector& debug_dirs, const DumpOptions& options, Module** out_module) { typedef typename ElfClass::Ehdr Ehdr; - *out_module = NULL; + *out_module = nullptr; - scoped_ptr module; - if (!InitModuleForElfClass(elf_header, obj_filename, obj_os, - module)) { + std::unique_ptr module; + if (!InitModuleForElfClass(elf_header, obj_filename, obj_os, module_id, + module, options.enable_multiple_field)) { return false; } @@ -1011,7 +1233,7 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header, // Load debuglink ELF file. fprintf(stderr, "Found debugging info in %s\n", debuglink_file.c_str()); MmapWrapper debug_map_wrapper; - Ehdr* debug_elf_header = NULL; + Ehdr* debug_elf_header = nullptr; if (!LoadELF(debuglink_file, &debug_map_wrapper, reinterpret_cast(&debug_elf_header)) || !SanitizeDebugFile(debug_elf_header, debuglink_file, @@ -1040,6 +1262,7 @@ namespace google_breakpad { bool ReadSymbolDataInternal(const uint8_t* obj_file, const string& obj_filename, const string& obj_os, + const string& module_id, const std::vector& debug_dirs, const DumpOptions& options, Module** module) { @@ -1052,12 +1275,12 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file, if (elfclass == ELFCLASS32) { return ReadSymbolDataElfClass( reinterpret_cast(obj_file), obj_filename, obj_os, - debug_dirs, options, module); + module_id, debug_dirs, options, module); } if (elfclass == ELFCLASS64) { return ReadSymbolDataElfClass( reinterpret_cast(obj_file), obj_filename, obj_os, - debug_dirs, options, module); + module_id, debug_dirs, options, module); } return false; @@ -1066,15 +1289,16 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file, bool WriteSymbolFile(const string& load_path, const string& obj_file, const string& obj_os, + const string& module_id, const std::vector& debug_dirs, const DumpOptions& options, std::ostream& sym_stream) { Module* module; - if (!ReadSymbolData(load_path, obj_file, obj_os, debug_dirs, options, + if (!ReadSymbolData(load_path, obj_file, obj_os, module_id, debug_dirs, options, &module)) return false; - bool result = module->Write(sym_stream, options.symbol_data); + bool result = module->Write(sym_stream, options.symbol_data, options.preserve_load_address); delete module; return result; } @@ -1085,9 +1309,10 @@ bool WriteSymbolFile(const string& load_path, bool WriteSymbolFileHeader(const string& load_path, const string& obj_file, const string& obj_os, + const string& module_id, std::ostream& sym_stream) { MmapWrapper map_wrapper; - void* elf_header = NULL; + void* elf_header = nullptr; if (!LoadELF(load_path, &map_wrapper, &elf_header)) { fprintf(stderr, "Could not load ELF file: %s\n", obj_file.c_str()); return false; @@ -1099,18 +1324,18 @@ bool WriteSymbolFileHeader(const string& load_path, } int elfclass = ElfClass(elf_header); - scoped_ptr module; + std::unique_ptr module; if (elfclass == ELFCLASS32) { if (!InitModuleForElfClass( reinterpret_cast(elf_header), obj_file, obj_os, - module)) { + module_id, 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( reinterpret_cast(elf_header), obj_file, obj_os, - module)) { + module_id, module, /*enable_multiple_field=*/false)) { fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str()); return false; } @@ -1125,16 +1350,17 @@ bool WriteSymbolFileHeader(const string& load_path, bool ReadSymbolData(const string& load_path, const string& obj_file, const string& obj_os, + const string& module_id, const std::vector& debug_dirs, const DumpOptions& options, Module** module) { MmapWrapper map_wrapper; - void* elf_header = NULL; + void* elf_header = nullptr; if (!LoadELF(load_path, &map_wrapper, &elf_header)) return false; return ReadSymbolDataInternal(reinterpret_cast(elf_header), - obj_file, obj_os, debug_dirs, options, module); + obj_file, obj_os, module_id, debug_dirs, options, module); } } // namespace google_breakpad diff --git a/src/common/linux/dump_symbols.h b/src/common/linux/dump_symbols.h index b033ce00e..25ede3e0f 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,19 @@ 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, + bool preserve_load_address) : 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), + preserve_load_address(preserve_load_address) {} SymbolData symbol_data; bool handle_inter_cu_refs; + bool enable_multiple_field; + bool preserve_load_address; }; // Find all the debugging information in OBJ_FILE, an ELF executable @@ -65,6 +70,7 @@ struct DumpOptions { bool WriteSymbolFile(const string& load_path, const string& obj_file, const string& obj_os, + const string& module_id, const std::vector& debug_dirs, const DumpOptions& options, std::ostream& sym_stream); @@ -76,6 +82,7 @@ bool WriteSymbolFile(const string& load_path, bool WriteSymbolFileHeader(const string& load_path, const string& obj_file, const string& obj_os, + const string& module_id, std::ostream& sym_stream); // As above, but simply return the debugging information in MODULE @@ -84,6 +91,7 @@ bool WriteSymbolFileHeader(const string& load_path, bool ReadSymbolData(const string& load_path, const string& obj_file, const string& obj_os, + const string& module_id, const std::vector& debug_dirs, const DumpOptions& options, Module** module); diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_symbols_unittest.cc index 54c210962..f20ac0dfc 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. // @@ -32,6 +31,10 @@ // dump_symbols_unittest.cc: // Unittests for google_breakpad::DumpSymbols +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -52,6 +55,7 @@ namespace google_breakpad { bool ReadSymbolDataInternal(const uint8_t* obj_file, const string& obj_filename, const string& obj_os, + const string& module_id, const std::vector& debug_dir, const DumpOptions& options, Module** module); @@ -92,10 +96,11 @@ 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, false); EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast(&header), "foo", "Linux", + "", vector(), options, &module)); @@ -129,10 +134,11 @@ TYPED_TEST(DumpSymbols, SimplePublic) { this->GetElfContents(elf); Module* module; - DumpOptions options(ALL_SYMBOL_DATA, true); + DumpOptions options(ALL_SYMBOL_DATA, true, false, false); EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, "foo", "Linux", + "", vector(), options, &module)); @@ -148,6 +154,54 @@ TYPED_TEST(DumpSymbols, SimplePublic) { delete module; } +TYPED_TEST(DumpSymbols, ModuleIdOverride) { + ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian); + // Zero out text section for simplicity. + Section text(kLittleEndian); + text.Append(4096, 0); + elf.AddSection(".text", text, SHT_PROGBITS); + + // Add a public symbol. + StringTable table(kLittleEndian); + SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table); + syms.AddSymbol("superfunc", + (typename TypeParam::Addr)0x1000, + (typename TypeParam::Addr)0x10, + // ELF32_ST_INFO works for 32-or 64-bit. + ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), + SHN_UNDEF + 1); + int index = elf.AddSection(".dynstr", table, SHT_STRTAB); + elf.AddSection(".dynsym", syms, + SHT_DYNSYM, // type + SHF_ALLOC, // flags + 0, // addr + index, // link + sizeof(typename TypeParam::Sym)); // entsize + + elf.Finish(); + this->GetElfContents(elf); + + Module* module; + DumpOptions options(ALL_SYMBOL_DATA, true, false, false); + EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, + "foo", + "Linux", + "some_module_id", + vector(), + options, + &module)); + + stringstream s; + module->Write(s, ALL_SYMBOL_DATA); + const string expected = + string("MODULE Linux ") + TypeParam::kMachineName + + " some_module_id foo\n" + "INFO CODE_ID 00000000000000000000000000000000\n" + "PUBLIC 1000 0 superfunc\n"; + EXPECT_EQ(expected, s.str()); + delete module; +} + TYPED_TEST(DumpSymbols, SimpleBuildID) { ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian); // Zero out text section for simplicity. @@ -186,10 +240,11 @@ TYPED_TEST(DumpSymbols, SimpleBuildID) { this->GetElfContents(elf); Module* module; - DumpOptions options(ALL_SYMBOL_DATA, true); + DumpOptions options(ALL_SYMBOL_DATA, true, false, false); EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, "foo", "Linux", + "", vector(), options, &module)); diff --git a/src/common/linux/eintr_wrapper.h b/src/common/linux/eintr_wrapper.h index 3f1d18481..a8428a9d3 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 f3206092b..89cfed5bd 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. // @@ -30,12 +29,18 @@ // elf_core_dump.cc: Implement google_breakpad::ElfCoreDump. // See elf_core_dump.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/elf_core_dump.h" #include #include #include +#include "common/memory_allocator.h" + namespace google_breakpad { // Implementation of ElfCoreDump::Note. @@ -45,7 +50,7 @@ ElfCoreDump::Note::Note() {} ElfCoreDump::Note::Note(const MemoryRange& content) : content_(content) {} bool ElfCoreDump::Note::IsValid() const { - return GetHeader() != NULL; + return GetHeader() != nullptr; } const ElfCoreDump::Nhdr* ElfCoreDump::Note::GetHeader() const { @@ -89,8 +94,7 @@ ElfCoreDump::Note ElfCoreDump::Note::GetNextNote() const { // static size_t ElfCoreDump::Note::AlignedSize(size_t size) { - size_t mask = sizeof(Word) - 1; - return (size + mask) & ~mask; + return PageAllocator::AlignUp(size, sizeof(Word)); } @@ -141,7 +145,7 @@ const ElfCoreDump::Phdr* ElfCoreDump::GetProgramHeader(unsigned index) const { return reinterpret_cast(content_.GetArrayElement( header->e_phoff, header->e_phentsize, index)); } - return NULL; + return nullptr; } const ElfCoreDump::Phdr* ElfCoreDump::GetFirstProgramHeaderOfType( @@ -152,7 +156,7 @@ const ElfCoreDump::Phdr* ElfCoreDump::GetFirstProgramHeaderOfType( return program; } } - return NULL; + return nullptr; } unsigned ElfCoreDump::GetProgramHeaderCount() const { diff --git a/src/common/linux/elf_core_dump.h b/src/common/linux/elf_core_dump.h index c8117a0e2..4f27179f4 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. // diff --git a/src/common/linux/elf_core_dump_unittest.cc b/src/common/linux/elf_core_dump_unittest.cc index 2399c12fd..633b60dbd 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. // @@ -29,6 +28,10 @@ // elf_core_dump_unittest.cc: Unit tests for google_breakpad::ElfCoreDump. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -52,10 +55,10 @@ using std::set; TEST(ElfCoreDumpTest, DefaultConstructor) { ElfCoreDump core; EXPECT_FALSE(core.IsValid()); - EXPECT_EQ(NULL, core.GetHeader()); + EXPECT_EQ(nullptr, core.GetHeader()); EXPECT_EQ(0U, core.GetProgramHeaderCount()); - EXPECT_EQ(NULL, core.GetProgramHeader(0)); - EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD)); + EXPECT_EQ(nullptr, core.GetProgramHeader(0)); + EXPECT_EQ(nullptr, core.GetFirstProgramHeaderOfType(PT_LOAD)); EXPECT_FALSE(core.GetFirstNote().IsValid()); } @@ -73,10 +76,10 @@ TEST(ElfCoreDumpTest, TestElfHeader) { ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); core.SetContent(mapped_core_file.content()); EXPECT_FALSE(core.IsValid()); - EXPECT_EQ(NULL, core.GetHeader()); + EXPECT_EQ(nullptr, core.GetHeader()); EXPECT_EQ(0U, core.GetProgramHeaderCount()); - EXPECT_EQ(NULL, core.GetProgramHeader(0)); - EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD)); + EXPECT_EQ(nullptr, core.GetProgramHeader(0)); + EXPECT_EQ(nullptr, core.GetFirstProgramHeaderOfType(PT_LOAD)); EXPECT_FALSE(core.GetFirstNote().IsValid()); ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); @@ -130,16 +133,20 @@ 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; const unsigned kCrashThread = 1; const int kCrashSignal = SIGABRT; ASSERT_TRUE(crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread, - kCrashSignal, NULL)); + kCrashSignal, nullptr)); pid_t expected_crash_thread_id = crash_generator.GetThreadId(kCrashThread); set expected_thread_ids; for (unsigned i = 0; i < kNumOfThreads; ++i) { @@ -203,13 +210,13 @@ TEST(ElfCoreDumpTest, ValidCoreFile) { switch (note.GetType()) { case NT_PRPSINFO: { - EXPECT_TRUE(description.data() != NULL); + EXPECT_TRUE(description.data() != nullptr); EXPECT_EQ(sizeof(elf_prpsinfo), description.length()); ++num_nt_prpsinfo; break; } case NT_PRSTATUS: { - EXPECT_TRUE(description.data() != NULL); + EXPECT_TRUE(description.data() != nullptr); EXPECT_EQ(sizeof(elf_prstatus), description.length()); const elf_prstatus* status = description.GetData(0); actual_thread_ids.insert(status->pr_pid); @@ -224,7 +231,7 @@ TEST(ElfCoreDumpTest, ValidCoreFile) { } #if defined(__i386__) || defined(__x86_64__) case NT_FPREGSET: { - EXPECT_TRUE(description.data() != NULL); + EXPECT_TRUE(description.data() != nullptr); EXPECT_EQ(sizeof(user_fpregs_struct), description.length()); ++num_nt_fpregset; break; @@ -232,7 +239,7 @@ TEST(ElfCoreDumpTest, ValidCoreFile) { #endif #if defined(__i386__) case NT_PRXFPREG: { - EXPECT_TRUE(description.data() != NULL); + EXPECT_TRUE(description.data() != nullptr); EXPECT_EQ(sizeof(user_fpxregs_struct), description.length()); ++num_nt_prxfpreg; break; diff --git a/src/common/linux/elf_gnu_compat.h b/src/common/linux/elf_gnu_compat.h index 0a3dfedb5..5d56c1e99 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 81e985a72..2e5c4eeb5 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. // @@ -30,12 +30,20 @@ // Original author: Ted Mielczarek +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/elf_symbols_to_module.h" +#include #include #include #include +#include +#include + #include "common/byte_cursor.h" #include "common/module.h" @@ -156,19 +164,19 @@ 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(iterator->value); ext->name = SymbolString(iterator->name_offset, strings); #if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle. int status = 0; char* demangled = - abi::__cxa_demangle(ext->name.c_str(), NULL, NULL, &status); + abi::__cxa_demangle(ext->name.c_str(), nullptr, nullptr, &status); if (demangled) { if (status == 0) ext->name = demangled; 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 861f72529..ab27ef6b8 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. // diff --git a/src/common/linux/elf_symbols_to_module_unittest.cc b/src/common/linux/elf_symbols_to_module_unittest.cc index 6a860701b..a74b29f0f 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. // @@ -32,6 +31,10 @@ // elf_symbols_to_module_unittest.cc: // Unittests for google_breakpad::ELFSymbolsToModule +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include diff --git a/src/common/linux/elfutils-inl.h b/src/common/linux/elfutils-inl.h index e56b37a9f..571371310 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. // @@ -50,13 +49,13 @@ const typename ElfClass::Shdr* FindElfSectionByName( const char* section_names, const char* names_end, int nsection) { - assert(name != NULL); - assert(sections != NULL); + assert(name != nullptr); + assert(sections != nullptr); assert(nsection > 0); int name_len = my_strlen(name); if (name_len == 0) - return NULL; + return nullptr; for (int i = 0; i < nsection; ++i) { const char* section_name = section_names + sections[i].sh_name; @@ -66,7 +65,7 @@ const typename ElfClass::Shdr* FindElfSectionByName( return sections + i; } } - return NULL; + return nullptr; } } // namespace google_breakpad diff --git a/src/common/linux/elfutils.cc b/src/common/linux/elfutils.cc index aa95357a3..770aeb1dc 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/elfutils.h" #include @@ -58,7 +61,7 @@ void FindElfClassSection(const char* elf_base, assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass); if (elf_header->e_shoff == 0) { - *section_start = NULL; + *section_start = nullptr; *section_size = 0; return; } @@ -75,7 +78,7 @@ void FindElfClassSection(const char* elf_base, sections, names, names_end, elf_header->e_shnum); - if (section != NULL && section->sh_size > 0) { + if (section != nullptr && section->sh_size > 0) { *section_start = elf_base + section->sh_offset; *section_size = section->sh_size; } @@ -132,7 +135,7 @@ bool FindElfSection(const void* elf_mapped_base, assert(section_start); assert(section_size); - *section_start = NULL; + *section_start = nullptr; *section_size = 0; if (!IsValidElf(elf_mapped_base)) @@ -145,11 +148,11 @@ bool FindElfSection(const void* elf_mapped_base, if (cls == ELFCLASS32) { FindElfClassSection(elf_base, section_name, section_type, section_start, section_size); - return *section_start != NULL; + return *section_start != nullptr; } else if (cls == ELFCLASS64) { FindElfClassSection(elf_base, section_name, section_type, section_start, section_size); - return *section_start != NULL; + return *section_start != nullptr; } return false; diff --git a/src/common/linux/elfutils.h b/src/common/linux/elfutils.h index ec5872a4f..130a8ac13 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; diff --git a/src/common/linux/file_id.cc b/src/common/linux/file_id.cc index 9944af7ae..1dfd5e956 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. // @@ -32,6 +31,10 @@ // See file_id.h for documentation // +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/file_id.h" #include @@ -45,10 +48,12 @@ #include "common/linux/elfutils.h" #include "common/linux/linux_libc_support.h" #include "common/linux/memory_mapped_file.h" +#include "common/memory_allocator.h" #include "common/using_std_string.h" #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); @@ -56,7 +61,10 @@ const size_t kMDGUIDSize = sizeof(MDGUID); FileID::FileID(const char* path) : path_(path) {} // ELF note name and desc are 32-bits word padded. -#define NOTE_PADDING(a) ((a + 3) & ~3) +template +inline T NotePadding(T size) { + return PageAllocator::AlignUp(size, 4); +} // These functions are also used inside the crashed process, so be safe // and use the syscall/libc wrappers instead of direct syscalls or libc. @@ -73,9 +81,9 @@ static bool ElfClassBuildIDNoteIdentifier(const void* section, size_t length, if (note_header->n_type == NT_GNU_BUILD_ID) break; note_header = reinterpret_cast( - reinterpret_cast(note_header) + sizeof(Nhdr) + - NOTE_PADDING(note_header->n_namesz) + - NOTE_PADDING(note_header->n_descsz)); + reinterpret_cast(note_header) + sizeof(Nhdr) + + NotePadding(note_header->n_namesz) + + NotePadding(note_header->n_descsz)); } if (reinterpret_cast(note_header) >= section_end || note_header->n_descsz == 0) { @@ -83,7 +91,7 @@ static bool ElfClassBuildIDNoteIdentifier(const void* section, size_t length, } const uint8_t* build_id = reinterpret_cast(note_header) + - sizeof(Nhdr) + NOTE_PADDING(note_header->n_namesz); + sizeof(Nhdr) + NotePadding(note_header->n_namesz); identifier.insert(identifier.end(), build_id, build_id + note_header->n_descsz); @@ -95,6 +103,13 @@ static bool ElfClassBuildIDNoteIdentifier(const void* section, size_t length, // and copy it into |identifier|. static bool FindElfBuildIDNote(const void* elf_mapped_base, wasteful_vector& identifier) { + void* note_section; + size_t note_size; + if (FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE, + (const void**)¬e_section, ¬e_size)) { + return ElfClassBuildIDNoteIdentifier(note_section, note_size, identifier); + } + PageAllocator allocator; // lld normally creates 2 PT_NOTEs, gold normally creates 1. auto_wasteful_vector segs(&allocator); @@ -106,13 +121,6 @@ static bool FindElfBuildIDNote(const void* elf_mapped_base, } } - void* note_section; - size_t note_size; - if (FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE, - (const void**)¬e_section, ¬e_size)) { - return ElfClassBuildIDNoteIdentifier(note_section, note_size, identifier); - } - return false; } @@ -124,8 +132,10 @@ static bool HashElfTextSection(const void* elf_mapped_base, void* text_section; size_t text_size; - if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS, - (const void**)&text_section, &text_size) || + if ((!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS, + (const void**)&text_section, &text_size) && + !FindElfSection(elf_mapped_base, "text", SHT_PROGBITS, + (const void**)&text_section, &text_size)) || text_size == 0) { return false; } @@ -198,4 +208,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 4aff021de..8e58d56e2 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 8225e5ac8..9de57c123 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. // @@ -29,6 +28,10 @@ // Unit tests for FileID +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -50,6 +53,8 @@ #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; @@ -171,6 +176,31 @@ TYPED_TEST(FileIDTest, ElfClass) { EXPECT_EQ(expected_identifier_string, identifier_string); } +TYPED_TEST(FileIDTest, ZephyrTextSection) { + const char expected_identifier_string[] = + "80808080808000000000008080808080"; + const size_t kTextSectionSize = 128; + + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); + Section text(kLittleEndian); + for (size_t i = 0; i < kTextSectionSize; ++i) { + text.D8(i * 3); + } + // Some binaries, namely Zephyr firmware binaries (https://www.zephyrproject.org/), + // refer to the `.text` section as `text`. They are logically identical however + // and should be handled the same. + elf.AddSection("text", text, SHT_PROGBITS); + elf.Finish(); + this->GetElfContents(elf); + + id_vector identifier(this->make_vector()); + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, + identifier)); + + string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); + EXPECT_EQ(expected_identifier_string, identifier_string); +} + TYPED_TEST(FileIDTest, BuildID) { const uint8_t kExpectedIdentifierBytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, @@ -321,6 +351,45 @@ TYPED_TEST(FileIDTest, BuildIDMultiplePH) { EXPECT_EQ(expected_identifier_string, identifier_string); } +TYPED_TEST(FileIDTest, BuildIDMultiplePHPreferGNU) { + const uint8_t kExpectedIdentifierBytes[] = + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13}; + const string expected_identifier_string = + this->get_file_id(kExpectedIdentifierBytes); + + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); + Section text(kLittleEndian); + text.Append(4096, 0); + elf.AddSection(".text", text, SHT_PROGBITS); + Notes notes1(kLittleEndian); + notes1.AddNote(0, "Linux", + reinterpret_cast("\0x42\0x02\0\0"), 4); + Notes notes2(kLittleEndian); + notes2.AddNote(NT_GNU_BUILD_ID, "GNU", + reinterpret_cast("\0x42\0x02\0\0"), 4); + Notes notes3(kLittleEndian); + notes3.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, + sizeof(kExpectedIdentifierBytes)); + int note1_idx = elf.AddSection(".note1", notes1, SHT_NOTE); + int note2_idx = elf.AddSection(".note2", notes2, SHT_NOTE); + int note3_idx = elf.AddSection(".note.gnu.build-id", notes3, SHT_NOTE); + elf.AddSegment(note1_idx, note1_idx, PT_NOTE); + elf.AddSegment(note2_idx, note2_idx, PT_NOTE); + elf.AddSegment(note3_idx, note3_idx, PT_NOTE); + elf.Finish(); + this->GetElfContents(elf); + + id_vector identifier(this->make_vector()); + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, + identifier)); + EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size()); + + string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); + EXPECT_EQ(expected_identifier_string, identifier_string); +} + // Test to make sure two files with different text sections produce // different hashes when not using a build id. TYPED_TEST(FileIDTest, UniqueHashes) { diff --git a/src/common/linux/google_crashdump_uploader.cc b/src/common/linux/google_crashdump_uploader.cc index a0d940b61..8c5e04925 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. // @@ -28,6 +27,10 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/google_crashdump_uploader.h" #include @@ -35,6 +38,7 @@ #include #include +#include #include "common/using_std_string.h" @@ -51,7 +55,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 http_layer{new LibcurlWrapper()}; Init(product, version, guid, @@ -63,21 +67,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 http_layer) { Init(product, version, guid, @@ -89,7 +94,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 +108,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 http_layer) { product_ = product; version_ = version; guid_ = guid; @@ -111,7 +116,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 a2d0575b5..74b5e1be9 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 #include +#include +#include #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 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 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 http_layer_; + std::unique_ptr 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 3d6612e82..4e0c30e39 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. // @@ -29,6 +28,10 @@ // Unit test for crash dump uploader. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "common/linux/google_crashdump_uploader.h" @@ -59,21 +62,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 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(nullptr, nullptr, nullptr)); } TEST_F(GoogleCrashdumpUploaderTest, TestSendRequestHappensWithValidParameters) { @@ -83,44 +77,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 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(nullptr, nullptr, nullptr)); } 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 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(nullptr, nullptr, nullptr)); } TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) { @@ -136,7 +113,7 @@ TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) { "http://foo.com", "", ""); - ASSERT_FALSE(uploader.Upload(NULL, NULL, NULL)); + ASSERT_FALSE(uploader.Upload(nullptr, nullptr, nullptr)); // Test with empty product version. GoogleCrashdumpUploader uploader1("product", @@ -151,7 +128,7 @@ TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) { "", ""); - ASSERT_FALSE(uploader1.Upload(NULL, NULL, NULL)); + ASSERT_FALSE(uploader1.Upload(nullptr, nullptr, nullptr)); // Test with empty client GUID. GoogleCrashdumpUploader uploader2("product", @@ -165,6 +142,6 @@ TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) { "", "", ""); - ASSERT_FALSE(uploader2.Upload(NULL, NULL, NULL)); + ASSERT_FALSE(uploader2.Upload(nullptr, nullptr, nullptr)); } } diff --git a/src/common/linux/guid_creator.cc b/src/common/linux/guid_creator.cc index 637406382..f3e576a40 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. // @@ -28,7 +27,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef HAVE_CONFIG_H -#include +#include // Must come first #endif #include "common/linux/eintr_wrapper.h" @@ -122,7 +121,7 @@ class GUIDGenerator { // time(NULL) is a very poor seed, so lacking anything better mix an // address into it. We drop the four rightmost bits as they're likely to // be 0 on almost all architectures. - srand(time(NULL) | ((uintptr_t)&once_control >> 4)); + srand(time(nullptr) | ((uintptr_t)&once_control >> 4)); } static pthread_once_t once_control; diff --git a/src/common/linux/guid_creator.h b/src/common/linux/guid_creator.h index c86d856c4..c02f55520 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 ace12b84e..e39042651 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/http_upload.h" #include @@ -63,7 +66,7 @@ bool HTTPUpload::SendRequest(const string& url, string* response_body, long* response_code, string* error_description) { - if (response_code != NULL) + if (response_code != nullptr) *response_code = 0; if (!CheckParameters(parameters)) @@ -71,19 +74,19 @@ bool HTTPUpload::SendRequest(const string& url, // We may have been linked statically; if curl_easy_init is in the // current binary, no need to search for a dynamic version. - void* curl_lib = dlopen(NULL, RTLD_NOW); + void* curl_lib = dlopen(nullptr, RTLD_NOW); if (!CheckCurlLib(curl_lib)) { fprintf(stderr, "Failed to open curl lib from binary, use libcurl.so instead\n"); dlerror(); // Clear dlerror before attempting to open libraries. dlclose(curl_lib); - curl_lib = NULL; + curl_lib = nullptr; } if (!curl_lib) { curl_lib = dlopen("libcurl.so", RTLD_NOW); } if (!curl_lib) { - if (error_description != NULL) + if (error_description != nullptr) *error_description = dlerror(); curl_lib = dlopen("libcurl.so.4", RTLD_NOW); } @@ -102,7 +105,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)(); - if (error_description != NULL) + if (error_description != nullptr) *error_description = "No Error"; if (!curl) { @@ -128,8 +131,8 @@ 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 = nullptr; + struct curl_httppost* lastptr = nullptr; // Add form data. CURLFORMcode (*curl_formadd)(struct curl_httppost**, struct curl_httppost**, ...); *(void**) (&curl_formadd) = dlsym(curl_lib, "curl_formadd"); @@ -151,14 +154,14 @@ 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 = nullptr; char buf[] = "Expect:"; 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); - if (response_body != NULL) { + if (response_body != nullptr) { (*curl_easy_setopt)(curl, CURLOPT_WRITEFUNCTION, WriteCallback); (*curl_easy_setopt)(curl, CURLOPT_WRITEDATA, reinterpret_cast(response_body)); @@ -170,7 +173,7 @@ bool HTTPUpload::SendRequest(const string& url, 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) { + if (response_code != nullptr) { 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); @@ -183,18 +186,18 @@ bool HTTPUpload::SendRequest(const string& url, url.c_str(), (*curl_easy_strerror)(err_code)); #endif - if (error_description != NULL) + if (error_description != nullptr) *error_description = (*curl_easy_strerror)(err_code); void (*curl_easy_cleanup)(CURL*); *(void**) (&curl_easy_cleanup) = dlsym(curl_lib, "curl_easy_cleanup"); (*curl_easy_cleanup)(curl); - if (formpost != NULL) { + if (formpost != nullptr) { void (*curl_formfree)(struct curl_httppost*); *(void**) (&curl_formfree) = dlsym(curl_lib, "curl_formfree"); (*curl_formfree)(formpost); } - if (headerlist != NULL) { + if (headerlist != nullptr) { 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); diff --git a/src/common/linux/http_upload.h b/src/common/linux/http_upload.h index 13f3d56cc..b7e557a00 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. // diff --git a/src/common/linux/ignore_ret.h b/src/common/linux/ignore_ret.h index efd274c20..1f879e8f4 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 fdb200f8e..2b6390981 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -48,6 +51,7 @@ LibcurlWrapper::LibcurlWrapper() LibcurlWrapper::~LibcurlWrapper() { if (init_ok_) { (*easy_cleanup_)(curl_); + (*global_cleanup_)(); dlclose(curl_lib_); } } @@ -263,6 +267,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; } @@ -299,12 +307,10 @@ bool LibcurlWrapper::SendRequestInner(const string& url, (*easy_getinfo_)(curl_, CURLINFO_RESPONSE_CODE, http_status_code); } -#ifndef NDEBUG if (err_code != CURLE_OK) fprintf(stderr, "Failed to send http request to %s, error: %s\n", url.c_str(), (*easy_strerror_)(err_code)); -#endif Reset(); diff --git a/src/common/linux/libcurl_wrapper.h b/src/common/linux/libcurl_wrapper.h index 823f83c7e..f8f961c1b 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(); @@ -112,6 +114,7 @@ class LibcurlWrapper { CURLcode (*easy_getinfo_)(CURL*, CURLINFO info, ...); void (*easy_reset_)(CURL*); 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 dd2929626..deb1a74b6 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. // @@ -31,6 +30,10 @@ // we call the libc functions directly we risk crashing in the dynamic linker // as it tries to resolve uncached PLT entries. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/linux_libc_support.h" #include @@ -129,7 +132,7 @@ const char* my_strchr(const char* haystack, char needle) { } const char* my_strrchr(const char* haystack, char needle) { - const char* ret = NULL; + const char* ret = nullptr; while (*haystack) { if (*haystack == needle) ret = haystack; @@ -145,7 +148,7 @@ void* my_memchr(const void* src, int needle, size_t src_len) { if (*p == needle) return (void*)p; } - return NULL; + return nullptr; } // Read a hex value diff --git a/src/common/linux/linux_libc_support.h b/src/common/linux/linux_libc_support.h index ec5a8d6b6..05e2aa245 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 adadfed44..48d6f5e29 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "common/linux/linux_libc_support.h" @@ -35,7 +38,7 @@ typedef testing::Test LinuxLibcSupportTest; } TEST(LinuxLibcSupportTest, strlen) { - static const char* test_data[] = { "", "a", "aa", "aaa", "aabc", NULL }; + static const char* test_data[] = { "", "a", "aa", "aaa", "aabc", nullptr }; for (unsigned i = 0; ; ++i) { if (!test_data[i]) break; @@ -53,7 +56,7 @@ TEST(LinuxLibcSupportTest, strcmp) { "ab", "aa", "abc", "ab", "abc", "abc", - NULL, + nullptr, }; for (unsigned i = 0; ; ++i) { @@ -127,9 +130,9 @@ TEST(LinuxLibcSupportTest, uitos) { } TEST(LinuxLibcSupportTest, strchr) { - ASSERT_EQ(NULL, my_strchr("abc", 'd')); - ASSERT_EQ(NULL, my_strchr("", 'd')); - ASSERT_EQ(NULL, my_strchr("efghi", 'd')); + ASSERT_EQ(nullptr, my_strchr("abc", 'd')); + ASSERT_EQ(nullptr, my_strchr("", 'd')); + ASSERT_EQ(nullptr, my_strchr("efghi", 'd')); ASSERT_TRUE(my_strchr("a", 'a')); ASSERT_TRUE(my_strchr("abc", 'a')); @@ -141,9 +144,9 @@ TEST(LinuxLibcSupportTest, strchr) { } TEST(LinuxLibcSupportTest, strrchr) { - ASSERT_EQ(NULL, my_strrchr("abc", 'd')); - ASSERT_EQ(NULL, my_strrchr("", 'd')); - ASSERT_EQ(NULL, my_strrchr("efghi", 'd')); + ASSERT_EQ(nullptr, my_strrchr("abc", 'd')); + ASSERT_EQ(nullptr, my_strrchr("", 'd')); + ASSERT_EQ(nullptr, my_strrchr("efghi", 'd')); ASSERT_TRUE(my_strrchr("a", 'a')); ASSERT_TRUE(my_strrchr("abc", 'a')); @@ -155,9 +158,9 @@ TEST(LinuxLibcSupportTest, strrchr) { } TEST(LinuxLibcSupportTest, memchr) { - ASSERT_EQ(NULL, my_memchr("abc", 'd', 3)); - ASSERT_EQ(NULL, my_memchr("abcd", 'd', 3)); - ASSERT_EQ(NULL, my_memchr("a", 'a', 0)); + ASSERT_EQ(nullptr, my_memchr("abc", 'd', 3)); + ASSERT_EQ(nullptr, my_memchr("abcd", 'd', 3)); + ASSERT_EQ(nullptr, my_memchr("a", 'a', 0)); static const char abc3[] = "abcabcabc"; ASSERT_EQ(abc3, my_memchr(abc3, 'a', 3)); diff --git a/src/common/linux/memory_mapped_file.cc b/src/common/linux/memory_mapped_file.cc index 99362945c..5e54aca5a 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. // @@ -30,6 +29,10 @@ // memory_mapped_file.cc: Implement google_breakpad::MemoryMappedFile. // See memory_mapped_file.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/memory_mapped_file.h" #include @@ -58,14 +61,18 @@ MemoryMappedFile::~MemoryMappedFile() { bool MemoryMappedFile::Map(const char* path, size_t offset) { Unmap(); - - int fd = sys_open(path, O_RDONLY, 0); + // Based on https://pubs.opengroup.org/onlinepubs/7908799/xsh/open.html + // If O_NONBLOCK is set: The open() function will return without blocking + // for the device to be ready or available. Setting this value will provent + // hanging if file is not avilable. + int fd = sys_open(path, O_RDONLY | O_NONBLOCK, 0); if (fd == -1) { return false; } #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) { @@ -88,7 +95,8 @@ bool MemoryMappedFile::Map(const char* path, size_t offset) { } size_t content_len = file_len - offset; - void* data = sys_mmap(NULL, content_len, PROT_READ, MAP_PRIVATE, fd, offset); + void* data = sys_mmap(nullptr, content_len, PROT_READ, MAP_PRIVATE, fd, + offset); sys_close(fd); if (data == MAP_FAILED) { return false; @@ -101,7 +109,7 @@ bool MemoryMappedFile::Map(const char* path, size_t offset) { void MemoryMappedFile::Unmap() { if (content_.data()) { sys_munmap(const_cast(content_.data()), content_.length()); - content_.Set(NULL, 0); + content_.Set(nullptr, 0); } } diff --git a/src/common/linux/memory_mapped_file.h b/src/common/linux/memory_mapped_file.h index fa660cc91..462e116eb 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. // @@ -34,7 +33,7 @@ #define COMMON_LINUX_MEMORY_MAPPED_FILE_H_ #include -#include "common/basictypes.h" + #include "common/memory_range.h" namespace google_breakpad { @@ -50,6 +49,9 @@ class MemoryMappedFile { // If Map() fails, the object behaves as if it is default constructed. MemoryMappedFile(const char* path, size_t offset); + MemoryMappedFile(const MemoryMappedFile&) = delete; + void operator=(const MemoryMappedFile&) = delete; + ~MemoryMappedFile(); // Maps a file at |path| into memory, which can then be accessed via @@ -78,8 +80,6 @@ class MemoryMappedFile { private: // Mapped file content as a MemoryRange object. MemoryRange content_; - - DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile); }; } // namespace google_breakpad diff --git a/src/common/linux/memory_mapped_file_unittest.cc b/src/common/linux/memory_mapped_file_unittest.cc index fad59f40c..213dca6f8 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. // @@ -30,6 +29,10 @@ // memory_mapped_file_unittest.cc: // Unit tests for google_breakpad::MemoryMappedFile. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -52,7 +55,7 @@ class MemoryMappedFileTest : public testing::Test { protected: void ExpectNoMappedData(const MemoryMappedFile& mapped_file) { EXPECT_TRUE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() == NULL); + EXPECT_TRUE(mapped_file.data() == nullptr); EXPECT_EQ(0U, mapped_file.size()); } }; @@ -84,7 +87,7 @@ TEST_F(MemoryMappedFileTest, MapNonexistentFile) { TEST_F(MemoryMappedFileTest, MapEmptyFile) { AutoTempDir temp_dir; string test_file = temp_dir.path() + "/empty_file"; - ASSERT_TRUE(WriteFile(test_file.c_str(), NULL, 0)); + ASSERT_TRUE(WriteFile(test_file.c_str(), nullptr, 0)); { MemoryMappedFile mapped_file(test_file.c_str(), 0); @@ -111,7 +114,7 @@ TEST_F(MemoryMappedFileTest, MapNonEmptyFile) { { MemoryMappedFile mapped_file(test_file.c_str(), 0); EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_TRUE(mapped_file.data() != nullptr); EXPECT_EQ(data_size, mapped_file.size()); EXPECT_EQ(0, memcmp(data, mapped_file.data(), data_size)); } @@ -119,7 +122,7 @@ TEST_F(MemoryMappedFileTest, MapNonEmptyFile) { MemoryMappedFile mapped_file; EXPECT_TRUE(mapped_file.Map(test_file.c_str(), 0)); EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_TRUE(mapped_file.data() != nullptr); EXPECT_EQ(data_size, mapped_file.size()); EXPECT_EQ(0, memcmp(data, mapped_file.data(), data_size)); } @@ -147,13 +150,13 @@ TEST_F(MemoryMappedFileTest, RemapAfterMap) { { MemoryMappedFile mapped_file(test_file1.c_str(), 0); EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_TRUE(mapped_file.data() != nullptr); EXPECT_EQ(data1_size, mapped_file.size()); EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size)); mapped_file.Map(test_file2.c_str(), 0); EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_TRUE(mapped_file.data() != nullptr); EXPECT_EQ(data2_size, mapped_file.size()); EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size)); } @@ -161,13 +164,13 @@ TEST_F(MemoryMappedFileTest, RemapAfterMap) { MemoryMappedFile mapped_file; EXPECT_TRUE(mapped_file.Map(test_file1.c_str(), 0)); EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_TRUE(mapped_file.data() != nullptr); EXPECT_EQ(data1_size, mapped_file.size()); EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size)); mapped_file.Map(test_file2.c_str(), 0); EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_TRUE(mapped_file.data() != nullptr); EXPECT_EQ(data2_size, mapped_file.size()); EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size)); } @@ -189,7 +192,7 @@ TEST_F(MemoryMappedFileTest, MapWithOffset) { { MemoryMappedFile mapped_file(test_file1.c_str(), page_size); EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_TRUE(mapped_file.data() != nullptr); EXPECT_EQ(data1_size - page_size, mapped_file.size()); EXPECT_EQ( 0, @@ -199,7 +202,7 @@ TEST_F(MemoryMappedFileTest, MapWithOffset) { MemoryMappedFile mapped_file; mapped_file.Map(test_file1.c_str(), page_size); EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_TRUE(mapped_file.data() != nullptr); EXPECT_EQ(data1_size - page_size, mapped_file.size()); EXPECT_EQ( 0, diff --git a/src/common/linux/safe_readlink.cc b/src/common/linux/safe_readlink.cc index 870c28af3..a42b01a5f 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. // @@ -30,6 +29,10 @@ // safe_readlink.cc: Implement google_breakpad::SafeReadLink. // See safe_readlink.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "third_party/lss/linux_syscall_support.h" diff --git a/src/common/linux/safe_readlink.h b/src/common/linux/safe_readlink.h index 4ae131b58..f3aa9332b 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 d346b2a80..8fa6d0656 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. // @@ -29,6 +28,10 @@ // safe_readlink_unittest.cc: Unit tests for google_breakpad::SafeReadLink. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "common/linux/safe_readlink.h" diff --git a/src/common/linux/scoped_pipe.cc b/src/common/linux/scoped_pipe.cc new file mode 100644 index 000000000..8de04ce95 --- /dev/null +++ b/src/common/linux/scoped_pipe.cc @@ -0,0 +1,132 @@ +// 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "common/linux/scoped_pipe.h" + +#include + +#include "common/linux/eintr_wrapper.h" + +namespace google_breakpad { + +ScopedPipe::ScopedPipe() { + fds_[0] = -1; + fds_[1] = -1; +} + +ScopedPipe::~ScopedPipe() { + CloseReadFd(); + CloseWriteFd(); +} + +bool ScopedPipe::Init() { + return pipe(fds_) == 0; +} + +void ScopedPipe::CloseReadFd() { + if (fds_[0] != -1) { + close(fds_[0]); + fds_[0] = -1; + } +} + +void ScopedPipe::CloseWriteFd() { + if (fds_[1] != -1) { + close(fds_[1]); + fds_[1] = -1; + } +} + +bool ScopedPipe::ReadLine(std::string& line) { + // Simple buffered file read. `read_buffer_` stores previously read bytes, and + // we either return a line from this buffer, or we append blocks of read bytes + // to the buffer until we have a complete line. + size_t eol_index = read_buffer_.find('\n'); + + // While we don't have a full line, and read pipe is valid. + while (eol_index == std::string::npos && GetReadFd() != -1) { + // Read a block of 128 bytes from the read pipe. + char read_buf[128]; + ssize_t read_len = HANDLE_EINTR( + read(GetReadFd(), read_buf, sizeof(read_buf))); + if (read_len <= 0) { + // Pipe error, or pipe has been closed. + CloseReadFd(); + break; + } + + // Append the block, and check if we have a full line now. + read_buffer_.append(read_buf, read_len); + eol_index = read_buffer_.find('\n'); + } + + if (eol_index != std::string::npos) { + // We have a full line to output. + line = read_buffer_.substr(0, eol_index); + if (eol_index < read_buffer_.size()) { + read_buffer_ = read_buffer_.substr(eol_index + 1); + } else { + read_buffer_ = ""; + } + + return true; + } + + if (read_buffer_.size()) { + // We don't have a full line to output, but we can only reach here if the + // pipe has closed and there are some bytes left at the end, so we should + // return those bytes. + line = std::move(read_buffer_); + read_buffer_ = ""; + + return true; + } + + // We don't have any buffered data left, and the pipe has closed. + return false; +} + +int ScopedPipe::Dup2WriteFd(int new_fd) const { + return dup2(fds_[1], new_fd); +} + +bool ScopedPipe::WriteForTesting(const void* bytes, size_t bytes_len) { + ssize_t r = HANDLE_EINTR(write(GetWriteFd(), bytes, bytes_len)); + if (r != static_cast(bytes_len)) { + CloseWriteFd(); + return false; + } + + return true; +} + +} // namespace google_breakpad diff --git a/src/common/linux/scoped_pipe.h b/src/common/linux/scoped_pipe.h new file mode 100644 index 000000000..25394c2ab --- /dev/null +++ b/src/common/linux/scoped_pipe.h @@ -0,0 +1,115 @@ +// 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_LINUX_SCOPED_PIPE_H_ +#define COMMON_LINUX_SCOPED_PIPE_H_ + +#include +#include + +namespace google_breakpad { + +// Small RAII wrapper for a pipe pair. +// +// Example (both ends of pipe in same process): +// ScopedPipe tmp; +// std::string line; +// if (tmp.Init() && tmp.Write(bytes, bytes_len)) { +// tmp.CloseWriteFd(); +// while (tmp.ReadLine(&line)) { +// std::cerr << line << std::endl; +// } +// } +// +// Example (reading output from a child process): +// ScopedPipe tmp; +// if (fork()) { +// // Parent process, read from the read end of the pipe. +// std::string line; +// while (tmp.ReadLine(line)) { +// // Process output... +// } +// // Close read pipe once done processing the output that we wanted, this +// // should ensure that the child process exits even if we didn't read all +// // of the output. +// tmp.CloseReadFd(); +// // Parent process should handle waiting for child to exit here... +// } else { +// // Child process, close the read fd and dup the write fd before exec'ing. +// tmp.CloseReadFd(); +// tmp.Dup2WriteFd(STDOUT_FILENO); +// tmp.Dup2WriteFd(STDERR_FILENO); +// execl("some-command", "some-arguments"); +// } +class ScopedPipe { + public: + ScopedPipe(); + ~ScopedPipe(); + + // Creates the pipe pair - returns false on error. + bool Init(); + + // Close the read pipe. This only needs to be used when the read pipe needs to + // be closed earlier. + void CloseReadFd(); + + // Close the write pipe. This only needs to be used when the write pipe needs + // to be closed earlier. + void CloseWriteFd(); + + // Reads characters until newline or end of pipe. On read failure this will + // close the read pipe, but continue to return true and read buffered lines + // until the internal buffering is exhausted. This will block if there is no + // data available on the read pipe. + bool ReadLine(std::string& line); + + // Writes bytes to the write end of the pipe, returns false and closes write + // pipe on failure. + bool WriteForTesting(const void* bytes, size_t bytes_len); + + // Calls the dup2 system call to replace any existing open file descriptor + // with number new_fd with a copy of the current write end file descriptor + // for the pipe. + int Dup2WriteFd(int new_fd) const; + + private: + int GetReadFd() const { + return fds_[0]; + } + + int GetWriteFd() const { + return fds_[1]; + } + + int fds_[2]; + std::string read_buffer_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_SCOPED_PIPE_H_ diff --git a/src/common/linux/scoped_pipe_unittest.cc b/src/common/linux/scoped_pipe_unittest.cc new file mode 100644 index 000000000..4daa5c255 --- /dev/null +++ b/src/common/linux/scoped_pipe_unittest.cc @@ -0,0 +1,75 @@ +// 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. + +// scoped_pipe_unittest.cc: Unit tests for google_breakpad::ScopedPipe. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "common/linux/scoped_pipe.h" + +#include "breakpad_googletest_includes.h" + +namespace google_breakpad { + +TEST(ScopedPipeTest, WriteAndClose) { + const char kTestData[] = "One\nTwo\nThree"; + ScopedPipe pipe; + std::string line; + + ASSERT_TRUE(pipe.Init()); + ASSERT_TRUE(pipe.WriteForTesting(kTestData, strlen(kTestData))); + pipe.CloseWriteFd(); + + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "One"); + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "Two"); + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "Three"); + ASSERT_FALSE(pipe.ReadLine(line)); +} + +TEST(ScopedPipeTest, MultipleWrites) { + const char kTestDataOne[] = "One\n"; + const char kTestDataTwo[] = "Two\n"; + ScopedPipe pipe; + std::string line; + + ASSERT_TRUE(pipe.Init()); + ASSERT_TRUE(pipe.WriteForTesting(kTestDataOne, strlen(kTestDataOne))); + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "One"); + + ASSERT_TRUE(pipe.WriteForTesting(kTestDataTwo, strlen(kTestDataTwo))); + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "Two"); +} + +} // namespace google_breakpad diff --git a/src/common/linux/scoped_tmpfile.cc b/src/common/linux/scoped_tmpfile.cc new file mode 100644 index 000000000..2395a64e8 --- /dev/null +++ b/src/common/linux/scoped_tmpfile.cc @@ -0,0 +1,103 @@ +// 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. + +// Utility class for creating a temporary file that is deleted in the +// destructor. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "common/linux/scoped_tmpfile.h" + +#include +#include +#include +#include +#include + +#include "common/linux/eintr_wrapper.h" + +#if !defined(__ANDROID__) +#define TEMPDIR "/tmp" +#else +#define TEMPDIR "/data/local/tmp" +#endif + +namespace google_breakpad { + +ScopedTmpFile::ScopedTmpFile() = default; + +ScopedTmpFile::~ScopedTmpFile() { + if (fd_ >= 0) { + close(fd_); + fd_ = -1; + } +} + +bool ScopedTmpFile::InitEmpty() { + // Prevent calling Init when fd_ is already valid, leaking the file. + if (fd_ != -1) { + return false; + } + + // Respect the TMPDIR environment variable. + const char* tempdir = getenv("TMPDIR"); + if (!tempdir) { + tempdir = TEMPDIR; + } + + // Create a temporary file that is not linked in to the filesystem, and that + // is only accessible by the current user. + fd_ = open(tempdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR); + + return fd_ >= 0; +} + +bool ScopedTmpFile::InitString(const char* text) { + return InitData(text, strlen(text)); +} + +bool ScopedTmpFile::InitData(const void* data, size_t data_len) { + if (!InitEmpty()) { + return false; + } + + return SetContents(data, data_len); +} + +bool ScopedTmpFile::SetContents(const void* data, size_t data_len) { + ssize_t r = HANDLE_EINTR(write(fd_, data, data_len)); + if (r != static_cast(data_len)) { + return false; + } + + return 0 == lseek(fd_, 0, SEEK_SET); +} + +} // namespace google_breakpad diff --git a/src/common/linux/scoped_tmpfile.h b/src/common/linux/scoped_tmpfile.h new file mode 100644 index 000000000..dffec182f --- /dev/null +++ b/src/common/linux/scoped_tmpfile.h @@ -0,0 +1,85 @@ +// 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. + +// Utility class for creating a temporary file for that is deleted in the +// destructor. + +#ifndef COMMON_LINUX_SCOPED_TMPFILE_H_ +#define COMMON_LINUX_SCOPED_TMPFILE_H_ + +#include + +namespace google_breakpad { + +// Small RAII wrapper for temporary files. +// +// Example: +// ScopedTmpFile tmp; +// if (tmp.Init("Some file contents")) { +// ... +// } +class ScopedTmpFile { + public: + // Initialize the ScopedTmpFile object - this does not create the temporary + // file until Init is called. + ScopedTmpFile(); + + // Destroy temporary file on scope exit. + ~ScopedTmpFile(); + + // Creates the empty temporary file - returns true iff the temporary file was + // created successfully. Should always be checked before using the file. + bool InitEmpty(); + + // Creates the temporary file with the provided C string. The terminating null + // is not written. Returns true iff the temporary file was created + // successfully and the contents were written successfully. + bool InitString(const char* text); + + // Creates the temporary file with the provided data. Returns true iff the + // temporary file was created successfully and the contents were written + // successfully. + bool InitData(const void* data, size_t data_len); + + // Returns the Posix file descriptor for the test file, or -1 if Init() + // returned false. Note: on Windows, this always returns -1. + int GetFd() const { + return fd_; + } + + private: + // Set the contents of the temporary file, and seek back to the start of the + // file. On failure, returns false. + bool SetContents(const void* data, size_t data_len); + + int fd_ = -1; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_SCOPED_TMPFILE_H_ diff --git a/src/common/linux/scoped_tmpfile_unittest.cc b/src/common/linux/scoped_tmpfile_unittest.cc new file mode 100644 index 000000000..f0bb2bbb4 --- /dev/null +++ b/src/common/linux/scoped_tmpfile_unittest.cc @@ -0,0 +1,50 @@ +// 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. + +// scoped_tmpfile_unittest.cc: Unit tests for google_breakpad::ScopedTmpfile. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "common/linux/scoped_tmpfile.h" + +#include + +#include "breakpad_googletest_includes.h" + +using google_breakpad::ScopedTmpFile; + +TEST(ScopedTmpFileTest, CheckContentsMatch) { + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("Test")); + + char file_contents[5] = {0}; + ASSERT_EQ(4, read(file.GetFd(), file_contents, sizeof(file_contents))); + EXPECT_STREQ(file_contents, "Test"); +} diff --git a/src/common/linux/symbol_collector_client.cc b/src/common/linux/symbol_collector_client.cc index 92b25ddba..e9a1893c2 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/symbol_collector_client.h" #include diff --git a/src/common/linux/symbol_collector_client.h b/src/common/linux/symbol_collector_client.h index 0e23242a2..6190376fc 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 1d5ff7196..8ab143c6f 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. // @@ -30,6 +29,10 @@ // symbol_upload.cc: implemented google_breakpad::sym_upload::Start, a helper // function for linux symbol upload tool. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/symbol_upload.h" #include diff --git a/src/common/linux/symbol_upload.h b/src/common/linux/symbol_upload.h index 9033152bf..a9d30e7b7 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 2ba25e611..4de506666 100644 --- a/src/common/linux/synth_elf.cc +++ b/src/common/linux/synth_elf.cc @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/synth_elf.h" #include @@ -6,6 +10,7 @@ #include #include "common/linux/elf_gnu_compat.h" +#include "common/memory_allocator.h" #include "common/using_std_string.h" namespace google_breakpad { @@ -155,7 +160,7 @@ void ELF::AddSegment(int start, int end, uint32_t type, uint32_t flags) { if (sections_[i].type_ != SHT_NOBITS) { assert(!prev_was_nobits); // non SHT_NOBITS sections are 4-byte aligned (see AddSection) - size = (size + 3) & ~3; + size = PageAllocator::AlignUp(size, 4); filesz += size; } else { prev_was_nobits = true; diff --git a/src/common/linux/synth_elf.h b/src/common/linux/synth_elf.h index 90fa28c0d..bf22081b6 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. // diff --git a/src/common/linux/synth_elf_unittest.cc b/src/common/linux/synth_elf_unittest.cc index fb3601e65..578f6a261 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. // @@ -32,6 +31,10 @@ // synth_elf_unittest.cc: // Unittests for google_breakpad::synth_elf::ELF +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "breakpad_googletest_includes.h" diff --git a/src/common/linux/tests/auto_testfile.h b/src/common/linux/tests/auto_testfile.h deleted file mode 100644 index 92fe017b9..000000000 --- a/src/common/linux/tests/auto_testfile.h +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 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. - -// Utility class for creating a temporary file for unit tests -// that is deleted in the destructor. - -#ifndef GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE -#define GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE - -#include -#include - -#include - -#include "breakpad_googletest_includes.h" -#include "common/linux/eintr_wrapper.h" -#include "common/tests/auto_tempdir.h" - -namespace google_breakpad { - -class AutoTestFile { - public: - // Create a new empty test file. - // test_prefix: (input) test-specific prefix, can't be NULL. - explicit AutoTestFile(const char* test_prefix) { - Init(test_prefix); - } - - // Create a new test file, and fill it with initial data from a C string. - // The terminating zero is not written. - // test_prefix: (input) test-specific prefix, can't be NULL. - // text: (input) initial content. - AutoTestFile(const char* test_prefix, const char* text) { - Init(test_prefix); - if (fd_ >= 0) - WriteText(text, static_cast(strlen(text))); - } - - AutoTestFile(const char* test_prefix, const char* text, size_t text_len) { - Init(test_prefix); - if (fd_ >= 0) - WriteText(text, text_len); - } - - // Destroy test file on scope exit. - ~AutoTestFile() { - if (fd_ >= 0) { - close(fd_); - fd_ = -1; - } - } - - // Returns true iff the test file could be created properly. - // Useful in tests inside EXPECT_TRUE(file.IsOk()); - bool IsOk() { - return fd_ >= 0; - } - - // Returns the Posix file descriptor for the test file, or -1 - // If IsOk() returns false. Note: on Windows, this always returns -1. - int GetFd() { - return fd_; - } - - private: - void Init(const char* test_prefix) { - fd_ = -1; - char path_templ[PATH_MAX]; - int ret = snprintf(path_templ, sizeof(path_templ), - TEMPDIR "/%s-unittest.XXXXXX", - test_prefix); - if (ret >= static_cast(sizeof(path_templ))) - return; - - fd_ = mkstemp(path_templ); - if (fd_ < 0) - return; - - unlink(path_templ); - } - - void WriteText(const char* text, size_t text_len) { - ssize_t r = HANDLE_EINTR(write(fd_, text, text_len)); - if (r != static_cast(text_len)) { - close(fd_); - fd_ = -1; - return; - } - - lseek(fd_, 0, SEEK_SET); - } - - int fd_; -}; - -} // namespace google_breakpad - -#endif // GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE diff --git a/src/common/linux/tests/crash_generator.cc b/src/common/linux/tests/crash_generator.cc index a70df28ad..7a7dae51d 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. // @@ -30,6 +29,10 @@ // crash_generator.cc: Implement google_breakpad::CrashGenerator. // See crash_generator.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/linux/tests/crash_generator.h" #include @@ -98,7 +101,7 @@ void* thread_function(void* data) { namespace google_breakpad { CrashGenerator::CrashGenerator() - : shared_memory_(NULL), + : shared_memory_(nullptr), shared_memory_size_(0) { } @@ -151,7 +154,7 @@ bool CrashGenerator::UnmapSharedMemory() { return true; if (munmap(shared_memory_, shared_memory_size_) == 0) { - shared_memory_ = NULL; + shared_memory_ = nullptr; shared_memory_size_ = 0; return true; } @@ -169,6 +172,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) { @@ -300,7 +312,7 @@ void CrashGenerator::CreateThreadsInChildProcess(unsigned num_threads) { } pthread_barrier_t thread_barrier; - if (pthread_barrier_init(&thread_barrier, NULL, num_threads) != 0) { + if (pthread_barrier_init(&thread_barrier, nullptr, num_threads) != 0) { fprintf(stderr, "CrashGenerator: Failed to initialize thread barrier\n"); exit(1); } diff --git a/src/common/linux/tests/crash_generator.h b/src/common/linux/tests/crash_generator.h index 7e2fcbf98..71c05d273 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 c390508a1..3dcdecb08 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 46bbf6137..537972e50 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/long_string_dictionary.h" #include @@ -161,7 +164,7 @@ const string LongStringDictionary::GetValueForKey(const char* key) const { const char* segment_value = SimpleStringDictionary::GetValueForKey(segment_key); - if (segment_value != NULL) { + if (segment_value != nullptr) { found_segment = true; return_value.append(segment_value); } else { diff --git a/src/common/long_string_dictionary.h b/src/common/long_string_dictionary.h index 68bf03de2..9319b27f7 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 f9b645ba7..86bb26bab 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -60,7 +63,7 @@ TEST(LongStringDictionary, LongStringDictionary) { EXPECT_EQ("", dict.GetValueForKey("key3")); // Remove by setting value to NULL - dict.SetKeyValue("key2", NULL); + dict.SetKeyValue("key2", nullptr); // Now make sure it's not there anymore EXPECT_EQ("", dict.GetValueForKey("key2")); diff --git a/src/common/mac/Breakpad.xcconfig b/src/common/mac/Breakpad.xcconfig index f09136908..fd28d3cec 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 94cdd8cfc..6ec7c00eb 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 920f277db..9121b0d08 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 04fcf6d0c..ae5368cdf 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 c4fd14029..dcc7da441 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 ebc5836a2..17db83d6e 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 index 3aa316b54..9c3cb3f92 100644 --- a/src/common/mac/HTTPGetRequest.h +++ b/src/common/mac/HTTPGetRequest.h @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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/HTTPGetRequest.m b/src/common/mac/HTTPGetRequest.m index f9b7bf0ec..e151cfd8a 100644 --- a/src/common/mac/HTTPGetRequest.m +++ b/src/common/mac/HTTPGetRequest.m @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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/HTTPMultipartUpload.h b/src/common/mac/HTTPMultipartUpload.h index 56d5394db..27b9cf861 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. // diff --git a/src/common/mac/HTTPMultipartUpload.m b/src/common/mac/HTTPMultipartUpload.m index 2aa64f791..b3a084a91 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. // diff --git a/src/common/mac/HTTPPutRequest.h b/src/common/mac/HTTPPutRequest.h index 431ea6104..36d38c016 100644 --- a/src/common/mac/HTTPPutRequest.h +++ b/src/common/mac/HTTPPutRequest.h @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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/HTTPPutRequest.m b/src/common/mac/HTTPPutRequest.m index ec67376b0..b7c7e091d 100644 --- a/src/common/mac/HTTPPutRequest.m +++ b/src/common/mac/HTTPPutRequest.m @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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,7 @@ - (NSString*)HTTPMethod { //============================================================================= - (NSData*)bodyData { - NSMutableData* postBody = [NSMutableData data]; - - [HTTPRequest appendFileToBodyData:postBody - withName:@"symbol_file" - withFileOrData:file_]; - - return postBody; + return [NSData dataWithContentsOfFile:file_]; } @end diff --git a/src/common/mac/HTTPRequest.h b/src/common/mac/HTTPRequest.h index b78fad6ba..493741473 100644 --- a/src/common/mac/HTTPRequest.h +++ b/src/common/mac/HTTPRequest.h @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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/HTTPRequest.m b/src/common/mac/HTTPRequest.m index ee7de3af9..af21874d1 100644 --- a/src/common/mac/HTTPRequest.m +++ b/src/common/mac/HTTPRequest.m @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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,8 +31,26 @@ #include #include +#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \ + __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) +#import +#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 @@ -41,20 +58,17 @@ static NSData* SendSynchronousNSURLRequest(NSURLRequest* req, NSURLResponse** outResponse, NSError** outError) { -#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) +#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]; - [[session + NSURLSessionDataTask *task = [session dataTaskWithRequest:req completionHandler:^(NSData* data, NSURLResponse* resp, NSError* err) { if (outError) @@ -64,19 +78,59 @@ if (err == nil) result = [data retain]; dispatch_semaphore_signal(waitSemaphone); - }] resume]; + }]; + [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 +#else // USE_NSURLSESSION return [NSURLConnection sendSynchronousRequest:req returningResponse:outResponse error:outError]; -#endif +#endif // USE_NSURLSESSION } @implementation HTTPRequest diff --git a/src/common/mac/HTTPSimplePostRequest.h b/src/common/mac/HTTPSimplePostRequest.h index bfabfead6..01a1e8688 100644 --- a/src/common/mac/HTTPSimplePostRequest.h +++ b/src/common/mac/HTTPSimplePostRequest.h @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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/HTTPSimplePostRequest.m b/src/common/mac/HTTPSimplePostRequest.m index 4cb3ef159..7aba94fdd 100644 --- a/src/common/mac/HTTPSimplePostRequest.m +++ b/src/common/mac/HTTPSimplePostRequest.m @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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/MachIPC.h b/src/common/mac/MachIPC.h index a3fae5a14..38b339f5e 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. // @@ -165,7 +164,7 @@ class MachMessage { // The receiver of the message can retrieve the raw data this way uint8_t* GetData() { - return GetDataLength() > 0 ? GetDataPacket()->data : NULL; + return GetDataLength() > 0 ? GetDataPacket()->data : nullptr; } uint32_t GetDataLength() { diff --git a/src/common/mac/MachIPC.mm b/src/common/mac/MachIPC.mm index b41a825d4..e2e7332bd 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. // @@ -30,9 +29,10 @@ // MachIPC.mm // Wrapper for mach IPC calls -#import #import "MachIPC.h" +#import #include "common/mac/bootstrap_compat.h" +#include "common/memory_allocator.h" namespace google_breakpad { //============================================================================== @@ -78,7 +78,7 @@ size_t size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t); // add space for MessageDataPacket - int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3; + size_t alignedDataLength = PageAllocator::AlignUp(GetDataLength(), 4); size += 2*sizeof(int32_t) + alignedDataLength; // add space for descriptors diff --git a/src/common/mac/SymbolCollectorClient.h b/src/common/mac/SymbolCollectorClient.h index 9e955c8e2..367753a4a 100644 --- a/src/common/mac/SymbolCollectorClient.h +++ b/src/common/mac/SymbolCollectorClient.h @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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,7 +95,8 @@ typedef NS_ENUM(NSInteger, SymbolStatus) { withUploadKey:(NSString*)uploadKey withDebugFile:(NSString*)debugFile withDebugID:(NSString*)debugID - withType:(NSString*)type; + withType:(NSString*)type + withProductName:(NSString*)productName; @end diff --git a/src/common/mac/SymbolCollectorClient.m b/src/common/mac/SymbolCollectorClient.m index 5926d2ad2..fd33432b7 100644 --- a/src/common/mac/SymbolCollectorClient.m +++ b/src/common/mac/SymbolCollectorClient.m @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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,18 +189,22 @@ + (CompleteUploadResult)completeUploadOnServer:(NSString*)APIURL withUploadKey:(NSString*)uploadKey withDebugFile:(NSString*)debugFile withDebugID:(NSString*)debugID - withType:(NSString*)type { + withType:(NSString*)type + withProductName:(NSString*)productName { NSURL* URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/v1/uploads/%@:complete?key=%@", APIURL, uploadKey, APIKey]]; - NSDictionary* symbolIdDictionary = - [NSDictionary dictionaryWithObjectsAndKeys:debugFile, @"debug_file", - debugID, @"debug_id", nil]; - NSDictionary* jsonDictionary = [NSDictionary - dictionaryWithObjectsAndKeys:symbolIdDictionary, @"symbol_id", type, - @"symbol_upload_type", nil]; + 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 diff --git a/src/common/mac/arch_utilities.cc b/src/common/mac/arch_utilities.cc index c0e4bac54..cfa2e2d70 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. // @@ -27,110 +26,35 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/mac/arch_utilities.h" +#include #include #include #include #include -#ifndef CPU_SUBTYPE_ARM_V7S -#define CPU_SUBTYPE_ARM_V7S (static_cast(11)) -#endif // CPU_SUBTYPE_ARM_V7S - -#ifndef CPU_TYPE_ARM64 -#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) -#endif // CPU_TYPE_ARM64 - -#ifndef CPU_SUBTYPE_ARM64_ALL -#define CPU_SUBTYPE_ARM64_ALL (static_cast(0)) -#endif // CPU_SUBTYPE_ARM64_ALL - -#ifndef CPU_SUBTYPE_ARM64_E -#define CPU_SUBTYPE_ARM64_E (static_cast(2)) -#endif // CPU_SUBTYPE_ARM64_E - -namespace { - -const NXArchInfo* ArchInfo_arm64(cpu_subtype_t cpu_subtype) { - const char* name = NULL; - switch (cpu_subtype) { - case CPU_SUBTYPE_ARM64_ALL: - name = "arm64"; - break; - case CPU_SUBTYPE_ARM64_E: - name = "arm64e"; - break; - default: - return NULL; - } - - NXArchInfo* arm64 = new NXArchInfo; - *arm64 = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM, - CPU_SUBTYPE_ARM_V7); - arm64->name = name; - arm64->cputype = CPU_TYPE_ARM64; - arm64->cpusubtype = cpu_subtype; - arm64->description = "arm 64"; - return arm64; -} - -const NXArchInfo* ArchInfo_armv7s() { - NXArchInfo* armv7s = new NXArchInfo; - *armv7s = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM, - CPU_SUBTYPE_ARM_V7); - armv7s->name = "armv7s"; - armv7s->cpusubtype = CPU_SUBTYPE_ARM_V7S; - armv7s->description = "arm v7s"; - return armv7s; -} - -} // namespace - -namespace google_breakpad { - -const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name) { - // TODO: Remove this when the OS knows about arm64. - if (!strcmp("arm64", arch_name)) - return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM64, - CPU_SUBTYPE_ARM64_ALL); - - if (!strcmp("arm64e", arch_name)) - return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM64, - CPU_SUBTYPE_ARM64_E); - - // TODO: Remove this when the OS knows about armv7s. - if (!strcmp("armv7s", arch_name)) - return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S); - - return NXGetArchInfoFromName(arch_name); -} - -const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype) { - // TODO: Remove this when the OS knows about arm64. - if (cpu_type == CPU_TYPE_ARM64 && cpu_subtype == CPU_SUBTYPE_ARM64_ALL) { - static const NXArchInfo* arm64 = ArchInfo_arm64(cpu_subtype); - return arm64; - } - - if (cpu_type == CPU_TYPE_ARM64 && cpu_subtype == CPU_SUBTYPE_ARM64_E) { - static const NXArchInfo* arm64e = ArchInfo_arm64(cpu_subtype); - return arm64e; - } - - // TODO: Remove this when the OS knows about armv7s. - if (cpu_type == CPU_TYPE_ARM && cpu_subtype == CPU_SUBTYPE_ARM_V7S) { - static const NXArchInfo* armv7s = ArchInfo_armv7s(); - return armv7s; - } - - return NXGetArchInfoFromCpuType(cpu_type, cpu_subtype); -} - -} // namespace google_breakpad +#ifdef __APPLE__ +#include +#include + +#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_16_0) && \ + __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_16_0) || \ + (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && defined(MAC_OS_VERSION_13_0) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_13_0) || \ + (defined(__TV_OS_VERSION_MIN_REQUIRED) && defined(__TV_OS_VERSION_16_0) && \ + __TV_OS_VERSION_MIN_REQUIRED >= __TVOS_16_0) +#define HAS_MACHO_UTILS 1 +#include +#else +#define HAS_MACHO_UTILS 0 +#endif +#endif -#ifndef __APPLE__ namespace { enum Architecture { @@ -145,69 +69,31 @@ enum Architecture { kNumArchitectures }; +struct NamedArchInfo { + const char* name; + ArchInfo info; +}; + // enum Architecture above and kKnownArchitectures below // must be kept in sync. -const NXArchInfo kKnownArchitectures[] = { - { - "i386", - CPU_TYPE_I386, - CPU_SUBTYPE_I386_ALL, - NX_LittleEndian, - "Intel 80x86" - }, - { - "x86_64", - CPU_TYPE_X86_64, - CPU_SUBTYPE_X86_64_ALL, - NX_LittleEndian, - "Intel x86-64" - }, - { - "x86_64h", - CPU_TYPE_X86_64, - CPU_SUBTYPE_X86_64_H, - NX_LittleEndian, - "Intel x86-64h Haswell" - }, - { - "arm", - CPU_TYPE_ARM, - CPU_SUBTYPE_ARM_ALL, - NX_LittleEndian, - "ARM" - }, - { - "arm64", - CPU_TYPE_ARM64, - CPU_SUBTYPE_ARM64_ALL, - NX_LittleEndian, - "ARM64" - }, - { - "arm64e", - CPU_TYPE_ARM64, - CPU_SUBTYPE_ARM64_E, - NX_LittleEndian, - "ARM64e" - }, - { - "ppc", - CPU_TYPE_POWERPC, - CPU_SUBTYPE_POWERPC_ALL, - NX_BigEndian, - "PowerPC" - } -}; +constexpr NamedArchInfo kKnownArchitectures[] = { + {"i386", {CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL}}, + {"x86_64", {CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL}}, + {"x86_64h", {CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H}}, + {"arm", {CPU_TYPE_ARM, CPU_SUBTYPE_ARM_ALL}}, + {"arm64", {CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL}}, + {"arm64e", {CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64E}}, + {"ppc", {CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL}}}; } // namespace -const NXArchInfo *NXGetLocalArchInfo(void) { +ArchInfo GetLocalArchInfo(void) { Architecture arch; #if defined(__i386__) arch = kArch_i386; #elif defined(__x86_64__) arch = kArch_x86_64; -#elif defined(__arm64) +#elif defined(__arm64__) || defined(__aarch64__) arch = kArch_arm64; #elif defined(__arm__) arch = kArch_arm; @@ -216,49 +102,75 @@ const NXArchInfo *NXGetLocalArchInfo(void) { #else #error "Unsupported CPU architecture" #endif - return &kKnownArchitectures[arch]; + return kKnownArchitectures[arch].info; } -const NXArchInfo *NXGetArchInfoFromName(const char *name) { - for (int arch = 0; arch < kNumArchitectures; ++arch) { - if (!strcmp(name, kKnownArchitectures[arch].name)) { - return &kKnownArchitectures[arch]; +#ifdef __APPLE__ + +std::optional GetArchInfoFromName(const char* arch_name) { +#if HAS_MACHO_UTILS + if (__builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, *)) { + cpu_type_t type; + cpu_subtype_t subtype; + if (macho_cpu_type_for_arch_name(arch_name, &type, &subtype)) { + return ArchInfo{type, subtype}; + } + return std::nullopt; + } +#endif +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + const NXArchInfo* info = NXGetArchInfoFromName(arch_name); +#pragma clang diagnostic pop + if (info) { + return ArchInfo{info->cputype, info->cpusubtype}; + } + return std::nullopt; +} + +const char* GetNameFromCPUType(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { +#if HAS_MACHO_UTILS + if (__builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, *)) { + const char* name = macho_arch_name_for_cpu_type(cpu_type, cpu_subtype); + if (name) { + return name; } + return kUnknownArchName; + } +#endif +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + const NXArchInfo* info = NXGetArchInfoFromCpuType(cpu_type, cpu_subtype); +#pragma clang diagnostic pop + if (info) { + return info->name; } - return NULL; + return kUnknownArchName; } -const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype, - cpu_subtype_t cpusubtype) { - const NXArchInfo *candidate = NULL; +#else + +std::optional GetArchInfoFromName(const char* arch_name) { for (int arch = 0; arch < kNumArchitectures; ++arch) { - if (kKnownArchitectures[arch].cputype == cputype) { - if (kKnownArchitectures[arch].cpusubtype == cpusubtype) { - return &kKnownArchitectures[arch]; - } - if (!candidate) { - candidate = &kKnownArchitectures[arch]; - } + if (!strcmp(arch_name, kKnownArchitectures[arch].name)) { + return kKnownArchitectures[arch].info; } } - return candidate; + return std::nullopt; } -struct fat_arch *NXFindBestFatArch(cpu_type_t cputype, - cpu_subtype_t cpusubtype, - struct fat_arch *fat_archs, - uint32_t nfat_archs) { - struct fat_arch *candidate = NULL; - for (uint32_t f = 0; f < nfat_archs; ++f) { - if (fat_archs[f].cputype == cputype) { - if (fat_archs[f].cpusubtype == cpusubtype) { - return &fat_archs[f]; +const char* GetNameFromCPUType(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { + const char* candidate = kUnknownArchName; + for (int arch = 0; arch < kNumArchitectures; ++arch) { + if (kKnownArchitectures[arch].info.cputype == cpu_type) { + if (kKnownArchitectures[arch].info.cpusubtype == cpu_subtype) { + return kKnownArchitectures[arch].name; } - if (!candidate) { - candidate = &fat_archs[f]; + if (!strcmp(candidate, kUnknownArchName)) { + candidate = kKnownArchitectures[arch].name; } } } return candidate; } -#endif // !__APPLE__ +#endif // __APPLE__ diff --git a/src/common/mac/arch_utilities.h b/src/common/mac/arch_utilities.h index 397c1f587..3b036738a 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. // @@ -32,16 +31,26 @@ #ifndef COMMON_MAC_ARCH_UTILITIES_H__ #define COMMON_MAC_ARCH_UTILITIES_H__ -#include +#include -namespace google_breakpad { +#include -// Custom implementation of |NXGetArchInfoFromName| and -// |NXGetArchInfoFromCpuType| that handle newer CPU on older OSes. -const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name); -const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype); +static constexpr const char* kUnknownArchName = ""; -} // namespace google_breakpad +struct ArchInfo { + cpu_type_t cputype; + cpu_subtype_t cpusubtype; +}; + +// Returns architecture info if `arch_name` corresponds to a valid, known +// architecture, and std::nullopt otherwise. +std::optional GetArchInfoFromName(const char* arch_name); + +// Returns the name of the architecture specified by `cpu_type` and +// `cpu_subtype`, or `kUnknownArchName` if it's unknown or invalid. +const char* GetNameFromCPUType(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); + +// Returns the architecture of the machine this code is running on. +ArchInfo GetLocalArchInfo(); #endif // COMMON_MAC_ARCH_UTILITIES_H__ diff --git a/src/common/mac/bootstrap_compat.cc b/src/common/mac/bootstrap_compat.cc index d875d95b5..408589ba9 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/mac/bootstrap_compat.h" namespace breakpad { diff --git a/src/common/mac/bootstrap_compat.h b/src/common/mac/bootstrap_compat.h index 8ca7357c3..b57d90700 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 b7bbc0b95..c4c7e6178 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 672323c86..0e2c094f4 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. // @@ -33,6 +32,10 @@ // dump_syms.cc: Create a symbol file for use with minidumps +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/mac/dump_syms.h" #include @@ -46,6 +49,7 @@ #include #include +#include #include #include #include @@ -74,18 +78,17 @@ #define CPU_TYPE_ARM64 (static_cast(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; using google_breakpad::StabsReader; using google_breakpad::StabsToModule; -using google_breakpad::scoped_ptr; using std::make_pair; using std::pair; using std::string; @@ -106,7 +109,7 @@ vector list_directory(const string& directory) { path += '/'; } - struct dirent* entry = NULL; + struct dirent* entry = nullptr; while ((entry = readdir(dir))) { if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { entries.push_back(path + entry->d_name); @@ -121,6 +124,7 @@ vector list_directory(const string& directory) { namespace google_breakpad { 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 +132,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 +144,31 @@ bool DumpSymbols::Read(const string& filename) { const vector 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 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,16 +186,22 @@ 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; } @@ -209,11 +221,10 @@ bool DumpSymbols::Read(const string& filename) { return true; } -bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype) { +bool DumpSymbols::SetArchitecture(const ArchInfo& info) { // Find the best match for the architecture the user requested. - const SuperFatArch* best_match = FindBestMatchForArchitecture( - cpu_type, cpu_subtype); + const SuperFatArch* best_match = + FindBestMatchForArchitecture(info.cputype, info.cpusubtype); if (!best_match) return false; // Record the selected object file. @@ -221,73 +232,60 @@ bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type, return true; } -bool DumpSymbols::SetArchitecture(const std::string& arch_name) { - bool arch_set = false; - const NXArchInfo* arch_info = - google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str()); - if (arch_info) { - arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype); - } - return arch_set; -} SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( - cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { - // Check if all the object files can be converted to struct fat_arch. - bool can_convert_to_fat_arch = true; - vector fat_arch_vector; - for (vector::const_iterator it = object_files_.begin(); - it != object_files_.end(); - ++it) { - struct fat_arch arch; - bool success = it->ConvertToFatArch(&arch); - if (!success) { - can_convert_to_fat_arch = false; - break; - } - fat_arch_vector.push_back(arch); - } - - // 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 - = NXFindBestFatArch(cpu_type, cpu_subtype, &fat_arch_vector[0], - static_cast(fat_arch_vector.size())); - - for (size_t i = 0; i < fat_arch_vector.size(); ++i) { - if (best_match == &fat_arch_vector[i]) - return &object_files_[i]; + cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype) { + SuperFatArch* closest_match = nullptr; + for (auto& object_file : object_files_) { + if (static_cast(object_file.cputype) == cpu_type) { + // If there's an exact match, return it directly. + if ((static_cast(object_file.cpusubtype) & + ~CPU_SUBTYPE_MASK) == (cpu_subtype & ~CPU_SUBTYPE_MASK)) { + return &object_file; + } + // Otherwise, hold on to this as the closest match since at least the CPU + // type matches. + if (!closest_match) { + closest_match = &object_file; + } } - assert(best_match == NULL); - return NULL; } - - // Check for an exact match with cpu_type and cpu_subtype. - for (vector::iterator it = object_files_.begin(); - it != object_files_.end(); - ++it) { - if (static_cast(it->cputype) == cpu_type && - static_cast(it->cpusubtype) == cpu_subtype) - return &*it; + // No exact match found. + fprintf(stderr, + "Failed to find an exact match for an object file with cpu " + "type: %d and cpu subtype: %d.\n", + cpu_type, cpu_subtype); + if (closest_match) { + fprintf(stderr, "Using %s as the closest match.\n", + GetNameFromCPUType(closest_match->cputype, + closest_match->cpusubtype)); + return closest_match; } + return nullptr; +} - // No exact match found. - // TODO(erikchen): If it becomes necessary, we can copy the implementation of - // 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); - return NULL; +void DumpSymbols::SetReportWarnings(bool report_warnings) { + report_warnings_ = report_warnings; } string DumpSymbols::Identifier() { - FileID file_id(object_filename_.c_str()); + std::unique_ptr 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]; + std::unique_ptr 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,63 +300,71 @@ 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(dwarf2reader::ByteReader* reader) : + DumperRangesHandler(ByteReader* reader) : reader_(reader) { } bool ReadRanges( - enum dwarf2reader::DwarfForm form, uint64_t data, - dwarf2reader::RangeListReader::CURangesInfo* cu_info, + enum DwarfForm form, uint64_t data, + RangeListReader::CURangesInfo* cu_info, vector* ranges) { DwarfRangeListHandler handler(ranges); - dwarf2reader::RangeListReader range_list_reader(reader_, cu_info, + RangeListReader range_list_reader(reader_, cu_info, &handler); return range_list_reader.ReadRanges(form, data); } private: - 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, + 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* lines) { - DwarfLineToModule handler(module, compilation_dir_, lines); - dwarf2reader::LineInfo parser(program, length, byte_reader_, - nullptr, 0, nullptr, 0, &handler); + Module* module, + vector* lines, + std::map* files) { + DwarfLineToModule handler(module, compilation_dir_, lines, files); + 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_; // WEAK + ByteReader* byte_reader_; // WEAK }; -bool DumpSymbols::CreateEmptyModule(scoped_ptr& module) { +bool DumpSymbols::CreateEmptyModule(std::unique_ptr& module) { // Select an object file, if SetArchitecture hasn't been called to set one // explicitly. if (!selected_object_file_) { @@ -367,8 +373,8 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr& module) { selected_object_file_ = &object_files_[0]; else { // Look for an object file whose architecture matches our own. - const NXArchInfo* local_arch = NXGetLocalArchInfo(); - if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) { + ArchInfo local_arch = GetLocalArchInfo(); + if (!SetArchitecture(local_arch)) { fprintf(stderr, "%s: object file contains more than one" " architecture, none of which match the current" " architecture; specify an architecture explicitly" @@ -383,11 +389,16 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr& 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 = - google_breakpad::BreakpadGetArchInfoFromCpuType( - selected_object_file_->cputype, selected_object_file_->cpusubtype); + const char* selected_arch_name = GetNameFromCPUType( + selected_object_file_->cputype, selected_object_file_->cpusubtype); + + // 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 (strcmp(selected_arch_name, kUnknownArchName) == 0) { + return false; + } - const char* selected_arch_name = selected_arch_info->name; if (strcmp(selected_arch_name, "i386") == 0) selected_arch_name = "x86"; @@ -396,41 +407,96 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr& module) { selected_object_name_ = object_filename_; if (object_files_.size() > 1) { selected_object_name_ += ", architecture "; - selected_object_name_ + selected_arch_name; + selected_object_name_ += selected_arch_name; } // Compute a module name, to appear in the MODULE record. - string module_name = google_breakpad::BaseName(object_filename_); + string module_name; + if (!module_name_.empty()) { + module_name = module_name_; + } else { + module_name = google_breakpad::BaseName(object_filename_); + } // Choose an identifier string, to appear in the MODULE record. string identifier = Identifier(); if (identifier.empty()) return false; - identifier += "0"; // Create a module to hold the debugging information. - module.reset(new Module(module_name, - "mac", - selected_arch_name, - identifier)); + module.reset(new Module(module_name, "mac", selected_arch_name, identifier, + "", enable_multiple_, prefer_extern_name_)); return true; } +void DumpSymbols::StartProcessSplitDwarf( + google_breakpad::CompilationUnit* reader, + Module* module, + google_breakpad::Endianness endianness, + bool handle_inter_cu_refs, + bool handle_inline) const { + std::string split_file; + google_breakpad::SectionMap split_sections; + google_breakpad::ByteReader split_byte_reader(endianness); + uint64_t cu_offset = 0; + if (reader->ProcessSplitDwarf(split_file, split_sections, split_byte_reader, + cu_offset)) + return; + DwarfCUToModule::FileContext file_context(split_file, module, + handle_inter_cu_refs); + for (auto section : split_sections) + file_context.AddSectionToSectionMap(section.first, section.second.first, + section.second.second); + // Because DWP/DWO file doesn't have .debug_addr/.debug_line/.debug_line_str, + // its debug info will refer to .debug_addr/.debug_line in the main binary. + if (file_context.section_map().find(".debug_addr") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_addr", reader->GetAddrBuffer(), + reader->GetAddrBufferLen()); + if (file_context.section_map().find(".debug_line") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line", reader->GetLineBuffer(), + reader->GetLineBufferLen()); + if (file_context.section_map().find(".debug_line_str") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line_str", + reader->GetLineStrBuffer(), + reader->GetLineStrBufferLen()); + DumperRangesHandler ranges_handler(&split_byte_reader); + DumperLineToModule line_to_module(&split_byte_reader); + DwarfCUToModule::WarningReporter reporter(split_file, cu_offset); + DwarfCUToModule root_handler( + &file_context, &line_to_module, &ranges_handler, &reporter, handle_inline, + reader->GetLowPC(), reader->GetAddrBase(), reader->HasSourceLineInfo(), + reader->GetSourceLineOffset()); + google_breakpad::DIEDispatcher die_dispatcher(&root_handler); + google_breakpad::CompilationUnit split_reader( + split_file, file_context.section_map(), cu_offset, &split_byte_reader, + &die_dispatcher); + split_reader.SetSplitDwarf(reader->GetAddrBase(), reader->GetDWOID()); + split_reader.Start(); + // Normally, it won't happen unless we have transitive reference. + if (split_reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&split_reader, module, endianness, + handle_inter_cu_refs, handle_inline); + } +} + 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); + google_breakpad::Endianness endianness = + macho_reader.big_endian() ? ENDIANNESS_BIG : ENDIANNESS_LITTLE; + ByteReader byte_reader(endianness); // 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( @@ -440,7 +506,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()) { @@ -459,23 +525,36 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module* module, // Walk the __debug_info section, one compilation unit at a time. uint64_t debug_info_length = debug_info_section.second; + bool handle_inline = symbol_data_ & INLINES; for (uint64_t offset = 0; offset < debug_info_length;) { // Make a handler for the root DIE that populates MODULE with the // debug info. - DwarfCUToModule::WarningReporter reporter(selected_object_name_, - offset); + std::unique_ptr reporter; + if (report_warnings_) { + reporter = std::make_unique( + selected_object_name_, offset); + } else { + reporter = std::make_unique( + selected_object_name_, offset); + } DwarfCUToModule root_handler(&file_context, &line_to_module, - &ranges_handler, &reporter); + &ranges_handler, reporter.get(), + handle_inline); // 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, &die_dispatcher); // Process the entire compilation unit; get the offset of the next. offset += dwarf_reader.Start(); + // Start to process split dwarf file. + if (dwarf_reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&dwarf_reader, module, endianness, + handle_inter_cu_refs, handle_inline); + } } } @@ -500,16 +579,14 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module* module, register_names = DwarfCFIToModule::RegisterNames::ARM64(); break; default: { - 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()); - if (arch) - fprintf(stderr, "architecture '%s'", arch->name); - else - fprintf(stderr, "architecture %d,%d", - macho_reader.cpu_type(), macho_reader.cpu_subtype()); - fprintf(stderr, " to Breakpad symbol file: no register name table\n"); + const char* arch_name = GetNameFromCPUType(macho_reader.cpu_type(), + macho_reader.cpu_subtype()); + fprintf( + stderr, + "%s: cannot convert DWARF call frame information for architecture " + "'%s' (%d, %d) to Breakpad symbol file: no register name table\n", + selected_object_name_.c_str(), arch_name, macho_reader.cpu_type(), + macho_reader.cpu_subtype()); return false; } } @@ -522,18 +599,18 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module* module, 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(); @@ -576,7 +653,7 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment& segment) { 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()) { @@ -588,10 +665,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()) { @@ -622,7 +699,7 @@ bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer& entries, } bool DumpSymbols::ReadSymbolData(Module** out_module) { - scoped_ptr module; + std::unique_ptr module; if (!CreateEmptyModule(module)) return false; @@ -647,23 +724,11 @@ 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) { - scoped_ptr module; + std::unique_ptr module; if (!CreateEmptyModule(module)) return false; diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h index daebf8766..8afd0ac5a 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. // @@ -39,11 +38,14 @@ #include #include +#include #include #include #include #include "common/byte_cursor.h" +#include "common/dwarf/dwarf2reader.h" +#include "common/mac/arch_utilities.h" #include "common/mac/macho_reader.h" #include "common/mac/super_fat_arch.h" #include "common/module.h" @@ -54,44 +56,57 @@ 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, + const std::string& module_name = "", + bool prefer_extern_name = 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), + module_name_(module_name), + prefer_extern_name_(prefer_extern_name), + report_warnings_(true) {} + ~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. + // the name of a fat file, a Mach-O file, or a dSYM bundle containing either + // of the above. + // + // If |module_name_| is empty, uses the basename of |filename| as the module + // name. Otherwise, uses |module_name_| as the module name. + // + // On success, return true; if there is a problem reading + // |filename|, report it and return false. bool Read(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 - // true. Otherwise, return false, and leave this dumper's selected - // architecture unchanged. + // 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 `info`, then select that + // object file for dumping, and return true. Otherwise, return false, and + // leave this dumper's selected architecture unchanged. // // By default, if this dumper's file contains only one object file, then // 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(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); + bool SetArchitecture(const ArchInfo& info); - // If this dumper's file includes an object file for |arch_name|, then select - // that object file for dumping, and return true. Otherwise, return false, - // and leave this dumper's selected architecture unchanged. - // - // By default, if this dumper's file contains only one object file, then - // 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); + // Set whether or not to report DWARF warnings + void SetReportWarnings(bool report_warnings); // Return a pointer to an array of SuperFatArch structures describing the // object files contained in this dumper's file. Set *|count| to the number @@ -104,24 +119,22 @@ class DumpSymbols { *count = object_files_.size(); if (object_files_.size() > 0) return &object_files_[0]; - return NULL; + return nullptr; } - // 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); - // 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,12 +146,15 @@ 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); + bool CreateEmptyModule(std::unique_ptr& module); + + // Process the split dwarf file referenced by reader. + void StartProcessSplitDwarf(google_breakpad::CompilationUnit* reader, + Module* module, + google_breakpad::Endianness endianness, + bool handle_inter_cu_refs, + bool handle_inline) const; // Read debugging information from |dwarf_sections|, which was taken from // |macho_reader|, and add it to |module|. @@ -163,19 +179,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 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 @@ -191,6 +210,28 @@ class DumpSymbols { // 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_; + + // If non-empty, used as the module name. Otherwise, the basename of + // |object_filename_| is used as the module name. + const std::string module_name_; + + // If a Function and an Extern share the same address but have a different + // name, prefer the name of the Extern. + // + // Use this when dumping Mach-O .dSYMs built with -gmlt (Minimum Line Tables), + // as the Function's fully-qualified name will only be present in the STABS + // (which are placed in the Extern), not in the DWARF symbols (which are + // placed in the Function). + bool prefer_extern_name_; + + // Whether or not to report warnings + bool report_warnings_; }; } // namespace google_breakpad diff --git a/src/common/mac/encoding_util.h b/src/common/mac/encoding_util.h index 6495a7427..3028f2e9d 100644 --- a/src/common/mac/encoding_util.h +++ b/src/common/mac/encoding_util.h @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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/encoding_util.m b/src/common/mac/encoding_util.m index 86d70fb6e..5cf84fc5d 100644 --- a/src/common/mac/encoding_util.m +++ b/src/common/mac/encoding_util.m @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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/file_id.cc b/src/common/mac/file_id.cc index 4661d5d62..f080a2114 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,46 @@ // // Author: Dan Waylonis +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "common/mac/file_id.h" + #include #include #include -#include -#include "common/mac/file_id.h" +#include + #include "common/mac/macho_id.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(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)) + std::unique_ptr 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 +95,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 5d60e84c9..a14cd1377 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 #include +#include 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 245be8265..3f86af873 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -35,7 +38,7 @@ namespace google_breakpad { void LaunchReporter(const char *reporter_executable_path, const char *config_file_path) { - const char* argv[] = { reporter_executable_path, config_file_path, NULL }; + const char* argv[] = { reporter_executable_path, config_file_path, nullptr }; // Launch the reporter pid_t pid = fork(); diff --git a/src/common/mac/launch_reporter.h b/src/common/mac/launch_reporter.h index 4531123c2..0cf73547c 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 3cf1d4b5f..aba3b306e 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. // @@ -34,14 +33,14 @@ // Author: Dan Waylonis +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include -#include #include -#include -#include -#include #include "common/mac/macho_id.h" #include "common/mac/macho_walker.h" @@ -54,73 +53,18 @@ 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) { - 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) { + : memory_(0), memory_size_(0), md5_context_(), update_function_(nullptr) { 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_(nullptr) {} -// 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; - } - - // 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; - } -} +MachoID::~MachoID() {} void MachoID::UpdateMD5(unsigned char* bytes, size_t size) { MD5Update(&md5_context_, bytes, static_cast(size)); @@ -169,59 +113,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; @@ -346,24 +237,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 e8874c37c..b9cbdb00b 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. // @@ -46,7 +45,7 @@ namespace MacFileUtilities { class MachoID { public: MachoID(const char* path); - MachoID(const char* path, void* memory, size_t size); + 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 @@ -80,10 +66,6 @@ class MachoID { // 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); - // Update the MD5 value by examining |size| |bytes| and applying the algorithm // to each byte. void UpdateMD5(unsigned char* bytes, size_t size); @@ -103,10 +85,6 @@ class MachoID { 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); - // File path char path_[PATH_MAX]; @@ -116,9 +94,6 @@ class MachoID { // 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 b42506cce..0f2f7bc3f 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. // @@ -32,6 +31,10 @@ // macho_reader.cc: Implementation of google_breakpad::Mach_O::FatReader and // google_breakpad::Mach_O::Reader. See macho_reader.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/mac/macho_reader.h" #include @@ -365,7 +368,7 @@ bool Reader::WalkLoadCommands(Reader::LoadCommandHandler* handler) const { // out. To help us handle this special case properly, give such // segments' contents NULL starting and ending pointers. if (segment.fileoff == 0 && segment.filesize == 0) { - segment.contents.start = segment.contents.end = NULL; + segment.contents.start = segment.contents.end = nullptr; } else { segment.contents.start = buffer_.start + segment.fileoff; segment.contents.end = segment.contents.start + segment.filesize; @@ -504,26 +507,35 @@ bool Reader::WalkSegmentSections(const Segment& segment, if (section_type == S_ZEROFILL || section_type == S_THREAD_LOCAL_ZEROFILL || section_type == S_GB_ZEROFILL) { // Zero-fill sections have a size, but no contents. - section.contents.start = section.contents.end = NULL; - } else if (segment.contents.start == NULL && - segment.contents.end == NULL) { + section.contents.start = section.contents.end = nullptr; + } else if (segment.contents.start == nullptr && + segment.contents.end == nullptr) { // Mach-O files in .dSYM bundles have the contents of the loaded // segments removed, and their file offsets and file sizes zeroed // out. However, the sections within those segments still have // non-zero sizes. There's no reason to call MisplacedSectionData in // this case; the caller may just need the section's load // address. But do set the contents' limits to NULL, for safety. - section.contents.start = section.contents.end = NULL; + section.contents.start = section.contents.end = nullptr; } else { 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 = nullptr; + } + } 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; diff --git a/src/common/mac/macho_reader.h b/src/common/mac/macho_reader.h index 02762c55c..47134b03a 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. // @@ -134,7 +133,7 @@ class FatReader { *count = object_files_.size(); if (object_files_.size() > 0) return &object_files_[0]; - return NULL; + return nullptr; } private: diff --git a/src/common/mac/macho_reader_unittest.cc b/src/common/mac/macho_reader_unittest.cc index dccda4e7b..7b629d1a0 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. // @@ -32,6 +31,12 @@ // macho_reader_unittest.cc: Unit tests for google_breakpad::Mach_O::FatReader // and google_breakpad::Mach_O::Reader. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + #include #include #include @@ -496,7 +501,7 @@ class WithConfiguration { WithConfiguration* saved_; }; -WithConfiguration* WithConfiguration::current_ = NULL; +WithConfiguration* WithConfiguration::current_ = nullptr; // A test_assembler::Section with a size that we can cite. The start(), // Here() and Mark() member functions of a SizedSection always represent @@ -1529,6 +1534,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'); @@ -1592,7 +1642,7 @@ TEST_F(LoadCommand, ZappedSegment) { Segment actual_segment; EXPECT_TRUE(reader.FindSegment("zapped", &actual_segment)); - ByteBuffer zapped_extent(NULL, 0); + ByteBuffer zapped_extent(nullptr, 0); EXPECT_CALL(section_handler, HandleSection(MatchSection(false, "twitching", "zapped", 0x696d83cc, 0, 0x93b3bd42, @@ -1658,7 +1708,7 @@ TEST_F(LoadCommand, MapSegmentSections) { MatchSection(true, "cara cara", "thorax", 0x04d462e2)); ASSERT_TRUE(section_map.find("sixteenprecisely") != section_map.end()); - ByteBuffer sixteenprecisely_contents(NULL, 0); + ByteBuffer sixteenprecisely_contents(nullptr, 0); EXPECT_THAT(section_map["sixteenprecisely"], MatchSection(true, "sixteenprecisely", "thorax", 0x04d462e2 + 7, 12, S_ZEROFILL, diff --git a/src/common/mac/macho_utilities.cc b/src/common/mac/macho_utilities.cc index f56fe768c..113e8d3fa 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. // @@ -31,6 +30,10 @@ // // Author: Dave Camp +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/mac/byteswap.h" #include "common/mac/macho_utilities.h" diff --git a/src/common/mac/macho_utilities.h b/src/common/mac/macho_utilities.h index 00563a77c..470cb5d22 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 a42128b80..c047da998 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. // @@ -33,28 +32,32 @@ // // Author: Dan Waylonis +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include -#include #include #include #include #include +#include "common/mac/arch_utilities.h" #include "common/mac/byteswap.h" -#include "common/mac/macho_walker.h" #include "common/mac/macho_utilities.h" +#include "common/mac/macho_walker.h" namespace MacFileUtilities { MachoWalker::MachoWalker(const char* path, LoadCommandCallback callback, void* context) : file_(-1), - memory_(NULL), + memory_(nullptr), memory_size_(0), callback_(callback), callback_context_(context), - current_header_(NULL), + current_header_(nullptr), current_header_size_(0), current_header_offset_(0) { file_ = open(path, O_RDONLY); @@ -67,7 +70,7 @@ MachoWalker::MachoWalker(void* memory, size_t size, memory_size_(size), callback_(callback), callback_context_(context), - current_header_(NULL), + current_header_(nullptr), current_header_size_(0), current_header_offset_(0) { } @@ -82,9 +85,8 @@ 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(); - assert(arch); - valid_cpu_type = arch->cputype; + ArchInfo arch = GetLocalArchInfo(); + valid_cpu_type = arch.cputype; valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE; } off_t offset; @@ -219,7 +221,7 @@ bool MachoWalker::WalkHeaderAtOffset(off_t offset) { current_header_offset_ = offset; offset += current_header_size_; bool result = WalkHeaderCore(offset, header.ncmds, swap); - current_header_ = NULL; + current_header_ = nullptr; current_header_size_ = 0; current_header_offset_ = 0; return result; @@ -239,7 +241,7 @@ bool MachoWalker::WalkHeader64AtOffset(off_t offset) { current_header_offset_ = offset; offset += current_header_size_; bool result = WalkHeaderCore(offset, header.ncmds, swap); - current_header_ = NULL; + current_header_ = nullptr; current_header_size_ = 0; current_header_offset_ = 0; return result; diff --git a/src/common/mac/macho_walker.h b/src/common/mac/macho_walker.h index 168f30e64..13e8232e9 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. // diff --git a/src/common/mac/minidump_upload.m b/src/common/mac/minidump_upload.m index 1fe4f213f..d8e2b24a6 100644 --- a/src/common/mac/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. // diff --git a/src/common/mac/scoped_task_suspend-inl.h b/src/common/mac/scoped_task_suspend-inl.h index d6d1bef97..a4957d7a7 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 cb1554037..3b83351f4 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/scoped_ptr.h" #include "common/mac/string_utilities.h" diff --git a/src/common/mac/string_utilities.h b/src/common/mac/string_utilities.h index e87304c18..de282a941 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. // diff --git a/src/common/mac/super_fat_arch.h b/src/common/mac/super_fat_arch.h index d7fa018ae..046fe166a 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. // diff --git a/src/common/mac/testing/GTMSenTestCase.h b/src/common/mac/testing/GTMSenTestCase.h index ce3d9022c..cfef3ef14 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 162f01e97..eb9351bf3 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 14bb3f7bd..741a1c3b8 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. // @@ -30,16 +29,11 @@ #ifndef BREAKPAD_COMMON_MACROS_H_ #define BREAKPAD_COMMON_MACROS_H_ -// Ensure that this macro definition stays in a private header file: clang -// suggests the first macro expanding to [[clang::fallthrough]] in its -// diagnostics, so if BP_FALLTHROUGH is visible in code depending on breakpad, -// clang would suggest BP_FALLTHROUGH for code depending on breakpad, instead of -// the client code's own fallthrough macro. -// TODO(thakis): Once everyone uses C++17, use its [[fallthrough]] instead. -#if defined(__clang__) -#define BP_FALLTHROUGH [[clang::fallthrough]] -#else -#define BP_FALLTHROUGH +#include + +// TODO: Delete when we require C++23. +#ifndef unreachable +#define unreachable() __builtin_unreachable() #endif #endif // BREAKPAD_COMMON_MACROS_H_ diff --git a/src/common/md5.cc b/src/common/md5.cc index b6e710da9..86298f4de 100644 --- a/src/common/md5.cc +++ b/src/common/md5.cc @@ -13,6 +13,10 @@ * will fill a supplied 16-byte array with the digest. */ +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "common/md5.h" diff --git a/src/common/md5.h b/src/common/md5.h index 2ab0ab95a..9d1f59b52 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 #include namespace google_breakpad { diff --git a/src/common/memory_allocator.h b/src/common/memory_allocator.h index 69055a158..e6dc4e9f2 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. // @@ -30,10 +29,11 @@ #ifndef GOOGLE_BREAKPAD_COMMON_MEMORY_ALLOCATOR_H_ #define GOOGLE_BREAKPAD_COMMON_MEMORY_ALLOCATOR_H_ +#include #include #include -#include #include +#include #include #include @@ -61,8 +61,8 @@ class PageAllocator { public: PageAllocator() : page_size_(getpagesize()), - last_(NULL), - current_page_(NULL), + last_(nullptr), + current_page_(nullptr), page_offset_(0), pages_allocated_(0) { } @@ -71,16 +71,24 @@ class PageAllocator { FreeAll(); } + // Rounds up `offset` to the closest properly aligned value. `alignment` must + // be positive and a power of two. + template + static T AlignUp(T offset, size_t alignment) { + assert(alignment > 0 && ((alignment - 1) & alignment) == 0); + return (offset + (alignment - 1)) & ~(alignment - 1); + } + void* Alloc(size_t bytes) { if (!bytes) - return NULL; + return nullptr; if (current_page_ && page_size_ - page_offset_ >= bytes) { uint8_t* const ret = current_page_ + page_offset_; page_offset_ += bytes; if (page_offset_ == page_size_) { page_offset_ = 0; - current_page_ = NULL; + current_page_ = nullptr; } return ret; @@ -90,12 +98,12 @@ class PageAllocator { (bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_; uint8_t* const ret = GetNPages(pages); if (!ret) - return NULL; + return nullptr; page_offset_ = (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) % page_size_; - current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL; + current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : nullptr; return ret + sizeof(PageHeader); } @@ -116,10 +124,10 @@ class PageAllocator { private: uint8_t* GetNPages(size_t num_pages) { - void* a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, + void* a = sys_mmap(nullptr, page_size_ * num_pages, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (a == MAP_FAILED) - return NULL; + return nullptr; #if defined(MEMORY_SANITIZER) // We need to indicate to MSan that memory allocated through sys_mmap is @@ -160,12 +168,15 @@ class PageAllocator { // Wrapper to use with STL containers template -struct PageStdAllocator : public std::allocator { - typedef typename std::allocator::pointer pointer; - typedef typename std::allocator::size_type size_type; +struct PageStdAllocator { + using AllocatorTraits = std::allocator_traits>; + 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), + stackdata_(nullptr), stackdata_size_(0) {} diff --git a/src/common/memory_allocator_unittest.cc b/src/common/memory_allocator_unittest.cc index 5803b90d5..07bce6f85 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. // @@ -27,6 +26,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + +#include + #include "breakpad_googletest_includes.h" #include "common/memory_allocator.h" @@ -34,7 +41,7 @@ using namespace google_breakpad; namespace { typedef testing::Test PageAllocatorTest; -} +} // namespace TEST(PageAllocatorTest, Setup) { PageAllocator allocator; @@ -47,7 +54,7 @@ TEST(PageAllocatorTest, SmallObjects) { EXPECT_EQ(0U, allocator.pages_allocated()); for (unsigned i = 1; i < 1024; ++i) { uint8_t* p = reinterpret_cast(allocator.Alloc(i)); - ASSERT_FALSE(p == NULL); + ASSERT_FALSE(p == nullptr); memset(p, 0, i); } } @@ -57,15 +64,44 @@ TEST(PageAllocatorTest, LargeObject) { EXPECT_EQ(0U, allocator.pages_allocated()); uint8_t* p = reinterpret_cast(allocator.Alloc(10000)); - ASSERT_FALSE(p == NULL); + ASSERT_FALSE(p == nullptr); EXPECT_EQ(3U, allocator.pages_allocated()); for (unsigned i = 1; i < 10; ++i) { uint8_t* p = reinterpret_cast(allocator.Alloc(i)); - ASSERT_FALSE(p == NULL); + ASSERT_FALSE(p == nullptr); memset(p, 0, i); } } +TEST(PageAllocatorTest, AlignUp) { + EXPECT_EQ(PageAllocator::AlignUp(0x11U, 1), 0x11U); + EXPECT_EQ(PageAllocator::AlignUp(0x11U, 2), 0x12U); + EXPECT_EQ(PageAllocator::AlignUp(0x13U, 2), 0x14U); + EXPECT_EQ(PageAllocator::AlignUp(0x11U, 4), 0x14U); + EXPECT_EQ(PageAllocator::AlignUp(0x15U, 4), 0x18U); + EXPECT_EQ(PageAllocator::AlignUp(0x11U, 8), 0x18U); + EXPECT_EQ(PageAllocator::AlignUp(0x19U, 8), 0x20U); + + // Ensure large 64 bit values are not truncated. + constexpr uint64_t kUnalignedU64 = 0x8000'0000'0000'0011; + constexpr uint64_t kAligned8U64 = 0x8000'0000'0000'0018; + static_assert(kUnalignedU64 > std::numeric_limits::max()); + static_assert(kAligned8U64 > std::numeric_limits::max()); + EXPECT_EQ(PageAllocator::AlignUp(kUnalignedU64, 8), kAligned8U64); +} + +namespace { +typedef testing::Test PageAllocatorDeathTest; +} // namespace + +TEST(PageAllocatorDeathTest, AlignUpBad0) { + EXPECT_DEBUG_DEATH({ PageAllocator::AlignUp(0x11U, 0); }, ""); +} + +TEST(PageAllocatorDeathTest, AlignUpBad9) { + EXPECT_DEBUG_DEATH({ PageAllocator::AlignUp(0x11U, 9); }, ""); +} + namespace { typedef testing::Test WastefulVectorTest; } diff --git a/src/common/memory_range.h b/src/common/memory_range.h index 41dd2da62..3dda169e7 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. // @@ -47,7 +46,7 @@ namespace google_breakpad { // in a crashed environment. class MemoryRange { public: - MemoryRange() : data_(NULL), length_(0) {} + MemoryRange() : data_(nullptr), length_(0) {} MemoryRange(const void* data, size_t length) { Set(data, length); @@ -61,7 +60,7 @@ class MemoryRange { // Resets to an empty range. void Reset() { - data_ = NULL; + data_ = nullptr; length_ = 0; } @@ -88,7 +87,7 @@ class MemoryRange { // |sub_offset| bytes of this memory range, or NULL if the subrange // is out of bounds. const void* GetData(size_t sub_offset, size_t sub_length) const { - return Covers(sub_offset, sub_length) ? (data_ + sub_offset) : NULL; + return Covers(sub_offset, sub_length) ? (data_ + sub_offset) : nullptr; } // Same as the two-argument version of GetData() but uses sizeof(DataType) diff --git a/src/common/memory_range_unittest.cc b/src/common/memory_range_unittest.cc index f6cf8c8b2..0e19daaed 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. // @@ -29,6 +28,10 @@ // memory_range_unittest.cc: Unit tests for google_breakpad::MemoryRange. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "common/memory_range.h" @@ -81,11 +84,11 @@ const struct { { 0, 4, 9, kBufferPointer + 36 }, { kBufferSize - 1, 1, 0, kBufferPointer + kBufferSize - 1 }, // Invalid array elemenets - { 0, 1, kBufferSize, NULL }, - { 0, 4, 10, NULL }, - { kBufferSize - 1, 1, 1, NULL }, - { kBufferSize - 1, 2, 0, NULL }, - { kBufferSize, 1, 0, NULL }, + { 0, 1, kBufferSize, nullptr }, + { 0, 4, 10, nullptr }, + { kBufferSize - 1, 1, 1, nullptr }, + { kBufferSize - 1, 2, 0, nullptr }, + { kBufferSize, 1, 0, nullptr }, }; const size_t kNumElements = sizeof(kElements) / sizeof(kElements[0]); @@ -93,7 +96,7 @@ const size_t kNumElements = sizeof(kElements) / sizeof(kElements[0]); TEST(MemoryRangeTest, DefaultConstructor) { MemoryRange range; - EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(nullptr, range.data()); EXPECT_EQ(0U, range.length()); } @@ -106,7 +109,7 @@ TEST(MemoryRangeTest, ConstructorWithDataAndLength) { TEST(MemoryRangeTest, Reset) { MemoryRange range; range.Reset(); - EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(nullptr, range.data()); EXPECT_EQ(0U, range.length()); range.Set(kBuffer, kBufferSize); @@ -114,7 +117,7 @@ TEST(MemoryRangeTest, Reset) { EXPECT_EQ(kBufferSize, range.length()); range.Reset(); - EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(nullptr, range.data()); EXPECT_EQ(0U, range.length()); } @@ -124,15 +127,15 @@ TEST(MemoryRangeTest, Set) { EXPECT_EQ(kBufferPointer, range.data()); EXPECT_EQ(kBufferSize, range.length()); - range.Set(NULL, 0); - EXPECT_EQ(NULL, range.data()); + range.Set(nullptr, 0); + EXPECT_EQ(nullptr, range.data()); EXPECT_EQ(0U, range.length()); } TEST(MemoryRangeTest, SubrangeOfEmptyMemoryRange) { MemoryRange range; MemoryRange subrange = range.Subrange(0, 10); - EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(nullptr, subrange.data()); EXPECT_EQ(0U, subrange.length()); } @@ -154,8 +157,8 @@ TEST(MemoryRangeTest, SubrangeAndGetData) { EXPECT_EQ(sub_length, subrange.length()); } else { EXPECT_FALSE(range.Covers(sub_offset, sub_length)); - EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length)); - EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(nullptr, range.GetData(sub_offset, sub_length)); + EXPECT_EQ(nullptr, subrange.data()); EXPECT_EQ(0U, subrange.length()); } } diff --git a/src/common/minidump_type_helper.h b/src/common/minidump_type_helper.h index 5a7d5a6a8..04bafe7e0 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 f70ae203c..c55bb6cf9 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. // @@ -31,31 +30,92 @@ // module.cc: Implement google_breakpad::Module. See module.h. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/module.h" +#include "common/string_view.h" #include #include #include #include +#include +#include #include +#include #include 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 == "") { + 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*/, + bool prefer_extern_name /* = false*/) + : name_(name), + os_(os), + architecture_(architecture), + id_(id), + code_id_(code_id), + load_address_(0), + enable_multiple_field_(enable_multiple_field), + prefer_extern_name_(prefer_extern_name) {} Module::~Module() { for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) @@ -64,12 +124,6 @@ Module::~Module() { it != functions_.end(); ++it) { delete *it; } - for (vector::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 +134,13 @@ void Module::SetAddressRanges(const vector& 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 +155,29 @@ void Module::AddFunction(Function* function) { it_ext = externs_.find(&arm_thumb_ext); } if (it_ext != externs_.end()) { - delete *it_ext; + Extern* found_ext = it_ext->get(); + bool name_mismatch = found_ext->name != function->name; + if (enable_multiple_field_) { + bool is_multiple_based_on_name; + // In the case of a .dSYM built with -gmlt, the external name will be the + // fully-qualified symbol name, but the function name will be the partial + // name (or omitted). + // + // Don't mark multiple in this case. + if (name_mismatch && + (function->name == "" || + found_ext->name.find(function->name.str()) != string::npos)) { + is_multiple_based_on_name = false; + } else { + is_multiple_based_on_name = name_mismatch; + } + // If the PUBLIC is for the same symbol as the FUNC, don't mark multiple. + function->is_multiple |= + is_multiple_based_on_name || found_ext->is_multiple; + } + if (name_mismatch && prefer_extern_name_) { + function->name = AddStringToPool(it_ext->get()->name); + } externs_.erase(it_ext); } #if _DEBUG @@ -115,39 +191,42 @@ void Module::AddFunction(Function* function) { } } #endif - - std::pair 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 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::iterator begin, - vector::iterator end) { - for (vector::iterator it = begin; it != end; ++it) - AddFunction(*it); -} - -void Module::AddStackFrameEntry(StackFrameEntry* stack_frame_entry) { +void Module::AddStackFrameEntry(std::unique_ptr 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 ext) { if (!AddressIsInModule(ext->address)) { return; } - std::pair ret = externs_.insert(ext); - if (!ret.second) { - // Free the duplicate that was not inserted because this Module - // now owns it. - delete ext; + std::pair ret = externs_.emplace(std::move(ext)); + if (!ret.second && enable_multiple_field_) { + (*ret.first)->is_multiple = true; } } @@ -158,7 +237,11 @@ void Module::GetFunctions(vector* vec, void Module::GetExterns(vector* vec, vector::iterator i) { - vec->insert(i, externs_.begin(), externs_.end()); + auto pos = vec->insert(i, externs_.size(), nullptr); + for (const std::unique_ptr& ext : externs_) { + *pos = ext.get(); + ++pos; + } } Module::File* Module::FindFile(const string& name) { @@ -190,7 +273,7 @@ Module::File* Module::FindFile(const char* name) { Module::File* Module::FindExistingFile(const string& name) { FileByNameMap::iterator it = files_.find(&name); - return (it == files_.end()) ? NULL : it->second; + return (it == files_.end()) ? nullptr : it->second; } void Module::GetFiles(vector* vec) { @@ -200,7 +283,11 @@ void Module::GetFiles(vector* vec) { } void Module::GetStackFrameEntries(vector* vec) const { - *vec = stack_frame_entries_; + vec->clear(); + vec->reserve(stack_frame_entries_.size()); + for (const auto& ent : stack_frame_entries_) { + vec->push_back(ent.get()); + } } void Module::AssignSourceIds() { @@ -220,6 +307,19 @@ void Module::AssignSourceIds() { 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& 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,6 +332,25 @@ void Module::AssignSourceIds() { } } +void Module::CreateInlineOrigins( + set& 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& 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)); @@ -261,7 +380,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, bool preserve_load_address) { stream << "MODULE " << os_ << " " << architecture_ << " " << id_ << " " << name_ << "\n"; if (!stream.good()) @@ -271,7 +390,17 @@ bool Module::Write(std::ostream& stream, SymbolData symbol_data) { stream << "INFO CODE_ID " << code_id_ << "\n"; } - if (symbol_data != ONLY_CFI) { + // load_address is subtracted from each line. If we use zero instead, we + // preserve the original addresses present in the ELF binary. + Address load_offset = load_address_; + if (preserve_load_address) { + load_offset = 0; + } + + if (symbol_data & SYMBOLS_AND_FILES) { + // Get all referenced inline origins. + set inline_origins; + CreateInlineOrigins(inline_origins); AssignSourceIds(); // Write out files. @@ -285,19 +414,37 @@ bool Module::Write(std::ostream& stream, SymbolData symbol_data) { } } - // Write out functions and their lines. + // 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 inlines and lines. for (FunctionSet::const_iterator func_it = functions_.begin(); func_it != functions_.end(); ++func_it) { Function* func = *func_it; vector::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_offset) << " " << range_it->size + << " " << func->parameter_size << " " << func->name << dec + << "\n"; + + if (!stream.good()) + return ReportError(); + // Write out inlines. + auto write_inline = [&](unique_ptr& 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_offset) << " " << r.size; + stream << dec << "\n"; + }; + Module::Inline::InlineDFS(func->inlines, write_inline); if (!stream.good()) return ReportError(); @@ -305,7 +452,7 @@ bool Module::Write(std::ostream& stream, SymbolData symbol_data) { (line_it->address >= range_it->address) && (line_it->address < (range_it->address + range_it->size))) { stream << hex - << (line_it->address - load_address_) << " " + << (line_it->address - load_offset) << " " << line_it->size << " " << dec << line_it->number << " " @@ -322,21 +469,20 @@ 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_offset) << " 0 " << ext->name << dec + << "\n"; } } - if (symbol_data != NO_CFI) { + if (symbol_data & CFI) { // Write out 'STACK CFI INIT' and 'STACK CFI' records. - vector::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->address - load_offset) << " " << entry->size << " " << dec; if (!stream.good() || !WriteRuleMap(entry->initial_rules, stream)) @@ -348,7 +494,7 @@ bool Module::Write(std::ostream& stream, SymbolData symbol_data) { for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin(); delta_it != entry->rule_changes.end(); ++delta_it) { stream << "STACK CFI " << hex - << (delta_it->first - load_address_) << " " << dec; + << (delta_it->first - load_offset) << " " << dec; if (!stream.good() || !WriteRuleMap(delta_it->second, stream)) return ReportError(); diff --git a/src/common/module.h b/src/common/module.h index 408e620b2..69eec36de 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,14 +37,18 @@ #ifndef COMMON_LINUX_MODULE_H__ #define COMMON_LINUX_MODULE_H__ +#include #include #include #include +#include #include #include #include +#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" @@ -66,6 +69,8 @@ class Module { static constexpr uint64_t kMaxAddress = std::numeric_limits
::max(); struct File; struct Function; + struct InlineOrigin; + struct Inline; struct Line; struct Extern; @@ -98,7 +103,7 @@ 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 @@ -108,7 +113,7 @@ class Module { } // The function's name. - string name; + StringView name; // The start address and the address ranges covered by the function. const Address address; @@ -120,8 +125,107 @@ class Module { // Source lines belonging to this function, sorted by increasing // address. vector lines; + + // Inlined call sites belonging to this functions. + vector> inlines; + + // If this symbol has been folded with other symbols in the linked binary. + bool is_multiple = false; + + // If the function's name should be filled out from a matching Extern, + // should they not match. + bool prefer_extern_name = 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; }; + // A inlined call site. + struct Inline { + Inline(InlineOrigin* origin, + const vector& ranges, + int call_site_line, + int call_site_file_id, + int inline_nest_level, + vector> 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 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> child_inlines; + + int getCallSiteFileID() const { + return call_site_file ? call_site_file->source_id : -1; + } + + static void InlineDFS( + vector>& inlines, + std::function&)> const& forEach) { + for (std::unique_ptr& in : inlines) { + forEach(in); + InlineDFS(in->child_inlines, forEach); + } + } + }; + + typedef map 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 references_; + }; + + map inline_origin_maps; + // A source line. struct Line { // For sorting by address. (Not style-guide compliant, but it's @@ -140,6 +244,8 @@ class Module { 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 @@ -179,16 +285,40 @@ class Module { } }; + 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, 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& lhs, + const std::unique_ptr& rhs) const { + return lhs->address < rhs->address; + } + bool operator() (const Extern* lhs, const std::unique_ptr& rhs) const { + return lhs->address < rhs->address; + } + bool operator() (const std::unique_ptr& 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, + bool prefer_extern_name = false); ~Module(); // Set the module's load address to LOAD_ADDRESS; addresses given @@ -216,23 +346,18 @@ 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::iterator begin, - vector::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 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 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 @@ -280,19 +405,32 @@ class Module { // symbol file, at which point we omit any unused files. void AssignSourceIds(); + // This function should be called before AssignSourceIds() to get the set of + // valid InlineOrigins*. + void CreateInlineOrigins( + set& 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); + // established by SetLoadAddress, unless preserve_load_address + // is equal to true, in which case each address will remain unchanged. + bool Write(std::ostream& stream, SymbolData symbol_data, bool preserve_load_address = false); + + // 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_; } @@ -340,21 +478,41 @@ class Module { typedef set FunctionSet; // A set containing Extern structures, sorted by address. - typedef set ExternSet; + typedef set, 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
function_addresses_; // The module owns all the call frame info entries that have been // added to it. - vector stack_frame_entries_; + vector> 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 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_; + + // If a Function and an Extern share the same address but have a different + // name, prefer the name of the Extern. + // + // Use this when dumping Mach-O .dSYMs built with -gmlt (Minimum Line Tables), + // as the Function's fully-qualified name will only be present in the STABS + // (which are placed in the Extern), not in the DWARF symbols (which are + // placed in the Function). + bool prefer_extern_name_; }; } // namespace google_breakpad diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc index 7b1b9cdaa..2a5579351 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. // @@ -31,25 +30,32 @@ // module_unittest.cc: Unit tests for google_breakpad::Module. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include #include #include +#include #include #include +#include #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 +73,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 +82,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 +92,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 +117,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 +143,7 @@ TEST(Write, RelativeLoadAddress) { m.AddFunction(function); // Some stack information. - Module::StackFrameEntry* entry = new Module::StackFrameEntry(); + auto entry = std::make_unique(); entry->address = 0x30f9e5c83323973dULL; entry->size = 0x49fc9ca7c7c13dc2ULL; entry->initial_rules[".cfa"] = "he was a handsome man"; @@ -145,7 +151,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 +175,50 @@ TEST(Write, RelativeLoadAddress) { contents.c_str()); } -TEST(Write, OmitUnusedFiles) { +TEST(Module, WritePreserveLoadAddress) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + // Set the load address to something. Doesn't matter what. + // The goal of this test is to demonstrate that the load + // address does not impact any of the generated addresses + // when the preserve_load_address option is equal to true. + m.SetLoadAddress(0x1337ULL); + + Module::File* file = m.FindFile("filename-a.cc"); + Module::Function* function = new Module::Function( + "do_stuff", 0x110ULL); + Module::Range range(0x110ULL, 0x210ULL); + function->ranges.push_back(range); + function->parameter_size = 0x50ULL; + Module::Line line1 = { 0x110ULL, 0x1ULL, + file, 20ULL }; + function->lines.push_back(line1); + m.AddFunction(function); + + // Some stack information. + auto entry = std::make_unique(); + entry->address = 0x200ULL; + entry->size = 0x55ULL; + entry->initial_rules[".cfa"] = "some call frame info"; + entry->rule_changes[0x201ULL][".s0"] = + "some rules change call frame info"; + m.AddStackFrameEntry(std::move(entry)); + + bool preserve_load_address = true; + m.Write(s, ALL_SYMBOL_DATA, preserve_load_address); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FILE 0 filename-a.cc\n" + "FUNC 110 210 50 do_stuff\n" + "110 1 20 0\n" + "STACK CFI INIT 200 55" + " .cfa: some call frame info\n" + "STACK CFI 201" + " .s0: some rules change call frame info\n", + contents.c_str()); +} + +TEST(Module, WriteOmitUnusedFiles) { Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); // Create some source files. @@ -192,7 +241,6 @@ TEST(Write, OmitUnusedFiles) { function->lines.push_back(line1); function->lines.push_back(line2); m.AddFunction(function); - m.AssignSourceIds(); vector vec; @@ -219,7 +267,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 +289,7 @@ TEST(Write, NoCFI) { m.AddFunction(function); // Some stack information. - Module::StackFrameEntry* entry = new Module::StackFrameEntry(); + auto entry = std::make_unique(); entry->address = 0x30f9e5c83323973dULL; entry->size = 0x49fc9ca7c7c13dc2ULL; entry->initial_rules[".cfa"] = "he was a handsome man"; @@ -249,13 +297,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 +313,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 +335,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 +355,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 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(); + entry1->address = 0x1000ULL; + entry1->size = 0x100ULL; + m.AddStackFrameEntry(std::move(entry1)); + auto entry2 = std::make_unique(); + entry2->address = 0x2000ULL; + entry2->size = 0x100ULL; + m.AddStackFrameEntry(std::move(entry2)); + auto entry3 = std::make_unique(); + 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(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(); 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(); 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(); entry3->address = 0x5e8d0db0a7075c6cULL; entry3->size = 0x1c7edb12a7aea229ULL; entry3->initial_rules[".cfa"] = "Whose woods are these"; @@ -338,7 +439,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 +494,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")); @@ -403,10 +504,10 @@ TEST(Construct, UniqueFiles) { EXPECT_EQ(file1, file3); EXPECT_EQ(file2, file4); EXPECT_EQ(file1, m.FindExistingFile("foo")); - EXPECT_TRUE(m.FindExistingFile("baz") == NULL); + EXPECT_TRUE(m.FindExistingFile("baz") == nullptr); } -TEST(Construct, DuplicateFunctions) { +TEST(Module, ConstructDuplicateFunctions) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); @@ -415,7 +516,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 +529,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 +550,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(0xffff); extern1->name = "_abc"; - Module::Extern* extern2 = new Module::Extern(0xaaaa); + auto extern2 = std::make_unique(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 +605,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(0xffff); extern1->name = "_xyz"; - Module::Extern* extern2 = new Module::Extern(0xffff); + auto extern2 = std::make_unique(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 +626,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(0xffff); + extern1->name = "_xyz"; + auto extern2 = std::make_unique(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(0xabc0); extern1->name = "abc"; - Module::Extern* extern2 = new Module::Extern(0xfff0); + auto extern2 = std::make_unique(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); @@ -526,25 +681,87 @@ TEST(Construct, FunctionsAndExternsWithSameAddress) { contents.c_str()); } +// If there exists an extern and a function at the same address, only write +// out the FUNC entry. +TEST(Module, ConstructFunctionsAndExternsWithSameAddressPreferExternName) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", false, true); + + // Two externs. + auto extern1 = std::make_unique(0xabc0); + extern1->name = "extern1"; + auto extern2 = std::make_unique(0xfff0); + extern2->name = "extern2"; + + m.AddExtern(std::move(extern1)); + m.AddExtern(std::move(extern2)); + + Module::Function* function = new Module::Function("function2", 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 fff0 10 0 extern2\n" + "PUBLIC abc0 0 extern1\n", + contents.c_str()); +} + +// 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(0xabc0); + extern1->name = "abc"; + auto extern2 = std::make_unique(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(0xabc1); thumb_extern1->name = "thumb_abc"; - Module::Extern* thumb_extern2 = new Module::Extern(0xfff1); + auto thumb_extern2 = std::make_unique(0xfff1); thumb_extern2->name = "thumb_xyz"; - Module::Extern* arm_extern1 = new Module::Extern(0xcc00); + auto arm_extern1 = std::make_unique(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,58 +781,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 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()); - - // Cleanup - Prevent Memory Leak errors. - delete (extern1); - delete (function); - delete (entry3); - delete (entry1); -} diff --git a/src/common/path_helper.cc b/src/common/path_helper.cc index 61a6e3184..fbbcfca31 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/path_helper.h" #include diff --git a/src/common/path_helper.h b/src/common/path_helper.h index 2166ba018..0c026c250 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 000000000..3eab0d21f --- /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 + +namespace google_breakpad { + +// Adds `a` and `b`, returning a pair of: +// - The result after any truncation. +// - Whether an overflow/underflow occurred. +template +std::pair 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::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::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 +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 000000000..453afbe03 --- /dev/null +++ b/src/common/safe_math_unittest.cc @@ -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. + +// safe_math_unittest.cc: Unit tests for SafeMath + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "safe_math.h" +#include "breakpad_googletest_includes.h" + +namespace { + +using google_breakpad::AddIgnoringOverflow; +using google_breakpad::AddWithOverflowCheck; + +TEST(SafeMath, AddOverflowWorksAsIntended) { + EXPECT_EQ(AddWithOverflowCheck(0, 0), + std::make_pair(0, false)); + EXPECT_EQ(AddWithOverflowCheck(0, 255), + std::make_pair(255, false)); + EXPECT_EQ(AddWithOverflowCheck(1, 255), + std::make_pair(0, true)); + + EXPECT_EQ(AddWithOverflowCheck(-128, 127), + std::make_pair(-1, false)); + EXPECT_EQ(AddWithOverflowCheck(127, -128), + std::make_pair(-1, false)); + EXPECT_EQ(AddWithOverflowCheck(1, -128), + std::make_pair(-127, false)); + EXPECT_EQ(AddWithOverflowCheck(127, -1), + std::make_pair(126, false)); + + EXPECT_EQ(AddWithOverflowCheck(-128, -1), + std::make_pair(127, true)); + EXPECT_EQ(AddWithOverflowCheck(-128, -128), + std::make_pair(0, true)); + EXPECT_EQ(AddWithOverflowCheck(127, 1), + std::make_pair(-128, true)); + EXPECT_EQ(AddWithOverflowCheck(127, 127), + std::make_pair(-2, true)); +} + +TEST(SafeMath, AddIgnoringOverflowWorksAsIntended) { + EXPECT_EQ(AddIgnoringOverflow(0, 0), 0); + EXPECT_EQ(AddIgnoringOverflow(0, 255), 255); + EXPECT_EQ(AddIgnoringOverflow(1, 255), 0); +} + +} // namespace diff --git a/src/common/scoped_ptr.h b/src/common/scoped_ptr.h index d137c1868..cec94c29b 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. // @@ -26,159 +26,28 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Scopers help you manage ownership of a pointer, helping you easily manage the -// a pointer within a scope, and automatically destroying the pointer at the -// end of a scope. There are two main classes you will use, which correspond -// to the operators new/delete and new[]/delete[]. -// -// Example usage (scoped_ptr): -// { -// scoped_ptr foo(new Foo("wee")); -// } // foo goes out of scope, releasing the pointer with it. -// -// { -// scoped_ptr foo; // No pointer managed. -// foo.reset(new Foo("wee")); // Now a pointer is managed. -// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed. -// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed. -// foo->Method(); // Foo::Method() called. -// foo.get()->Method(); // Foo::Method() called. -// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer -// // manages a pointer. -// foo.reset(new Foo("wee4")); // foo manages a pointer again. -// foo.reset(); // Foo("wee4") destroyed, foo no longer -// // manages a pointer. -// } // foo wasn't managing a pointer, so nothing was destroyed. -// -// Example usage (scoped_array): -// { -// scoped_array foo(new Foo[100]); -// foo.get()->Method(); // Foo::Method on the 0th element. -// foo[10].Method(); // Foo::Method on the 10th element. -// } +// scoped_ptr is just a type alias for std::unique_ptr. Mass conversion TBD. #ifndef COMMON_SCOPED_PTR_H_ #define COMMON_SCOPED_PTR_H_ // This is an implementation designed to match the anticipated future TR2 -// implementation of the scoped_ptr class, and its closely-related brethren, -// scoped_array, scoped_ptr_malloc. +// implementation of the scoped_array class. #include #include #include -namespace google_breakpad { - -// A scoped_ptr is like a T*, except that the destructor of scoped_ptr -// automatically deletes the pointer it holds (if any). -// That is, scoped_ptr owns the T object that it points to. -// Like a T*, a scoped_ptr may hold either NULL or a pointer to a T object. -// Also like T*, scoped_ptr is thread-compatible, and once you -// dereference it, you get the threadsafety guarantees of T. -// -// The size of a scoped_ptr is small: -// sizeof(scoped_ptr) == sizeof(C*) -template -class scoped_ptr { - public: - - // The element type - typedef C element_type; - - // Constructor. Defaults to initializing with NULL. - // There is no way to create an uninitialized scoped_ptr. - // The input parameter must be allocated with new. - explicit scoped_ptr(C* p = NULL) : ptr_(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_ptr() { - enum { type_must_be_complete = sizeof(C) }; - delete ptr_; - } - - // 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 != ptr_) { - enum { type_must_be_complete = sizeof(C) }; - delete ptr_; - ptr_ = p; - } - } +#include - // Accessors to get the owned object. - // operator* and operator-> will assert() if there is no current object. - C& operator*() const { - assert(ptr_ != NULL); - return *ptr_; - } - C* operator->() const { - assert(ptr_ != NULL); - return ptr_; - } - C* get() const { return ptr_; } +#include "common/scoped_ptr.h" - // Comparison operators. - // These return whether two scoped_ptr refer to the same object, not just to - // two different but equal objects. - bool operator==(C* p) const { return ptr_ == p; } - bool operator!=(C* p) const { return ptr_ != p; } - - // Swap two scoped pointers. - void swap(scoped_ptr& p2) { - C* tmp = ptr_; - ptr_ = p2.ptr_; - p2.ptr_ = tmp; - } - - // Release a pointer. - // 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 = ptr_; - ptr_ = NULL; - return retVal; - } - - private: - C* ptr_; - - // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't - // make sense, and if C2 == C, it still doesn't make sense because you should - // never have the same object owned by two different scoped_ptrs. - template bool operator==(scoped_ptr const& p2) const; - template bool operator!=(scoped_ptr const& p2) const; - - // Disallow evil constructors - scoped_ptr(const scoped_ptr&); - void operator=(const scoped_ptr&); -}; - -// Free functions -template -void swap(scoped_ptr& p1, scoped_ptr& p2) { - p1.swap(p2); -} - -template -bool operator==(C* p1, const scoped_ptr& p2) { - return p1 == p2.get(); -} - -template -bool operator!=(C* p1, const scoped_ptr& p2) { - return p1 != p2.get(); -} +namespace google_breakpad { -// scoped_array is like scoped_ptr, except that the caller must allocate +// scoped_array is like std::unique_ptr, except that the caller must allocate // with new [] and the destructor deletes objects with delete []. // -// As with scoped_ptr, a scoped_array either points to an object +// As with std::unique_ptr, a scoped_array either points to an object // or is NULL. A scoped_array owns the object that it points to. // scoped_array is thread-compatible, and once you index into it, // the returned objects have only the threadsafety guarantees of T. @@ -194,7 +63,7 @@ class scoped_array { // 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) { } + explicit scoped_array(C* p = nullptr) : 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. @@ -206,7 +75,7 @@ class scoped_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) { + void reset(C* p = nullptr) { if (p != array_) { enum { type_must_be_complete = sizeof(C) }; delete[] array_; @@ -218,7 +87,7 @@ class scoped_array { // Will assert() if there is no current object, or index i is negative. C& operator[](ptrdiff_t i) const { assert(i >= 0); - assert(array_ != NULL); + assert(array_ != nullptr); return array_[i]; } @@ -248,7 +117,7 @@ class scoped_array { // and will not own the object any more. C* release() { C* retVal = array_; - array_ = NULL; + array_ = nullptr; return retVal; } @@ -280,125 +149,6 @@ bool operator!=(C* p1, const scoped_array& p2) { return p1 != p2.get(); } -// This class wraps the c library function free() in a class that can be -// passed as a template argument to scoped_ptr_malloc below. -class ScopedPtrMallocFree { - public: - inline void operator()(void* x) const { - free(x); - } -}; - -// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a -// second template argument, the functor used to free the object. - -template -class scoped_ptr_malloc { - public: - - // The element type - typedef C element_type; - - // Constructor. Defaults to initializing with NULL. - // There is no way to create an uninitialized scoped_ptr. - // The input parameter must be allocated with an allocator that matches the - // Free functor. For the default Free functor, this is malloc, calloc, or - // realloc. - explicit scoped_ptr_malloc(C* p = NULL): ptr_(p) {} - - // Destructor. If there is a C object, call the Free functor. - ~scoped_ptr_malloc() { - reset(); - } - - // Reset. Calls the Free functor on 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 (ptr_ != p) { - FreeProc free_proc; - free_proc(ptr_); - ptr_ = p; - } - } - - // Get the current object. - // operator* and operator-> will cause an assert() failure if there is - // no current object. - C& operator*() const { - assert(ptr_ != NULL); - return *ptr_; - } - - C* operator->() const { - assert(ptr_ != NULL); - return ptr_; - } - - C* get() const { - return ptr_; - } - - // Comparison operators. - // These return whether a scoped_ptr_malloc and a plain pointer refer - // to the same object, not just to two different but equal objects. - // For compatibility with the boost-derived implementation, these - // take non-const arguments. - bool operator==(C* p) const { - return ptr_ == p; - } - - bool operator!=(C* p) const { - return ptr_ != p; - } - - // Swap two scoped pointers. - void swap(scoped_ptr_malloc & b) { - C* tmp = b.ptr_; - b.ptr_ = ptr_; - ptr_ = tmp; - } - - // Release a pointer. - // 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* tmp = ptr_; - ptr_ = NULL; - return tmp; - } - - private: - C* ptr_; - - // no reason to use these: each scoped_ptr_malloc should have its own object - template - bool operator==(scoped_ptr_malloc const& p) const; - template - bool operator!=(scoped_ptr_malloc const& p) const; - - // Disallow evil constructors - scoped_ptr_malloc(const scoped_ptr_malloc&); - void operator=(const scoped_ptr_malloc&); -}; - -template inline -void swap(scoped_ptr_malloc& a, scoped_ptr_malloc& b) { - a.swap(b); -} - -template inline -bool operator==(C* p, const scoped_ptr_malloc& b) { - return p == b.get(); -} - -template inline -bool operator!=(C* p, const scoped_ptr_malloc& b) { - return p != b.get(); -} - } // namespace google_breakpad #endif // COMMON_SCOPED_PTR_H_ diff --git a/src/common/simple_string_dictionary.cc b/src/common/simple_string_dictionary.cc index e0a74ceeb..d3e09b8fc 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/simple_string_dictionary.h" namespace google_breakpad { diff --git a/src/common/simple_string_dictionary.h b/src/common/simple_string_dictionary.h index 948492053..0e3158859 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. // @@ -33,8 +32,6 @@ #include #include -#include "common/basictypes.h" - namespace google_breakpad { // Opaque type for the serialized representation of a NonAllocatingMap. One is @@ -81,6 +78,8 @@ class NonAllocatingMap { : map_(map), current_(0) { } + Iterator(const Iterator&) = delete; + void operator=(const Iterator&) = delete; // Returns the next entry in the map, or NULL if at the end of the // collection. @@ -91,14 +90,12 @@ class NonAllocatingMap { return entry; } } - return NULL; + return nullptr; } private: const NonAllocatingMap& map_; size_t current_; - - DISALLOW_COPY_AND_ASSIGN(Iterator); }; NonAllocatingMap() : entries_() { @@ -145,11 +142,11 @@ class NonAllocatingMap { const char* GetValueForKey(const char* key) const { assert(key); if (!key) - return NULL; + return nullptr; size_t index = GetEntryIndexForKey(key); if (index == num_entries) - return NULL; + return nullptr; return entries_[index].value; } diff --git a/src/common/simple_string_dictionary_unittest.cc b/src/common/simple_string_dictionary_unittest.cc index e7b8fd763..caa21c5c4 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "common/simple_string_dictionary.h" @@ -83,7 +86,7 @@ TEST(NonAllocatingMapTest, SimpleStringDictionary) { EXPECT_FALSE(dict.GetValueForKey("key3")); // Remove by setting value to NULL - dict.SetKeyValue("key2", NULL); + dict.SetKeyValue("key2", nullptr); // Now make sure it's not there anymore EXPECT_FALSE(dict.GetValueForKey("key2")); @@ -323,13 +326,13 @@ TEST(NonAllocatingMapTest, ByIndex) { TEST(NonAllocatingMapTest, NullKey) { NonAllocatingMap<4, 6, 6> map; - ASSERT_DEATH(map.SetKeyValue(NULL, "hello"), ""); + ASSERT_DEATH(map.SetKeyValue(nullptr, "hello"), ""); map.SetKeyValue("hi", "there"); - ASSERT_DEATH(map.GetValueForKey(NULL), ""); + ASSERT_DEATH(map.GetValueForKey(nullptr), ""); EXPECT_STREQ("there", map.GetValueForKey("hi")); - ASSERT_DEATH(map.GetValueForKey(NULL), ""); + ASSERT_DEATH(map.GetValueForKey(nullptr), ""); map.RemoveKey("hi"); EXPECT_EQ(0u, map.GetCount()); } diff --git a/src/common/solaris/dump_symbols.cc b/src/common/solaris/dump_symbols.cc index 9524a18b5..07ca87e7a 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. // @@ -29,6 +28,11 @@ // Author: Alfred Peng +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include #include #include #include @@ -43,7 +47,6 @@ #include #include -#include "common/scoped_ptr.h" #include "common/solaris/dump_symbols.h" #include "common/solaris/file_id.h" #include "common/solaris/guid_creator.h" @@ -216,14 +219,14 @@ bool IsValidElf(const GElf_Ehdr* elf_header) { static bool FindSectionByName(Elf* elf, const char* name, int shstrndx, GElf_Shdr* shdr) { - assert(name != NULL); + assert(name != nullptr); if (strlen(name) == 0) return false; - Elf_Scn* scn = NULL; + Elf_Scn* scn = nullptr; - while ((scn = elf_nextscn(elf, scn)) != NULL) { + while ((scn = elf_nextscn(elf, scn)) != nullptr) { if (gelf_getshdr(scn, shdr) == (GElf_Shdr*)0) { fprintf(stderr, "failed to read section header: %s\n", elf_errmsg(0)); return false; @@ -396,7 +399,7 @@ bool LoadAllSymbols(const GElf_Shdr* stab_section, const GElf_Shdr* stabstr_section, GElf_Word base, struct SymbolInfo* symbols) { - if (stab_section == NULL || stabstr_section == NULL) + if (stab_section == nullptr || stabstr_section == nullptr) return false; char* stabstr = reinterpret_cast(stabstr_section->sh_offset + base); @@ -479,7 +482,7 @@ bool LoadSymbols(Elf* elf, GElf_Ehdr* elf_header, struct SymbolInfo* symbols, } bool WriteModuleInfo(int fd, GElf_Half arch, const std::string& obj_file) { - const char* arch_name = NULL; + const char* arch_name = nullptr; if (arch == EM_386) arch_name = "x86"; else if (arch == EM_X86_64) @@ -492,7 +495,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, @@ -607,13 +610,13 @@ class MmapWrapper { base_(mapped_address), size_(mapped_size) { } ~MmapWrapper() { - if (base_ != NULL) { + if (base_ != nullptr) { assert(size_ > 0); munmap((char*)base_, size_); } } void release() { - base_ = NULL; + base_ = nullptr; size_ = 0; } @@ -648,16 +651,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(nullptr, 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, nullptr); AutoElfEnder elfEnder(elf); - if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr*)NULL) { + if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr*)nullptr) { 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 3bca8a235..9c986e4cc 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. // diff --git a/src/common/solaris/file_id.cc b/src/common/solaris/file_id.cc index c32c73bb0..9efb2e86d 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. // @@ -33,20 +32,23 @@ // // Author: Alfred Peng +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "common/solaris/file_id.h" + +#include #include #include #include -#include -#include #include #include +#include +#include #include -#include -#include - #include "common/md5.h" -#include "common/solaris/file_id.h" #include "common/solaris/message_output.h" #include "google_breakpad/common/minidump_format.h" @@ -68,7 +70,7 @@ static bool FindElfTextSection(int fd, const void* elf_base, assert(text_start); assert(text_size); - *text_start = NULL; + *text_start = nullptr; *text_size = 0; if (elf_version(EV_CURRENT) == EV_NONE) { @@ -78,10 +80,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, nullptr); AutoElfEnder elfEnder(elf); - if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr*)NULL) { + if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr*)nullptr) { print_message2(2, "failed to read elf header: %s\n", elf_errmsg(-1)); return false; } @@ -95,11 +97,11 @@ 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 = nullptr; + Elf_Scn* scn = nullptr; GElf_Shdr shdr; - while ((scn = elf_nextscn(elf, scn)) != NULL) { + while ((scn = elf_nextscn(elf, scn)) != nullptr) { if (gelf_getshdr(scn, &shdr) == (GElf_Shdr*)0) { print_message2(2, "failed to read section header: %s\n", elf_errmsg(0)); return false; @@ -119,7 +121,7 @@ static bool FindElfTextSection(int fd, const void* elf_base, } } } - if (text_section != NULL && text_section->sh_size > 0) { + if (text_section != nullptr && text_section->sh_size > 0) { *text_start = (char*)elf_base + text_section->sh_offset; *text_size = text_section->sh_size; return true; @@ -128,10 +130,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 +138,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,12 +154,12 @@ 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(nullptr, 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 = nullptr; int text_size = 0; if (FindElfTextSection(fd, base, &text_section, &text_size)) { @@ -194,4 +198,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 375e85751..2e41f0ae6 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 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 17d773e72..e6f377e88 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. // @@ -29,15 +28,18 @@ // Author: Alfred Peng -#include -#include +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif +#include "common/solaris/guid_creator.h" + +#include #include #include +#include #include -#include "common/solaris/guid_creator.h" - // // GUIDGenerator // @@ -48,7 +50,7 @@ class GUIDGenerator { public: GUIDGenerator() { - srandom(time(NULL)); + srandom(time(nullptr)); } bool CreateGUID(GUID *guid) const { diff --git a/src/common/solaris/guid_creator.h b/src/common/solaris/guid_creator.h index 4aee3a1c2..91ed00419 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 3e3b1d465..9810dc571 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 43c404029..55f24813c 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. // @@ -31,6 +31,10 @@ // This file implements the google_breakpad::StabsReader class. // See stabs_reader.h. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/stabs_reader.h" #include @@ -76,7 +80,7 @@ StabsReader::StabsReader(const uint8_t* stab, size_t stab_size, handler_(handler), string_offset_(0), next_cu_string_offset_(0), - current_source_file_(NULL) { } + current_source_file_(nullptr) { } const char* StabsReader::SymbolString() { ptrdiff_t offset = string_offset_ + iterator_->name_offset; @@ -134,7 +138,7 @@ 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 = nullptr; { const char* name = SymbolString(); if (name[0] && name[strlen(name) - 1] == '/') { diff --git a/src/common/stabs_reader.h b/src/common/stabs_reader.h index 1e773f45d..655683f12 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. // @@ -49,10 +49,6 @@ #include #include -#ifdef HAVE_CONFIG_H -#include -#endif - #ifdef HAVE_MACH_O_NLIST_H #include #elif defined(HAVE_A_OUT_H) diff --git a/src/common/stabs_reader_unittest.cc b/src/common/stabs_reader_unittest.cc index 24f3e1a57..fe7fb9e07 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. // @@ -31,6 +30,10 @@ // stabs_reader_unittest.cc: Unit tests for google_breakpad::StabsReader. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -132,7 +135,7 @@ class StabsAssembler: public Section { string_assembler_(string_assembler), value_size_(0), entry_count_(0), - cu_header_(NULL) { } + cu_header_(nullptr) { } ~StabsAssembler() { assert(!cu_header_); } // Accessor and setter for value_size_. @@ -185,7 +188,7 @@ class StabsAssembler: public Section { cu_header_->final_entry_count = entry_count_; cu_header_->final_string_size = string_assembler_->EndCU(); delete cu_header_; - cu_header_ = NULL; + cu_header_ = nullptr; return *this; } @@ -317,7 +320,7 @@ TEST_F(Stabs, MockStabsInput) { EXPECT_CALL(mock_handler, EndCompilationUnit(0xd04b7448U)) .WillOnce(Return(true)); EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("file3.c"), - 0x11759f10U, NULL)) + 0x11759f10U, nullptr)) .WillOnce(Return(true)); EXPECT_CALL(mock_handler, EndCompilationUnit(0x11cfe4b5U)) .WillOnce(Return(true)); @@ -335,7 +338,7 @@ TEST_F(Stabs, AbruptCU) { InSequence s; EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file2-1.c"), 0xbf10d5e4, NULL)) + StartCompilationUnit(StrEq("file2-1.c"), 0xbf10d5e4, nullptr)) .WillOnce(Return(true)); EXPECT_CALL(mock_handler, EndCompilationUnit(0)) .WillOnce(Return(true)); @@ -355,7 +358,7 @@ TEST_F(Stabs, AbruptFunction) { InSequence s; EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file3-1.c"), 0xb83ddf10U, NULL)) + StartCompilationUnit(StrEq("file3-1.c"), 0xb83ddf10U, nullptr)) .WillOnce(Return(true)); EXPECT_CALL(mock_handler, StartFunction(StrEq("fun3_1"), 0xbbd4a145U)) .WillOnce(Return(true)); @@ -392,12 +395,12 @@ TEST_F(Stabs, NoCUEnd) { InSequence s; EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file5-1.c"), 0x2f7493c9U, NULL)) + StartCompilationUnit(StrEq("file5-1.c"), 0x2f7493c9U, nullptr)) .WillOnce(Return(true)); EXPECT_CALL(mock_handler, EndCompilationUnit(0)) .WillOnce(Return(true)); EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file5-2.c"), 0xf9f1d50fU, NULL)) + StartCompilationUnit(StrEq("file5-2.c"), 0xf9f1d50fU, nullptr)) .WillOnce(Return(true)); EXPECT_CALL(mock_handler, EndCompilationUnit(0)) .WillOnce(Return(true)); @@ -427,7 +430,7 @@ TEST_F(Stabs, Unitized) { { InSequence s; EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("antimony"), 0x7e259f1aU, NULL)) + StartCompilationUnit(StrEq("antimony"), 0x7e259f1aU, nullptr)) .WillOnce(Return(true)); EXPECT_CALL(mock_handler, StartFunction(Eq("arsenic"), 0x7fbcccaeU)) .WillOnce(Return(true)); @@ -436,7 +439,7 @@ TEST_F(Stabs, Unitized) { EXPECT_CALL(mock_handler, EndCompilationUnit(0x80b0014cU)) .WillOnce(Return(true)); EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("aluminum"), 0x86756839U, NULL)) + StartCompilationUnit(StrEq("aluminum"), 0x86756839U, nullptr)) .WillOnce(Return(true)); EXPECT_CALL(mock_handler, StartFunction(Eq("selenium"), 0xa8e120b0U)) .WillOnce(Return(true)); @@ -466,7 +469,7 @@ TEST_F(Stabs, NonUnitized) { InSequence s; EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("Tanzania"), - 0x11a97352, NULL)) + 0x11a97352, nullptr)) .WillOnce(Return(true)); EXPECT_CALL(mock_handler, EndCompilationUnit(0x21a97352)) .WillOnce(Return(true)); @@ -494,7 +497,7 @@ TEST_F(Stabs, FunctionEnd) { InSequence s; EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("compilation unit"), - 0x52a830d644cd6942ULL, NULL)) + 0x52a830d644cd6942ULL, nullptr)) .WillOnce(Return(true)); EXPECT_CALL(mock_handler, StartFunction(Eq("function 1"), 0xbb5ab70ecdd23bfeULL)) diff --git a/src/common/stabs_to_module.cc b/src/common/stabs_to_module.cc index 05b25a74e..05982b941 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. // @@ -31,12 +30,18 @@ // dump_stabs.cc --- implement the StabsToModule class. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include #include #include +#include +#include #include "common/stabs_to_module.h" #include "common/using_std_string.h" @@ -47,8 +52,9 @@ namespace google_breakpad { // Older GCC may not support it. 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) { + char *demangled = abi::__cxa_demangle( + mangled.c_str(), nullptr, nullptr, &status); + if (status == 0 && demangled != nullptr) { string str(demangled); free(demangled); return str; @@ -80,8 +86,8 @@ bool StabsToModule::EndCompilationUnit(uint64_t address) { assert(in_compilation_unit_); in_compilation_unit_ = false; comp_unit_base_address_ = 0; - current_source_file_ = NULL; - current_source_file_name_ = NULL; + current_source_file_ = nullptr; + current_source_file_name_ = nullptr; if (address) boundaries_.push_back(static_cast(address)); return true; @@ -90,7 +96,8 @@ bool StabsToModule::EndCompilationUnit(uint64_t address) { 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. @@ -109,7 +116,7 @@ bool StabsToModule::EndFunction(uint64_t address) { functions_.push_back(current_function_); else delete current_function_; - current_function_ = NULL; + current_function_ = nullptr; if (address) boundaries_.push_back(static_cast(address)); return true; @@ -132,7 +139,7 @@ bool StabsToModule::Line(uint64_t address, const char *name, int number) { } bool StabsToModule::Extern(const string& name, uint64_t address) { - Module::Extern *ext = new Module::Extern(address); + auto ext = std::make_unique(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 +149,7 @@ bool StabsToModule::Extern(const string& name, uint64_t address) { } else { ext->name = name; } - module_->AddExtern(ext); + module_->AddExtern(std::move(ext)); return true; } @@ -191,8 +198,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 6f6e0ed7f..e384e66f4 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. // @@ -67,9 +66,9 @@ class StabsToModule: public google_breakpad::StabsHandler { module_(module), in_compilation_unit_(false), comp_unit_base_address_(0), - current_function_(NULL), - current_source_file_(NULL), - current_source_file_name_(NULL) { } + current_function_(nullptr), + current_source_file_(nullptr), + current_source_file_name_(nullptr) { } ~StabsToModule(); // The standard StabsHandler virtual member functions. diff --git a/src/common/stabs_to_module_unittest.cc b/src/common/stabs_to_module_unittest.cc index 9c134e733..3befb51c2 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. // @@ -31,6 +30,10 @@ // dump_stabs_unittest.cc: Unit tests for StabsToModule. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "breakpad_googletest_includes.h" @@ -56,13 +59,13 @@ TEST(StabsToModule, SimpleCU) { // Now check to see what has been added to the Module. Module::File *file = m.FindExistingFile("source-file-name"); - ASSERT_TRUE(file != NULL); + ASSERT_TRUE(file != nullptr); vector 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); @@ -122,7 +125,7 @@ TEST(StabsToModule, DuplicateFunctionNames) { // Now check to see what has been added to the Module. Module::File *file = m.FindExistingFile("compilation-unit"); - ASSERT_TRUE(file != NULL); + ASSERT_TRUE(file != nullptr); vector functions; m.GetFunctions(&functions, functions.end()); @@ -155,16 +158,16 @@ TEST(InferSizes, LineSize) { // Now check to see what has been added to the Module. Module::File *file1 = m.FindExistingFile("source-file-name-1"); - ASSERT_TRUE(file1 != NULL); + ASSERT_TRUE(file1 != nullptr); Module::File *file2 = m.FindExistingFile("source-file-name-2"); - ASSERT_TRUE(file2 != NULL); + ASSERT_TRUE(file2 != nullptr); vector 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); @@ -202,7 +205,7 @@ TEST(FunctionNames, Mangled) { // Now check to see what has been added to the Module. Module::File *file = m.FindExistingFile("compilation-unit"); - ASSERT_TRUE(file != NULL); + ASSERT_TRUE(file != nullptr); vector functions; m.GetFunctions(&functions, functions.end()); @@ -211,10 +214,9 @@ TEST(FunctionNames, Mangled) { Module::Function *function = functions[0]; // This is GCC-specific, but we shouldn't be seeing STABS data anywhere // but Linux. - EXPECT_STREQ("std::vector >::" - "push_back(unsigned long long const&)", - function->name.c_str()); + EXPECT_THAT(function->name.str(), ::testing::ContainsRegex( + "std::vector\\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 a3dd50aab..32093bd4b 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 6a78ed7e4..a4e64ff06 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "common/convert_UTF.h" diff --git a/src/common/string_conversion.h b/src/common/string_conversion.h index 02d1486aa..c5f5a3576 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. // diff --git a/src/common/string_conversion_unittest.cc b/src/common/string_conversion_unittest.cc index e9f9b55d9..0f372c800 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. // @@ -29,6 +28,10 @@ // string_conversion_unittest.cc: Unit tests for google_breakpad::UTF* helpers. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include diff --git a/src/common/string_view.h b/src/common/string_view.h new file mode 100644 index 000000000..8b9b19e6e --- /dev/null +++ b/src/common/string_view.h @@ -0,0 +1,117 @@ +// 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 +#include +#include + +#include +#include + +#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 2cf15a855..19d6f3dd2 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 + // 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( + static_cast::type>(data1) & + static_cast::type>(data2)); +} + +inline SymbolData operator|(SymbolData data1, SymbolData data2) { + return static_cast( + static_cast::type>(data1) | + static_cast::type>(data2)); +} + #endif // COMMON_SYMBOL_DATA_H_ diff --git a/src/common/test_assembler.cc b/src/common/test_assembler.cc index 8a48bfb0b..95c1619a3 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. // @@ -32,6 +31,10 @@ // test_assembler.cc: Implementation of google_breakpad::TestAssembler. // See test_assembler.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/test_assembler.h" #include @@ -39,6 +42,8 @@ #include +#include "common/memory_allocator.h" + namespace google_breakpad { namespace test_assembler { @@ -55,7 +60,7 @@ Label::~Label() { } Label& Label::operator=(uint64_t value) { - value_->Set(NULL, value); + value_->Set(nullptr, value); return *this; } @@ -105,7 +110,7 @@ bool Label::IsKnownConstant(uint64_t* value_p) const { Binding* base; uint64_t addend; value_->Get(&base, &addend); - if (base != NULL) return false; + if (base != nullptr) return false; if (value_p) *value_p = addend; return true; } @@ -127,7 +132,7 @@ bool Label::IsKnownOffsetFrom(const Label& label, uint64_t* offset_p) const Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { } Label::Binding::Binding(uint64_t addend) - : base_(NULL), addend_(addend), reference_count_(1) { } + : base_(nullptr), addend_(addend), reference_count_(1) { } Label::Binding::~Binding() { assert(reference_count_ == 0); @@ -142,7 +147,7 @@ void Label::Binding::Set(Binding* binding, uint64_t addend) { } else if (!base_) { // We are a known constant, but BINDING may not be, so turn the // tables and try to set BINDING's value instead. - binding->Set(NULL, addend_ - addend); + binding->Set(nullptr, addend_ - addend); } else { if (binding) { // Find binding's final value. Since the final value is always either @@ -324,7 +329,7 @@ Section& Section::ULEB128(uint64_t value) { 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); + size_t new_size = PageAllocator::AlignUp(contents_.size(), alignment); contents_.append(new_size - contents_.size(), pad_byte); assert((contents_.size() & (alignment - 1)) == 0); return *this; diff --git a/src/common/test_assembler.h b/src/common/test_assembler.h index 125ef4503..4d40b50dd 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. // @@ -135,7 +134,7 @@ class Label { // 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 = nullptr) 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,8 @@ 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 = nullptr) const; private: // A label's value, or if that is not yet known, how the value is diff --git a/src/common/test_assembler_unittest.cc b/src/common/test_assembler_unittest.cc index bda25ebfc..0307fdbf4 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. // @@ -31,6 +30,10 @@ // test_assembler_unittest.cc: Unit tests for google_breakpad::TestAssembler. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include diff --git a/src/common/tests/auto_tempdir.h b/src/common/tests/auto_tempdir.h index 1df88db8b..d7b583e1a 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. // @@ -53,7 +52,7 @@ class AutoTempDir { public: AutoTempDir() { char temp_dir[] = TEMPDIR "/breakpad.XXXXXX"; - EXPECT_TRUE(mkdtemp(temp_dir) != NULL); + EXPECT_TRUE(mkdtemp(temp_dir) != nullptr); path_.assign(temp_dir); } @@ -73,7 +72,7 @@ class AutoTempDir { return; dirent* entry; - while ((entry = readdir(dir)) != NULL) { + while ((entry = readdir(dir)) != nullptr) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; string entry_path = path + "/" + entry->d_name; diff --git a/src/common/tests/file_utils.cc b/src/common/tests/file_utils.cc index c1cbb39cc..84a228095 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. // @@ -30,6 +29,10 @@ // file_utils.cc: Implement utility functions for file manipulation. // See file_utils.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include diff --git a/src/common/tests/file_utils.h b/src/common/tests/file_utils.h index 3d1a9c6fa..b96029d0e 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. // diff --git a/src/common/unordered.h b/src/common/unordered.h index c9cbd5854..7606f1701 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 {}; template > struct unordered_set : public __gnu_cxx::hash_set {}; -#elif defined(_LIBCPP_VERSION) // c++11 +#else #include #include using std::unordered_map; using std::unordered_set; - -#else // Fallback to tr1::unordered -#include -#include -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 13c1da59c..0f11db7bd 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 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 5f7594b16..000000000 --- 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 ed8cb5b65..631e389d5 100644 --- a/src/common/windows/dia_util.cc +++ b/src/common/windows/dia_util.cc @@ -1,92 +1,96 @@ -// 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 - -namespace google_breakpad { - -bool FindDebugStream(const wchar_t* name, - IDiaSession* session, - IDiaEnumDebugStreamData** debug_stream) { - CComPtr enum_debug_streams; - if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) { - fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n"); - return false; - } - - CComPtr 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 enum_tables; - if (FAILED(session->getEnumTables(&enum_tables))) { - fprintf(stderr, "IDiaSession::getEnumTables failed\n"); - return false; - } - - // Iterate through the tables. - CComPtr 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "common/windows/dia_util.h" + +#include + +namespace google_breakpad { + +bool FindDebugStream(const wchar_t* name, + IDiaSession* session, + IDiaEnumDebugStreamData** debug_stream) { + CComPtr enum_debug_streams; + if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) { + fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n"); + return false; + } + + CComPtr 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 enum_tables; + if (FAILED(session->getEnumTables(&enum_tables))) { + fprintf(stderr, "IDiaSession::getEnumTables failed\n"); + return false; + } + + // Iterate through the tables. + CComPtr temp_table; + ULONG fetched = 0; + while (SUCCEEDED(enum_tables->Next(1, &temp_table, &fetched)) && + fetched == 1) { + void* temp = nullptr; + 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 b9e0df2d5..16ed8380a 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 b7f877e66..2c298c33a 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. // @@ -31,6 +30,10 @@ // // See guid_string.h for documentation. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "common/windows/string_utils-inl.h" diff --git a/src/common/windows/guid_string.h b/src/common/windows/guid_string.h index 48a5c1d37..ee3d10066 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 efee0d58b..76363398b 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. // @@ -27,14 +26,28 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include +#include +#include +#include + #include +#include +#include +#include +#include + +#if defined(HAVE_ZLIB) +#include +#endif // Disable exception handler warnings. #pragma warning(disable:4530) -#include -#include - #include "common/windows/string_utils-inl.h" #include "common/windows/http_upload.h" @@ -43,9 +56,64 @@ namespace { using std::string; using std::wstring; using std::map; - using std::vector; - using std::ifstream; - using std::ios; + using std::unique_ptr; + +// Silence warning C4100, which may strike when building without zlib support. +#pragma warning(push) +#pragma warning(disable:4100) + + // Compresses the contents of `data` into `deflated` using the deflate + // algorithm, if supported. Returns true on success, or false if not supported + // or in case of any error. The contents of `deflated` are undefined in the + // latter case. + bool Deflate(const string& data, string& deflated) { +#if defined(HAVE_ZLIB) + z_stream stream{}; + + // Start with an output buffer sufficient for 75% compression to avoid + // reallocations. + deflated.resize(data.size() / 4); + stream.next_in = reinterpret_cast(const_cast(data.data())); + stream.avail_in = data.size(); + stream.next_out = reinterpret_cast(&deflated[0]); + stream.avail_out = deflated.size(); + stream.data_type = Z_TEXT; + + // Z_BEST_SPEED is chosen because, in practice, it offers excellent speed + // with comparable compression for the symbol data typically being uploaded. + // Z_BEST_COMPRESSION: 2151202094 bytes compressed 84.27% in 74.440s. + // Z_DEFAULT_COMPRESSION: 2151202094 bytes compressed 84.08% in 36.016s. + // Z_BEST_SPEED: 2151202094 bytes compressed 80.39% in 13.73s. + int result = deflateInit(&stream, Z_BEST_SPEED); + if (result != Z_OK) { + return false; + } + + while (true) { + result = deflate(&stream, /*flush=*/Z_FINISH); + if (result == Z_STREAM_END) { // All data processed. + deflated.resize(stream.total_out); + break; + } + if (result != Z_OK && result != Z_BUF_ERROR) { + fwprintf(stderr, L"Compression failed with zlib error %d\n", result); + break; // Error condition. + } + // Grow `deflated` by at least 1k to accept the rest of the data. + deflated.resize(deflated.size() + std::max(stream.avail_in, 1024U)); + stream.next_out = reinterpret_cast(&deflated[stream.total_out]); + stream.avail_out = deflated.size() - stream.total_out; + } + deflateEnd(&stream); + + return result == Z_STREAM_END; +#else + return false; +#endif // defined(HAVE_ZLIB) + } + +// Restore C4100 to its previous state. +#pragma warning(pop) const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)"; @@ -71,7 +139,8 @@ namespace { } // compute the length of the buffer we'll need - int charcount = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0); + int charcount = MultiByteToWideChar( + CP_UTF8, 0, utf8.c_str(), -1, nullptr, 0); if (charcount == 0) { return wstring(); @@ -92,7 +161,7 @@ namespace { // compute the length of the buffer we'll need int charcount = WideCharToMultiByte(cp, 0, wide.c_str(), -1, - NULL, 0, NULL, NULL); + nullptr, 0, nullptr, nullptr); if (charcount == 0) { return string(); } @@ -100,45 +169,82 @@ namespace { // convert char *buf = new char[charcount]; WideCharToMultiByte(cp, 0, wide.c_str(), -1, buf, charcount, - NULL, NULL); + nullptr, nullptr); string result(buf); delete[] buf; return result; } - bool GetFileContents(const wstring& filename, vector* 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 - // later, _wfopen has been deprecated in favor of _wfopen_s, which does - // not exist in earlier versions, so let the ifstream open the file itself. - // GCC doesn't support wide file name and opening on FILE* requires ugly - // hacks, so fallback to multi byte file. -#ifdef _MSC_VER - ifstream file; - file.open(filename.c_str(), ios::binary); -#else // GCC - ifstream file(WideToMBCP(filename, CP_ACP).c_str(), ios::binary); -#endif // _MSC_VER >= 1400 - if (file.is_open()) { - file.seekg(0, ios::end); - std::streamoff length = file.tellg(); - // Check for loss of data when converting lenght from std::streamoff into - // std::vector::size_type - std::vector::size_type vector_size = - static_cast::size_type>(length); - if (static_cast(vector_size) == length) { - contents->resize(vector_size); - if (length != 0) { - file.seekg(0, ios::beg); - file.read(&((*contents)[0]), length); + // Returns a string representation of a given Windows error code, or null + // on failure. + using ScopedLocalString = unique_ptr; + ScopedLocalString FormatError(DWORD error) { + wchar_t* message_buffer = nullptr; + DWORD message_length = + ::FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, + /*lpSource=*/::GetModuleHandle(L"wininet.dll"), error, + /*dwLanguageId=*/0, reinterpret_cast(&message_buffer), + /*nSize=*/0, /*Arguments=*/nullptr); + return ScopedLocalString(message_length ? message_buffer : nullptr, + &LocalFree); + } + + // Emits a log message to stderr for the named operation and Windows error + // code. + void LogError(const char* operation, DWORD error) { + ScopedLocalString message = FormatError(error); + fwprintf(stderr, L"%S failed with error %u: %s\n", operation, error, + message ? message.get() : L""); + } + + // Invokes the Win32 CloseHandle function on `handle` if it is valid. + // Intended for use as a deleter for a std::unique_ptr. + void CloseWindowsHandle(void* handle) { + if (handle != INVALID_HANDLE_VALUE && handle != nullptr) { + ::CloseHandle(handle); + } + } + + // Appends the contents of the file at `filename` to `contents`. + bool AppendFileContents(const wstring& filename, string* contents) { + // Use Win32 APIs rather than the STL so that files larger than 2^31-1 bytes + // can be read. This also allows for use of a hint to the cache manager that + // the file will be read sequentially, which can improve performance. + using ScopedWindowsHandle = + unique_ptr; + ScopedWindowsHandle file( + ::CreateFileW(filename.c_str(), GENERIC_READ, + FILE_SHARE_DELETE | FILE_SHARE_READ, + /*lpSecurityAttributes=*/nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, + /*hTemplateFile=*/nullptr), &CloseWindowsHandle); + BY_HANDLE_FILE_INFORMATION info = {}; + if (file.get() != nullptr && file.get() != INVALID_HANDLE_VALUE && + ::GetFileInformationByHandle(file.get(), &info)) { + uint64_t file_size = info.nFileSizeHigh; + file_size <<= 32; + file_size |= info.nFileSizeLow; + string::size_type position = contents->size(); + contents->resize(position + file_size); + constexpr DWORD kChunkSize = 1024*1024; + while (file_size) { + const DWORD bytes_to_read = + (file_size >= kChunkSize + ? kChunkSize + : static_cast(file_size)); + DWORD bytes_read = 0; + if (!::ReadFile(file.get(), &((*contents)[position]), bytes_to_read, + &bytes_read, /*lpOverlapped=*/nullptr)) { + return false; } - rv = true; + position += bytes_read; + file_size -= bytes_read; } - file.close(); } - return rv; + return true; } bool CheckParameters(const map& parameters) { @@ -174,39 +280,48 @@ namespace { static_cast(&content_length), &content_length_size, 0)) { has_content_length_header = true; - claimed_size = wcstol(content_length, NULL, 10); + claimed_size = wcstol(content_length, nullptr, 10); response_body.reserve(claimed_size); + } else { + DWORD error = ::GetLastError(); + if (error != ERROR_HTTP_HEADER_NOT_FOUND) { + LogError("HttpQueryInfo", error); + } } - DWORD bytes_available; DWORD total_read = 0; - BOOL return_code; - - while (((return_code = InternetQueryDataAvailable(request, &bytes_available, - 0, 0)) != 0) && bytes_available > 0) { - vector response_buffer(bytes_available); + while (true) { + DWORD bytes_available; + if (!InternetQueryDataAvailable(request, &bytes_available, 0, 0)) { + LogError("InternetQueryDataAvailable", ::GetLastError()); + return false; + } + if (bytes_available == 0) { + break; + } + // Grow the output to hold the available bytes. + response_body.resize(total_read + bytes_available); DWORD size_read; - - return_code = InternetReadFile(request, - &response_buffer[0], - bytes_available, &size_read); - - if (return_code && size_read > 0) { - total_read += size_read; - response_body.append(&response_buffer[0], size_read); + if (!InternetReadFile(request, &response_body[total_read], + bytes_available, &size_read)) { + LogError("InternetReadFile", ::GetLastError()); + return false; } - else { + if (size_read == 0) { break; } + total_read += size_read; } + // The body may have been over-sized above; shrink to the actual bytes read. + response_body.resize(total_read); - bool succeeded = return_code && (!has_content_length_header || - (total_read == claimed_size)); - if (succeeded && response) { + if (has_content_length_header && (total_read != claimed_size)) { + return false; // The response doesn't match the Content-Length header. + } + if (response) { *response = UTF8ToWide(response_body); } - - return succeeded; + return true; } bool SendRequestInner( @@ -234,8 +349,7 @@ namespace { components.dwUrlPathLength = sizeof(path) / sizeof(path[0]); if (!InternetCrackUrl(url.c_str(), static_cast(url.size()), 0, &components)) { - DWORD err = GetLastError(); - wprintf(L"%d\n", err); + LogError("InternetCrackUrl", ::GetLastError()); return false; } bool secure = false; @@ -248,22 +362,24 @@ namespace { AutoInternetHandle internet(InternetOpen(kUserAgent, INTERNET_OPEN_TYPE_PRECONFIG, - NULL, // proxy name - NULL, // proxy bypass + nullptr, // proxy name + nullptr, // proxy bypass 0)); // flags if (!internet.get()) { + LogError("InternetOpen", ::GetLastError()); return false; } AutoInternetHandle connection(InternetConnect(internet.get(), host, components.nPort, - NULL, // user name - NULL, // password + nullptr, // user name + nullptr, // password INTERNET_SERVICE_HTTP, 0, // flags - NULL)); // context + 0)); // context if (!connection.get()) { + LogError("InternetConnect", ::GetLastError()); return false; } @@ -272,20 +388,23 @@ namespace { AutoInternetHandle request(HttpOpenRequest(connection.get(), http_method.c_str(), path, - NULL, // version - NULL, // referer - NULL, // agent type + nullptr, // version + nullptr, // referer + nullptr, // agent type http_open_flags, - NULL)); // context + 0)); // context if (!request.get()) { + LogError("HttpOpenRequest", ::GetLastError()); return false; } if (!content_type_header.empty()) { - HttpAddRequestHeaders(request.get(), - content_type_header.c_str(), - static_cast(-1), - HTTP_ADDREQ_FLAG_ADD); + if (!HttpAddRequestHeaders(request.get(), + content_type_header.c_str(), + static_cast(-1), + HTTP_ADDREQ_FLAG_ADD)) { + LogError("HttpAddRequestHeaders", ::GetLastError()); + } } if (timeout_ms) { @@ -293,20 +412,21 @@ namespace { INTERNET_OPTION_SEND_TIMEOUT, timeout_ms, sizeof(*timeout_ms))) { - fwprintf(stderr, L"Could not unset send timeout, continuing...\n"); + LogError("InternetSetOption-send timeout", ::GetLastError()); } if (!InternetSetOption(request.get(), INTERNET_OPTION_RECEIVE_TIMEOUT, timeout_ms, sizeof(*timeout_ms))) { - fwprintf(stderr, L"Could not unset receive timeout, continuing...\n"); + LogError("InternetSetOption-receive timeout", ::GetLastError()); } } - if (!HttpSendRequest(request.get(), NULL, 0, + if (!HttpSendRequest(request.get(), nullptr, 0, const_cast(request_body.data()), static_cast(request_body.size()))) { + LogError("HttpSendRequest", ::GetLastError()); return false; } @@ -316,10 +436,11 @@ namespace { if (!HttpQueryInfo(request.get(), HTTP_QUERY_STATUS_CODE, static_cast(&http_status), &http_status_size, 0)) { + LogError("HttpQueryInfo", ::GetLastError()); return false; } - int http_response = wcstol(http_status, NULL, 10); + int http_response = wcstol(http_status, nullptr, 10); if (response_code) { *response_code = http_response; } @@ -357,10 +478,10 @@ namespace { 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,23 +492,19 @@ 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"); - - vector contents; - if (!GetFileContents(filename, &contents)) { - return false; - } - - if (!contents.empty()) { - request_body->append(&(contents[0]), contents.size()); + 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"); } - request_body->append("\r\n"); - return true; + return AppendFileContents(filename, request_body); } bool GenerateRequestBody(const map& parameters, @@ -432,14 +549,28 @@ 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; } + static const wchar_t kNoEncoding[] = L""; + static const wchar_t kDeflateEncoding[] = L"Content-Encoding: deflate\r\n"; + const wchar_t* encoding_header = &kNoEncoding[0]; + string compressed_body; + if (Deflate(request_body, compressed_body)) { + request_body.swap(compressed_body); + encoding_header = &kDeflateEncoding[0]; + } // else deflate unsupported or failed; send the raw data. + string().swap(compressed_body); // Free memory. + return SendRequestInner( url, L"PUT", - L"", + encoding_header, request_body, timeout_ms, response_body, diff --git a/src/common/windows/http_upload.h b/src/common/windows/http_upload.h index c7d8c6fec..4a2e9bf2f 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. // @@ -42,6 +41,7 @@ #include #include +#include namespace google_breakpad { @@ -52,7 +52,8 @@ using std::map; class HTTPUpload { public: // Sends a PUT request containing the data in |path| to the given - // URL. + // URL. The data is encoded via the deflate algorithm, if support for such + // is available at build-time. // Only HTTP(S) URLs are currently supported. Returns true on success. // If the request is successful and response_body is non-NULL, // the response body will be returned in response_body. diff --git a/src/common/windows/module_info.h b/src/common/windows/module_info.h index 3dccc8088..ade32c11c 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 - -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 + +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 5a821b64f..12d1a2f15 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. // @@ -100,12 +100,16 @@ // position) so that resolution will work as expected for translated addresses. // This is transparent to the rest of the toolchain. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/windows/omap.h" +#include #include #include -#include #include #include "common/windows/dia_util.h" @@ -170,14 +174,14 @@ bool EndpointIndexLess(const EndpointIndex& ei1, const EndpointIndex& ei2) { bool FindAndLoadOmapTable(const wchar_t* name, IDiaSession* session, OmapTable* table) { - assert(name != NULL); - assert(session != NULL); - assert(table != NULL); + assert(name != nullptr); + assert(session != nullptr); + assert(table != nullptr); CComPtr stream; if (!FindDebugStream(name, session, &stream)) return false; - assert(stream.p != NULL); + assert(stream.p != nullptr); LONG count = 0; if (FAILED(stream->get_Count(&count))) { @@ -189,7 +193,7 @@ bool FindAndLoadOmapTable(const wchar_t* name, // Get the length of the stream in bytes. DWORD bytes_read = 0; ULONG count_read = 0; - if (FAILED(stream->Next(count, 0, &bytes_read, NULL, &count_read))) { + if (FAILED(stream->Next(count, 0, &bytes_read, nullptr, &count_read))) { fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading " "length of stream \"%ws\"\n", name); return false; @@ -220,20 +224,20 @@ bool FindAndLoadOmapTable(const wchar_t* name, // This determines the original image length by looking through the segment // table. bool GetOriginalImageLength(IDiaSession* session, DWORD* image_length) { - assert(session != NULL); - assert(image_length != NULL); + assert(session != nullptr); + assert(image_length != nullptr); CComPtr enum_segments; if (!FindTable(session, &enum_segments)) return false; - assert(enum_segments.p != NULL); + assert(enum_segments.p != nullptr); DWORD temp_image_length = 0; CComPtr segment; ULONG fetched = 0; while (SUCCEEDED(enum_segments->Next(1, &segment, &fetched)) && fetched == 1) { - assert(segment.p != NULL); + assert(segment.p != nullptr); DWORD rva = 0; DWORD length = 0; @@ -262,7 +266,7 @@ bool GetOriginalImageLength(IDiaSession* session, DWORD* image_length) { // immediately preceding a gap. The mapped ranges must be sorted by // 'rva_original'. void FillInRemovedLengths(Mapping* mapping) { - assert(mapping != NULL); + assert(mapping != nullptr); // Find and fill gaps. We do this with two sweeps. We first sweep forward // looking for gaps. When we identify a gap we then sweep forward with a @@ -315,7 +319,7 @@ void FillInRemovedLengths(Mapping* mapping) { // Builds a unified view of the mapping between the original and transformed // image space by merging OMAPTO and OMAPFROM data. void BuildMapping(const OmapData& omap_data, Mapping* mapping) { - assert(mapping != NULL); + assert(mapping != nullptr); mapping->clear(); @@ -403,7 +407,7 @@ void BuildMapping(const OmapData& omap_data, Mapping* mapping) { } void BuildEndpointIndexMap(ImageMap* image_map) { - assert(image_map != NULL); + assert(image_map != nullptr); if (image_map->mapping.size() == 0) return; @@ -473,7 +477,7 @@ void BuildSubsequentRVAMap(const OmapData& omap_data, // Clips the given mapped range. void ClipMappedRangeOriginal(const AddressRange& clip_range, MappedRange* mapped_range) { - assert(mapped_range != NULL); + assert(mapped_range != nullptr); // The clipping range is entirely outside of the mapped range. if (clip_range.end() <= mapped_range->rva_original || @@ -543,15 +547,15 @@ int AddressRange::Compare(const AddressRange& rhs) const { bool GetOmapDataAndDisableTranslation(IDiaSession* session, OmapData* omap_data) { - assert(session != NULL); - assert(omap_data != NULL); + assert(session != nullptr); + assert(omap_data != nullptr); CComPtr address_map; if (FAILED(session->QueryInterface(&address_map))) { fprintf(stderr, "IDiaSession::QueryInterface(IDiaAddressMap) failed\n"); return false; } - assert(address_map.p != NULL); + assert(address_map.p != nullptr); BOOL omap_enabled = FALSE; if (FAILED(address_map->get_addressMapEnabled(&omap_enabled))) { @@ -593,7 +597,7 @@ bool GetOmapDataAndDisableTranslation(IDiaSession* session, } void BuildImageMap(const OmapData& omap_data, ImageMap* image_map) { - assert(image_map != NULL); + assert(image_map != nullptr); BuildMapping(omap_data, &image_map->mapping); BuildEndpointIndexMap(image_map); @@ -603,7 +607,7 @@ void BuildImageMap(const OmapData& omap_data, ImageMap* image_map) { void MapAddressRange(const ImageMap& image_map, const AddressRange& original_range, AddressRangeVector* mapped_ranges) { - assert(mapped_ranges != NULL); + assert(mapped_ranges != nullptr); const Mapping& map = image_map.mapping; diff --git a/src/common/windows/omap.h b/src/common/windows/omap.h index bc293afb5..51601fa91 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 2a4713d93..cd20d9fb8 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 7fe66bd40..ebe0d47e3 100644 --- a/src/common/windows/omap_unittest.cc +++ b/src/common/windows/omap_unittest.cc @@ -1,329 +1,333 @@ -// 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#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 0eeb30cca..7ae978c7d 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/windows/pdb_source_line_writer.h" #include @@ -40,6 +43,7 @@ #include #include #include +#include #include #include @@ -58,6 +62,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. @@ -99,7 +105,7 @@ void MaybeRecordSymbol(DWORD rva, // Take the 'least' symbol by lexicographical order of the decorated name. We // use the decorated rather than undecorated name because computing the latter // is expensive. - BSTR current_name, new_name; + CComBSTR current_name, new_name; loc->second.symbol->get_name(¤t_name); symbol->get_name(&new_name); if (wcscmp(new_name, current_name) < 0) { @@ -154,11 +160,249 @@ bool CreateDiaDataSourceInstance(CComPtr& data_source) { 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> 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& 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_(nullptr), handle_inline_(handle_inline) {} + PDBSourceLineWriter::~PDBSourceLineWriter() { Close(); } @@ -177,7 +421,7 @@ bool PDBSourceLineWriter::Open(const wstring& file, FileFormat format) { Close(); code_file_.clear(); - if (FAILED(CoInitialize(NULL))) { + if (FAILED(CoInitialize(nullptr))) { fprintf(stderr, "CoInitialize failed\n"); return false; } @@ -192,25 +436,33 @@ 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, nullptr, nullptr); + 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, nullptr, nullptr); + 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,48 +480,83 @@ bool PDBSourceLineWriter::Open(const wstring& file, FileFormat format) { return true; } -bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers* lines) { - // The line number format is: - // - CComPtr line; - ULONG count; - - 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; +int PDBSourceLineWriter::GetCallsiteInlineOriginId( + CComPtr& callsite) { + wstring name; + { + CComBSTR name_bstr; + callsite->get_name(&name_bstr); + if (name.assign(name_bstr, name_bstr.Length()).empty()) { + name = L""; } + } - DWORD length; - if (FAILED(line->get_length(&length))) { - fprintf(stderr, "failed to get line code length\n"); - return false; - } + const int next_id = inline_origins_.size(); + auto iter_inserted = inline_origins_.emplace(std::move(name), next_id); + if (!iter_inserted.second) { + // `name` is already present. Return its previously-assigned unique id. + return iter_inserted.first->second; + } + // `name` was just inserted. Assign it the next id and return this value. + iter_inserted.first->second = next_id; + return next_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); +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; + } + + if (FAILED(dia_line->get_length(&line->length))) { + fprintf(stderr, "failed to get line code length\n"); + return false; + } - DWORD line_num; - if (FAILED(line->get_lineNumber(&line_num))) { - fprintf(stderr, "failed to get line number\n"); + 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); + + if (FAILED(dia_line->get_lineNumber(&line->line_num))) { + fprintf(stderr, "failed to get line number\n"); + return false; + } + return true; +} + +bool PDBSourceLineWriter::GetLines(IDiaEnumLineNumbers* lines, + Lines* line_list) const { + CComPtr 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: + // + 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, @@ -320,9 +607,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> inlines; + if (!GetInlines(block, &line_list, 0, &inlines)) { + return false; + } + PrintInlines(inlines); + } + PrintLines(line_list); return true; } @@ -334,17 +632,21 @@ bool PDBSourceLineWriter::PrintSourceFiles() { } CComPtr compilands; - if (FAILED(global->findChildren(SymTagCompiland, NULL, + if (FAILED(global->findChildren(SymTagCompiland, nullptr, nsNone, &compilands))) { fprintf(stderr, "findChildren failed\n"); 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 compiland; ULONG count; while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) { CComPtr source_files; - if (FAILED(session_->findFile(compiland, NULL, nsNone, &source_files))) { + if (FAILED(session_->findFile(compiland, nullptr, nsNone, &source_files))) { return false; } CComPtr file; @@ -387,14 +689,14 @@ bool PDBSourceLineWriter::PrintFunctions() { return false; } - CComPtr symbols = NULL; + CComPtr symbols = nullptr; // Find all function symbols first. SymbolMap rva_symbol; - hr = global->findChildren(SymTagFunction, NULL, nsNone, &symbols); + hr = global->findChildren(SymTagFunction, nullptr, nsNone, &symbols); if (SUCCEEDED(hr)) { - CComPtr symbol = NULL; + CComPtr symbol = nullptr; while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) { if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) { @@ -413,10 +715,10 @@ bool PDBSourceLineWriter::PrintFunctions() { // Find all public symbols and record public symbols that are not also private // symbols. - hr = global->findChildren(SymTagPublicSymbol, NULL, nsNone, &symbols); + hr = global->findChildren(SymTagPublicSymbol, nullptr, nsNone, &symbols); if (SUCCEEDED(hr)) { - CComPtr symbol = NULL; + CComPtr symbol = nullptr; while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) { if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) { @@ -455,7 +757,7 @@ bool PDBSourceLineWriter::PrintFunctions() { // of those blocks and print out an extra FUNC line for blocks // that are not contained in their parent functions. CComPtr compilands; - if (FAILED(global->findChildren(SymTagCompiland, NULL, + if (FAILED(global->findChildren(SymTagCompiland, nullptr, nsNone, &compilands))) { fprintf(stderr, "findChildren failed on the global\n"); return false; @@ -464,7 +766,7 @@ bool PDBSourceLineWriter::PrintFunctions() { CComPtr compiland; while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) { CComPtr blocks; - if (FAILED(compiland->findChildren(SymTagBlock, NULL, + if (FAILED(compiland->findChildren(SymTagBlock, nullptr, nsNone, &blocks))) { fprintf(stderr, "findChildren failed on a compiland\n"); return false; @@ -503,6 +805,84 @@ bool PDBSourceLineWriter::PrintFunctions() { return true; } +void PDBSourceLineWriter::PrintInlineOrigins() const { + // Inline origins' unique identifiers are assigned sequentially starting from + // zero. Make a reverse-mapping from ids to names, then print the names in + // order of id. + vector names_by_id(inline_origins_.size()); + for (const auto& origin : inline_origins_) { + names_by_id[origin.second] = &origin.first; + } + int id = 0; + for (const wstring* name : names_by_id) { + fprintf(output_, "INLINE_ORIGIN %d %ls\n", id++, name->c_str()); + } +} + +bool PDBSourceLineWriter::GetInlines(IDiaSymbol* block, + Lines* line_list, + int inline_nest_level, + vector>* inlines) { + CComPtr inline_callsites; + if (FAILED(block->findChildrenEx(SymTagInlineSite, nullptr, nsNone, + &inline_callsites))) { + return false; + } + ULONG count; + CComPtr callsite; + while (SUCCEEDED(inline_callsites->Next(1, &callsite, &count)) && + count == 1) { + unique_ptr new_inline(new Inline(inline_nest_level)); + CComPtr 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 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(); + } + new_inline->SetOriginId(GetCallsiteInlineOriginId(callsite)); + new_inline->SetCallSiteLine(call_site_line); + new_inline->SetCallSiteFileId(file_id); + // Go to next level. + vector> 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>& inlines) const { + for (const unique_ptr& in : inlines) { + in->Print(output_); + } +} + #undef max bool PDBSourceLineWriter::PrintFrameDataUsingPDB() { @@ -673,10 +1053,8 @@ 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, @@ -723,7 +1101,7 @@ bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol* symbol, if (rva == 0) break; - CComPtr next_sym = NULL; + CComPtr next_sym = nullptr; LONG displacement; if (FAILED(session_->findSymbolByRVAEx(rva, SymTagPublicSymbol, &next_sym, &displacement))) { @@ -843,19 +1221,9 @@ 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,6 +1247,8 @@ 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. @@ -940,7 +1310,7 @@ int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol* function) { // Gather the symbols corresponding to data. CComPtr data_children; - if (FAILED(function->findChildren(SymTagData, NULL, nsNone, + if (FAILED(function->findChildren(SymTagData, nullptr, nsNone, &data_children))) { return 0; } @@ -1063,12 +1433,10 @@ 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; + output_ = nullptr; return ret; } diff --git a/src/common/windows/pdb_source_line_writer.h b/src/common/windows/pdb_source_line_writer.h index 00f6e5929..c4d7c0613 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 +#include +#include #include #include +#include #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,7 +62,7 @@ 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 @@ -99,9 +103,105 @@ class PDBSourceLineWriter { bool UsesGUID(bool *uses_guid); private: - // Outputs the line/address pairs for each line in the enumerator. + // 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> 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 ranges_; + // The list of direct Inlines inlined inside this Inline. + vector> 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& 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 line_map_; + }; + + // Returns the unique id for the inline origin with the same name as the given + // callsite, creating a new id if needed. + int GetCallsiteInlineOriginId(CComPtr& callsite); + + // 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 +218,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>* inlines); + + // Outputs all inlines. + void PrintInlines(const vector>& 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. @@ -172,8 +291,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::iterator iter = file_ids_.find(id); + DWORD GetRealFileID(DWORD id) const { + unordered_map::const_iterator iter = file_ids_.find(id); if (iter == file_ids_.end()) return id; return iter->second; @@ -213,9 +332,15 @@ class PDBSourceLineWriter { // This maps unique filenames to file IDs. unordered_map unique_files_; + // The INLINE_ORIGINS records; inline origin name -> unique id. + std::map 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 cb6cc7139..d1d25cf43 100644 --- a/src/common/windows/pe_source_line_writer.cc +++ b/src/common/windows/pe_source_line_writer.cc @@ -1,77 +1,80 @@ -// 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#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 2bf1d4fd2..324663bac 100644 --- a/src/common/windows/pe_source_line_writer.h +++ b/src/common/windows/pe_source_line_writer.h @@ -1,69 +1,67 @@ -// 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 - -#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 + +#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(const PESourceLineWriter&) = delete; + void operator=(const PESourceLineWriter&) = delete; + ~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_; +}; + +} // 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 9c94af05f..4af88a4ba 100644 --- a/src/common/windows/pe_util.cc +++ b/src/common/windows/pe_util.cc @@ -1,407 +1,415 @@ -// 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 -#include -#include -#include - -#include - -#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(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( - 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(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(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( - 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( - ImageRvaToVa(img->FileHeader, - img->MappedAddress, - unwind_rva, - &img->LastRvaSection)); - unwind_rva = chained_func->UnwindInfoAddress; - } - - UnwindInfo *unwind_info = static_cast( - 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( - (unwind_info->unwind_code + - ((unwind_info->count_of_codes + 1) & ~1))); - - unwind_info = static_cast( - 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "pe_util.h" + +#include +#include +#include +#include + +#include +#include + +#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(), nullptr)); + 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(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( + 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(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(), nullptr)); + 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(), nullptr)); + if (!img) { + fprintf(stderr, "Failed to load %s\n", img_file.c_str()); + return false; + } + PIMAGE_OPTIONAL_HEADER64 optional_header = + &(reinterpret_cast(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( + 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( + ImageRvaToVa(img->FileHeader, + img->MappedAddress, + unwind_rva, + &img->LastRvaSection)); + unwind_rva = chained_func->UnwindInfoAddress; + } + + UnwindInfo *unwind_info = static_cast( + 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( + (unwind_info->unwind_code + + ((unwind_info->count_of_codes + 1) & ~1))); + + unwind_info = static_cast( + ImageRvaToVa(img->FileHeader, + img->MappedAddress, + chained_func->UnwindInfoAddress, + &img->LastRvaSection)); + } + else { + unwind_info = nullptr; + } + } 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 634ba2934..6c6b364f9 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 - -#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 + +#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 935e19f52..c6f5e0ac1 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. // diff --git a/src/common/windows/string_utils.cc b/src/common/windows/string_utils.cc index 90aab0386..032131208 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. // @@ -27,11 +26,17 @@ // (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 -#include +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif #include "common/windows/string_utils-inl.h" +#include +#include + +#include + namespace google_breakpad { // static @@ -52,13 +57,14 @@ bool WindowsStringUtils::safe_mbstowcs(const string& mbs, wstring* wcs) { size_t wcs_length; #if _MSC_VER >= 1400 // MSVC 2005/8 - errno_t err; - if ((err = mbstowcs_s(&wcs_length, NULL, 0, mbs.c_str(), _TRUNCATE)) != 0) { + errno_t err = mbstowcs_s(&wcs_length, nullptr, 0, mbs.c_str(), _TRUNCATE); + if (err != 0) { return false; } assert(wcs_length > 0); #else // _MSC_VER >= 1400 - if ((wcs_length = mbstowcs(NULL, mbs.c_str(), mbs.length())) == (size_t)-1) { + wcs_length = mbstowcs(nullptr, mbs.c_str(), mbs.length()); + if (wcs_length == (size_t)-1) { return false; } @@ -70,7 +76,7 @@ bool WindowsStringUtils::safe_mbstowcs(const string& mbs, wstring* wcs) { // Now, convert. #if _MSC_VER >= 1400 // MSVC 2005/8 - if ((err = mbstowcs_s(NULL, &wcs_v[0], wcs_length, mbs.c_str(), + if ((err = mbstowcs_s(nullptr, &wcs_v[0], wcs_length, mbs.c_str(), _TRUNCATE)) != 0) { return false; } @@ -95,13 +101,14 @@ bool WindowsStringUtils::safe_wcstombs(const wstring& wcs, string* mbs) { size_t mbs_length; #if _MSC_VER >= 1400 // MSVC 2005/8 - errno_t err; - if ((err = wcstombs_s(&mbs_length, NULL, 0, wcs.c_str(), _TRUNCATE)) != 0) { + errno_t err = wcstombs_s(&mbs_length, nullptr, 0, wcs.c_str(), _TRUNCATE); + if (err != 0) { return false; } assert(mbs_length > 0); #else // _MSC_VER >= 1400 - if ((mbs_length = wcstombs(NULL, wcs.c_str(), wcs.length())) == (size_t)-1) { + mbs_length = wcstombs(nullptr, wcs.c_str(), wcs.length()); + if (mbs_length == (size_t)-1) { return false; } @@ -113,7 +120,7 @@ bool WindowsStringUtils::safe_wcstombs(const wstring& wcs, string* mbs) { // Now, convert. #if _MSC_VER >= 1400 // MSVC 2005/8 - if ((err = wcstombs_s(NULL, &mbs_v[0], mbs_length, wcs.c_str(), + if ((err = wcstombs_s(nullptr, &mbs_v[0], mbs_length, wcs.c_str(), _TRUNCATE)) != 0) { return false; } 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 000000000..ee3b1919e --- /dev/null +++ b/src/common/windows/sym_upload_v2_protocol.cc @@ -0,0 +1,122 @@ +// 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "common/windows/sym_upload_v2_protocol.h" + +#include + +#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 000000000..19e6f87a8 --- /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 + +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 30c663ed3..9695100a0 100644 --- a/src/common/windows/symbol_collector_client.cc +++ b/src/common/windows/symbol_collector_client.cc @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "common/windows/symbol_collector_client.h" #include @@ -12,6 +16,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 +28,7 @@ namespace google_breakpad { url, L"", L"", - NULL, + timeout_ms, &response, &response_code)) { wprintf(L"Failed to create upload url.\n"); @@ -66,25 +71,43 @@ 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; if (!HTTPUpload::SendSimplePostRequest( url, body, - L"application/json", - NULL, + L"Content-Type: application/json", + timeout_ms, &response, &response_code)) { wprintf(L"Failed to complete upload.\n"); @@ -116,6 +139,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 +150,7 @@ namespace google_breakpad { if (!HTTPUpload::SendGetRequest( url, - NULL, + timeout_ms, &response, &response_code)) { wprintf(L"Failed to check symbol status.\n"); @@ -152,4 +176,4 @@ namespace google_breakpad { SymbolStatus::Missing; } -} // namespace google_breakpad \ No newline at end of file +} // namespace google_breakpad diff --git a/src/common/windows/symbol_collector_client.h b/src/common/windows/symbol_collector_client.h index 30e0cb323..4e9bf3b6f 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 ba6c520f7..9a4eb0de9 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -6,8 +6,8 @@ /* Define to 1 if you have the 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,18 +18,27 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the `rustc_demangle' library (-lrustc_demangle). */ +#undef HAVE_LIBRUSTC_DEMANGLE + +/* Define to 1 if you have the `zstd' library (-lzstd). */ +#undef HAVE_LIBZSTD + /* Define to 1 if you have the `memfd_create' function. */ #undef HAVE_MEMFD_CREATE -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD +/* Define to 1 if you have the header file. */ +#undef HAVE_RUSTC_DEMANGLE_H + /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H @@ -82,17 +91,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 d8828043f..efd94e9d7 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 4256706d7..be209801a 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. * @@ -228,7 +227,7 @@ typedef struct { #define MD_CONTEXT_AMD64_ALL (MD_CONTEXT_AMD64_FULL | \ MD_CONTEXT_AMD64_SEGMENTS | \ - MD_CONTEXT_X86_DEBUG_REGISTERS) + MD_CONTEXT_AMD64_DEBUG_REGISTERS) /* CONTEXT_ALL */ diff --git a/src/google_breakpad/common/minidump_cpu_arm.h b/src/google_breakpad/common/minidump_cpu_arm.h index 6a7113833..2ac0623ec 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 0411bebb4..96f263320 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 f4e2b5891..91b700af5 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 b24cc4243..17a71af7c 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 61f419386..75638b5da 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 000000000..812cf5fda --- /dev/null +++ b/src/google_breakpad/common/minidump_cpu_riscv.h @@ -0,0 +1,156 @@ +/* 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_CONTEXT_RISCV_GPR_COUNT 32 +#define MD_CONTEXT_RISCV_FPR_COUNT 32 + +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 | 0x00000002) +#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 version; + + 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; + + /* 32 floating point registers, f0 .. f31. Breakpad only supports RISCV32 + * with 32 bit floating point. */ + uint32_t fpregs[MD_CONTEXT_RISCV_FPR_COUNT]; + uint32_t fcsr; +} 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 | 0x00000002) +#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; + uint32_t version; + + 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; + + /* 32 floating point registers, f0 .. f31. Breakpad only supports RISCV64 with + * 64 bit floating point. */ + uint64_t fpregs[MD_CONTEXT_RISCV_FPR_COUNT]; + uint32_t fcsr; +} 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 95c08b174..6452588a6 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 e09cb7cb5..add1e225d 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 f26a8a2ae..169094b22 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 6138d5d76..a3bc000ee 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. * @@ -34,7 +33,6 @@ * * Author: Mark Mentovai * Split into its own file: Neal Sidhwaney */ - #ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ #define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ @@ -43,43 +41,89 @@ #include "google_breakpad/common/breakpad_types.h" +#if defined(__unix__) || defined(__linux__) || defined(__APPLE__) +#include +#else +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPWR 30 +#define SIGSYS 31 +#endif + +#ifndef SIGSTKFLT +#define SIGSTKFLT 990 /* 16 on x64 */ +#endif +#ifndef SIGPWR +#define SIGPWR 991 /* 30 on x64 */ +#endif /* For (MDException).exception_code. These values come from bits/signum.h. */ typedef enum { - MD_EXCEPTION_CODE_LIN_SIGHUP = 1, /* Hangup (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGINT = 2, /* Interrupt (ANSI) */ - MD_EXCEPTION_CODE_LIN_SIGQUIT = 3, /* Quit (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGILL = 4, /* Illegal instruction (ANSI) */ - MD_EXCEPTION_CODE_LIN_SIGTRAP = 5, /* Trace trap (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGABRT = 6, /* Abort (ANSI) */ - MD_EXCEPTION_CODE_LIN_SIGBUS = 7, /* BUS error (4.2 BSD) */ - MD_EXCEPTION_CODE_LIN_SIGFPE = 8, /* Floating-point exception (ANSI) */ - MD_EXCEPTION_CODE_LIN_SIGKILL = 9, /* Kill, unblockable (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGUSR1 = 10, /* User-defined signal 1 (POSIX). */ - MD_EXCEPTION_CODE_LIN_SIGSEGV = 11, /* Segmentation violation (ANSI) */ - MD_EXCEPTION_CODE_LIN_SIGUSR2 = 12, /* User-defined signal 2 (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGPIPE = 13, /* Broken pipe (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGALRM = 14, /* Alarm clock (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGTERM = 15, /* Termination (ANSI) */ - MD_EXCEPTION_CODE_LIN_SIGSTKFLT = 16, /* Stack faultd */ - MD_EXCEPTION_CODE_LIN_SIGCHLD = 17, /* Child status has changed (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGCONT = 18, /* Continue (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGSTOP = 19, /* Stop, unblockable (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGTSTP = 20, /* Keyboard stop (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGTTIN = 21, /* Background read from tty (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGTTOU = 22, /* Background write to tty (POSIX) */ - MD_EXCEPTION_CODE_LIN_SIGURG = 23, - /* Urgent condition on socket (4.2 BSD) */ - MD_EXCEPTION_CODE_LIN_SIGXCPU = 24, /* CPU limit exceeded (4.2 BSD) */ - MD_EXCEPTION_CODE_LIN_SIGXFSZ = 25, - /* File size limit exceeded (4.2 BSD) */ - MD_EXCEPTION_CODE_LIN_SIGVTALRM = 26, /* Virtual alarm clock (4.2 BSD) */ - MD_EXCEPTION_CODE_LIN_SIGPROF = 27, /* Profiling alarm clock (4.2 BSD) */ - MD_EXCEPTION_CODE_LIN_SIGWINCH = 28, /* Window size change (4.3 BSD, Sun) */ - MD_EXCEPTION_CODE_LIN_SIGIO = 29, /* I/O now possible (4.2 BSD) */ - MD_EXCEPTION_CODE_LIN_SIGPWR = 30, /* Power failure restart (System V) */ - MD_EXCEPTION_CODE_LIN_SIGSYS = 31, /* Bad system call */ + MD_EXCEPTION_CODE_LIN_SIGHUP = SIGHUP, /* Hangup (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGINT = SIGINT, /* Interrupt (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGQUIT = SIGQUIT, /* Quit (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGILL = SIGILL, /* Illegal instruction (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGTRAP = SIGTRAP, /* Trace trap (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGABRT = SIGABRT, /* Abort (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGBUS = SIGBUS, /* BUS error (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGFPE = SIGFPE, /* Floating-point exception (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGKILL = SIGKILL, /* Kill, unblockable (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGUSR1 = SIGUSR1, /* User-defined signal 1 (POSIX). */ + MD_EXCEPTION_CODE_LIN_SIGSEGV = SIGSEGV, /* Segmentation violation (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGUSR2 = SIGUSR2, /* User-defined signal 2 (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGPIPE = SIGPIPE, /* Broken pipe (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGALRM = SIGALRM, /* Alarm clock (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGTERM = SIGTERM, /* Termination (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGSTKFLT = SIGSTKFLT, /* Stack faultd */ + MD_EXCEPTION_CODE_LIN_SIGCHLD = + SIGCHLD, /* Child status has changed (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGCONT = SIGCONT, /* Continue (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGSTOP = SIGSTOP, /* Stop, unblockable (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGTSTP = SIGTSTP, /* Keyboard stop (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGTTIN = + SIGTTIN, /* Background read from tty (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGTTOU = SIGTTOU, /* Background write to tty (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGURG = SIGURG, + /* Urgent condition on socket (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGXCPU = SIGXCPU, /* CPU limit exceeded (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGXFSZ = SIGXFSZ, + /* File size limit exceeded (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGVTALRM = + SIGVTALRM, /* Virtual alarm clock (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGPROF = SIGPROF, /* Profiling alarm clock (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGWINCH = + SIGWINCH, /* Window size change (4.3 BSD, Sun) */ + MD_EXCEPTION_CODE_LIN_SIGIO = SIGIO, /* I/O now possible (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGPWR = SIGPWR, /* Power failure restart (System V) */ + MD_EXCEPTION_CODE_LIN_SIGSYS = SIGSYS, /* Bad system call */ MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED = 0xFFFFFFFF /* No exception, dump requested. */ } MDExceptionCodeLinux; @@ -113,6 +157,11 @@ typedef enum { MD_EXCEPTION_FLAG_LIN_SEGV_ACCERR = 2, MD_EXCEPTION_FLAG_LIN_SEGV_BNDERR = 3, MD_EXCEPTION_FLAG_LIN_SEGV_PKUERR = 4, + MD_EXCEPTION_FLAG_LIN_SEGV_ACCADI = 5, + MD_EXCEPTION_FLAG_LIN_SEGV_ADIDERR = 6, + MD_EXCEPTION_FLAG_LIN_SEGV_ADIPERR = 7, + MD_EXCEPTION_FLAG_LIN_SEGV_MTEAERR = 8, + MD_EXCEPTION_FLAG_LIN_SEGV_MTESERR = 9, /* SIGBUS */ MD_EXCEPTION_FLAG_LIN_BUS_ADRALN = 1, @@ -122,4 +171,4 @@ typedef enum { MD_EXCEPTION_FLAG_LIN_BUS_MCEERR_AO = 5, } MDExceptionFlagLinux; -#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */ +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */ diff --git a/src/google_breakpad/common/minidump_exception_mac.h b/src/google_breakpad/common/minidump_exception_mac.h index fadbf4ef6..acfafaa0f 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 adff5a6bb..dd87d7a73 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 f18ddf424..16641919a 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 4b5d57c85..0431a3fa7 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 7b36d1127..959d15ba2 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; @@ -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; @@ -1070,10 +1096,23 @@ typedef struct { MDRawSimpleStringDictionaryEntry entries[0]; } MDRawSimpleStringDictionary; +typedef struct { + MDRVA name; + uint16_t type; + uint16_t reserved; + MDRVA value; +} MDRawCrashpadAnnotation; + +typedef struct { + uint32_t count; + MDRawCrashpadAnnotation objects[0]; +} MDRawCrashpadAnnotationList; + typedef struct { uint32_t version; MDLocationDescriptor list_annotations; MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */ + MDLocationDescriptor annotation_objects; /* MDRawCrashpadAnnotationList */ } MDRawModuleCrashpadInfo; typedef struct { @@ -1083,7 +1122,7 @@ typedef struct { typedef struct { uint32_t count; - MDLocationDescriptor modules[0]; /* MDRawModuleCrashpadInfoLink */ + MDRawModuleCrashpadInfoLink modules[0]; } MDRawModuleCrashpadInfoList; 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 fae57923c..f9abdc361 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 1c7bf465c..e86b28d2c 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 #include +#include #include "common/using_std_string.h" #include "google_breakpad/processor/source_line_resolver_base.h" @@ -84,6 +84,8 @@ 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 . // Notice, that this method modifies the input |file_line| which is why it @@ -94,6 +96,39 @@ class SymbolParseHelper { long* index, // out char** filename); // out + // Parses a |inline_origin_line| declaration. Returns true on success. + // Old Format: INLINE_ORIGIN . + // New Format: INLINE_ORIGIN . + // Notice, that this method modifies the input |inline_origin_line| which is + // why it can't be const. On success, , , + // and 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 + // [
]+ + // New Format: INLINE + // [
]+ + // Notice, that this method modifies the input |inline| + // which is why it can't be const. On success, , + // , and are stored in + // |*has_call_site_file_id*|, |*inline_nest_level|, |*call_site_line|, and + // |*origin_id|, and all pairs of (
, ) 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>* ranges); // out + // Parses a |function_line| declaration. Returns true on success. // Format: FUNC []
. // Notice, that this method modifies the input |function_line| which is why it diff --git a/src/google_breakpad/processor/call_stack.h b/src/google_breakpad/processor/call_stack.h index c59142315..a18f8f74b 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. // @@ -45,7 +44,8 @@ #ifndef GOOGLE_BREAKPAD_PROCESSOR_CALL_STACK_H__ #define GOOGLE_BREAKPAD_PROCESSOR_CALL_STACK_H__ -#include +#include + #include namespace google_breakpad { diff --git a/src/google_breakpad/processor/code_module.h b/src/google_breakpad/processor/code_module.h index 29b8d9c9a..76bbfab81 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 74f113c19..b7f726760 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. // @@ -35,8 +34,6 @@ #ifndef GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULES_H__ #define GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULES_H__ -#include - #include #include "google_breakpad/common/breakpad_types.h" diff --git a/src/google_breakpad/processor/dump_context.h b/src/google_breakpad/processor/dump_context.h index df80bf7ef..7a1c643e2 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 112f687f4..0b1f48844 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 eac6c90ae..aa2b0de30 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 014413c94..0b51ba135 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 fdf910776..11cec75ed 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 30f88df49..378fcc39b 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 02ebdcd79..2a2bdec6c 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. // @@ -39,10 +38,10 @@ #ifndef GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_H__ #define GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_H__ +#include #include #include -#include "common/scoped_ptr.h" #include "common/using_std_string.h" #include "google_breakpad/processor/dump_context.h" #include "google_breakpad/processor/memory_region.h" @@ -122,10 +121,10 @@ class Microdump { string GetCrashReason() { return crash_reason_; } uint64_t GetCrashAddress() { return crash_address_; } private: - scoped_ptr context_; - scoped_ptr stack_region_; - scoped_ptr modules_; - scoped_ptr system_info_; + std::unique_ptr context_; + std::unique_ptr stack_region_; + std::unique_ptr modules_; + std::unique_ptr system_info_; string crash_reason_; uint64_t crash_address_; }; diff --git a/src/google_breakpad/processor/microdump_processor.h b/src/google_breakpad/processor/microdump_processor.h index 60d14a541..abf468f48 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 1c40a821a..e523ab367 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. // @@ -90,7 +89,6 @@ #include #include -#include "common/basictypes.h" #include "common/using_std_string.h" #include "google_breakpad/processor/code_module.h" #include "google_breakpad/processor/code_modules.h" @@ -115,7 +113,7 @@ template class RangeMap; // itself. class MinidumpObject : public DumpObject { public: - virtual ~MinidumpObject() {} + virtual ~MinidumpObject() = default; protected: explicit MinidumpObject(Minidump* minidump); @@ -137,7 +135,9 @@ class MinidumpObject : public DumpObject { // same interface, and may be derived from this class. class MinidumpStream : public MinidumpObject { public: - virtual ~MinidumpStream() {} + MinidumpStream(const MinidumpStream&) = delete; + void operator=(const MinidumpStream&) = delete; + ~MinidumpStream() override = default; protected: explicit MinidumpStream(Minidump* minidump); @@ -151,8 +151,6 @@ class MinidumpStream : public MinidumpObject { // that implements MinidumpStream can compare expected_size to a // known size as an integrity check. virtual bool Read(uint32_t expected_size) = 0; - - DISALLOW_COPY_AND_ASSIGN(MinidumpStream); }; @@ -168,7 +166,9 @@ class MinidumpStream : public MinidumpObject { // user wants). class MinidumpContext : public DumpContext { public: - virtual ~MinidumpContext(); + MinidumpContext(const MinidumpContext&) = delete; + void operator=(const MinidumpContext&) = delete; + ~MinidumpContext() override; protected: explicit MinidumpContext(Minidump* minidump); @@ -193,8 +193,6 @@ class MinidumpContext : public DumpContext { // for access to data about the minidump file itself, such as whether // it should be byte-swapped. Minidump* minidump_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpContext); }; @@ -209,7 +207,7 @@ class MinidumpContext : public DumpContext { class MinidumpMemoryRegion : public MinidumpObject, public MemoryRegion { public: - virtual ~MinidumpMemoryRegion(); + ~MinidumpMemoryRegion() override; static void set_max_bytes(uint32_t max_bytes) { max_bytes_ = max_bytes; } static uint32_t max_bytes() { return max_bytes_; } @@ -220,22 +218,22 @@ class MinidumpMemoryRegion : public MinidumpObject, const uint8_t* GetMemory() const; // The address of the base of the memory region. - uint64_t GetBase() const; + uint64_t GetBase() const override; // The size, in bytes, of the memory region. - uint32_t GetSize() const; + uint32_t GetSize() const override; // Frees the cached memory region, if cached. void FreeMemory(); // Obtains the value of memory at the pointer specified by address. - bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const; - bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const; - bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const; - bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const; + 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; // Print a human-readable representation of the object to stdout. - void Print() const; + void Print() const override; void SetPrintMode(bool hexdump, unsigned int width); protected: @@ -278,9 +276,9 @@ class MinidumpMemoryRegion : public MinidumpObject, // contain a memory region or context. class MinidumpThread : public MinidumpObject { public: - virtual ~MinidumpThread(); + ~MinidumpThread() override; - const MDRawThread* thread() const { return valid_ ? &thread_ : NULL; } + const MDRawThread* thread() const { return valid_ ? &thread_ : nullptr; } // GetMemory may return NULL even if the MinidumpThread is valid, // if the thread memory cannot be read. virtual MinidumpMemoryRegion* GetMemory(); @@ -323,7 +321,9 @@ class MinidumpThread : public MinidumpObject { // a process. class MinidumpThreadList : public MinidumpStream { public: - virtual ~MinidumpThreadList(); + MinidumpThreadList(const MinidumpThreadList&) = delete; + void operator=(const MinidumpThreadList&) = delete; + ~MinidumpThreadList() override; static void set_max_threads(uint32_t max_threads) { max_threads_ = max_threads; @@ -365,11 +365,89 @@ class MinidumpThreadList : public MinidumpStream { // The list of threads. MinidumpThreads* threads_; - uint32_t thread_count_; + uint32_t thread_count_; +}; + +// MinidumpThreadName contains the name of a thread. +class MinidumpThreadName : public MinidumpObject { + public: + ~MinidumpThreadName() override; + + const MDRawThreadName* thread_name() const { + return valid_ ? &thread_name_ : nullptr; + } + + // 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(); - DISALLOW_COPY_AND_ASSIGN(MinidumpThreadList); + // 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: + MinidumpThreadNameList(const MinidumpThreadNameList&) = delete; + void operator=(const MinidumpThreadNameList&) = delete; + ~MinidumpThreadNameList() override; + + 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 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_; +}; // MinidumpModule wraps MDRawModule, which contains information about loaded // code modules. Access is provided to various data referenced indirectly @@ -378,7 +456,7 @@ class MinidumpThreadList : public MinidumpStream { class MinidumpModule : public MinidumpObject, public CodeModule { public: - virtual ~MinidumpModule(); + ~MinidumpModule() override; static void set_max_cv_bytes(uint32_t max_cv_bytes) { max_cv_bytes_ = max_cv_bytes; @@ -390,27 +468,27 @@ class MinidumpModule : public MinidumpObject, } static uint32_t max_misc_bytes() { return max_misc_bytes_; } - const MDRawModule* module() const { return valid_ ? &module_ : NULL; } + const MDRawModule* module() const { return valid_ ? &module_ : nullptr; } // CodeModule implementation - virtual uint64_t base_address() const { + uint64_t base_address() const override { return valid_ ? module_.base_of_image : static_cast(-1); } - virtual uint64_t size() const { return valid_ ? module_.size_of_image : 0; } - virtual string code_file() const; - virtual string code_identifier() const; - virtual string debug_file() const; - virtual string debug_identifier() const; - virtual string version() const; - virtual CodeModule* Copy() const; - virtual bool is_unloaded() const { return false; } + uint64_t size() const override { return valid_ ? module_.size_of_image : 0; } + string code_file() const override; + string code_identifier() const override; + string debug_file() const override; + string debug_identifier() const override; + string version() const override; + CodeModule* Copy() const override; + bool is_unloaded() const override { return false; } // Getter and setter for shrink_down_delta. This is used when the address // range for a module is shrunk down due to address range conflicts with // other modules. The base_address and size fields are not updated and they // should always reflect the original values (reported in the minidump). - virtual uint64_t shrink_down_delta() const; - virtual void SetShrinkDownDelta(uint64_t shrink_down_delta); + uint64_t shrink_down_delta() const override; + void SetShrinkDownDelta(uint64_t shrink_down_delta) override; // The CodeView record, which contains information to locate the module's // debugging information (pdb). This is returned as uint8_t* because @@ -501,7 +579,9 @@ class MinidumpModule : public MinidumpObject, class MinidumpModuleList : public MinidumpStream, public CodeModules { public: - virtual ~MinidumpModuleList(); + MinidumpModuleList(const MinidumpModuleList&) = delete; + void operator=(const MinidumpModuleList&) = delete; + ~MinidumpModuleList() override; static void set_max_modules(uint32_t max_modules) { max_modules_ = max_modules; @@ -509,19 +589,19 @@ class MinidumpModuleList : public MinidumpStream, static uint32_t max_modules() { return max_modules_; } // CodeModules implementation. - virtual unsigned int module_count() const { + unsigned int module_count() const override { return valid_ ? module_count_ : 0; } - virtual const MinidumpModule* GetModuleForAddress(uint64_t address) const; - virtual const MinidumpModule* GetMainModule() const; - virtual const MinidumpModule* GetModuleAtSequence( - unsigned int sequence) const; - virtual const MinidumpModule* GetModuleAtIndex(unsigned int index) const; - virtual const CodeModules* Copy() const; + const MinidumpModule* GetModuleForAddress(uint64_t address) const override; + const MinidumpModule* GetMainModule() const override; + const MinidumpModule* GetModuleAtSequence( + unsigned int sequence) const override; + const MinidumpModule* GetModuleAtIndex(unsigned int index) const override; + const CodeModules* Copy() const override; // Returns a vector of all modules which address ranges needed to be shrunk // down due to address range conflicts with other modules. - virtual vector > GetShrunkRangeModules() const; + vector> GetShrunkRangeModules() const override; // Print a human-readable representation of the object to stdout. void Print(); @@ -536,7 +616,7 @@ class MinidumpModuleList : public MinidumpStream, static const uint32_t kStreamType = MD_MODULE_LIST_STREAM; - bool Read(uint32_t expected_size); + bool Read(uint32_t expected_size) override; bool StoreRange(const MinidumpModule& module, uint64_t base_address, @@ -553,8 +633,6 @@ class MinidumpModuleList : public MinidumpStream, MinidumpModules* modules_; uint32_t module_count_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpModuleList); }; @@ -569,7 +647,9 @@ class MinidumpModuleList : public MinidumpStream, // memory minidumps contain all of a process' mapped memory. class MinidumpMemoryList : public MinidumpStream { public: - virtual ~MinidumpMemoryList(); + MinidumpMemoryList(const MinidumpMemoryList&) = delete; + void operator=(const MinidumpMemoryList&) = delete; + ~MinidumpMemoryList() override; static void set_max_regions(uint32_t max_regions) { max_regions_ = max_regions; @@ -617,8 +697,6 @@ class MinidumpMemoryList : public MinidumpStream { // The list of regions. MemoryRegions* regions_; uint32_t region_count_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpMemoryList); }; @@ -630,10 +708,12 @@ class MinidumpMemoryList : public MinidumpStream { // occurred. class MinidumpException : public MinidumpStream { public: - virtual ~MinidumpException(); + MinidumpException(const MinidumpException&) = delete; + void operator=(const MinidumpException&) = delete; + ~MinidumpException() override; const MDRawExceptionStream* exception() const { - return valid_ ? &exception_ : NULL; + return valid_ ? &exception_ : nullptr; } // The thread ID is used to determine if a thread is the exception thread, @@ -657,19 +737,19 @@ class MinidumpException : public MinidumpStream { bool Read(uint32_t expected_size) override; MDRawExceptionStream exception_; - MinidumpContext* context_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpException); + MinidumpContext* context_; }; // MinidumpAssertion wraps MDRawAssertionInfo, which contains information // about an assertion that caused the minidump to be generated. class MinidumpAssertion : public MinidumpStream { public: - virtual ~MinidumpAssertion(); + MinidumpAssertion(const MinidumpAssertion&) = delete; + void operator=(const MinidumpAssertion&) = delete; + ~MinidumpAssertion() override; const MDRawAssertionInfo* assertion() const { - return valid_ ? &assertion_ : NULL; + return valid_ ? &assertion_ : nullptr; } string expression() const { @@ -700,8 +780,6 @@ class MinidumpAssertion : public MinidumpStream { string expression_; string function_; string file_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpAssertion); }; @@ -709,10 +787,12 @@ class MinidumpAssertion : public MinidumpStream { // the system on which the minidump was generated. See also MinidumpMiscInfo. class MinidumpSystemInfo : public MinidumpStream { public: - virtual ~MinidumpSystemInfo(); + MinidumpSystemInfo(const MinidumpSystemInfo&) = delete; + void operator=(const MinidumpSystemInfo&) = delete; + ~MinidumpSystemInfo() override; const MDRawSystemInfo* system_info() const { - return valid_ ? &system_info_ : NULL; + return valid_ ? &system_info_ : nullptr; } // GetOS and GetCPU return textual representations of the operating system @@ -755,8 +835,6 @@ class MinidumpSystemInfo : public MinidumpStream { // A string identifying the CPU vendor, if known. const string* cpu_vendor_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpSystemInfo); }; @@ -767,7 +845,7 @@ class MinidumpUnloadedModule : public MinidumpObject, ~MinidumpUnloadedModule() override; const MDRawUnloadedModule* module() const { - return valid_ ? &unloaded_module_ : NULL; + return valid_ ? &unloaded_module_ : nullptr; } // CodeModule implementation @@ -824,6 +902,8 @@ class MinidumpUnloadedModule : public MinidumpObject, class MinidumpUnloadedModuleList : public MinidumpStream, public CodeModules { public: + MinidumpUnloadedModuleList(const MinidumpUnloadedModuleList&) = delete; + void operator=(const MinidumpUnloadedModuleList&) = delete; ~MinidumpUnloadedModuleList() override; static void set_max_modules(uint32_t max_modules) { @@ -866,8 +946,6 @@ class MinidumpUnloadedModuleList : public MinidumpStream, MinidumpUnloadedModules* unloaded_modules_; uint32_t module_count_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpUnloadedModuleList); }; @@ -876,8 +954,11 @@ class MinidumpUnloadedModuleList : public MinidumpStream, // information. See also MinidumpSystemInfo. class MinidumpMiscInfo : public MinidumpStream { public: + MinidumpMiscInfo(const MinidumpMiscInfo&) = delete; + void operator=(const MinidumpMiscInfo&) = delete; + const MDRawMiscInfo* misc_info() const { - return valid_ ? &misc_info_ : NULL; + return valid_ ? &misc_info_ : nullptr; } // Print a human-readable representation of the object to stdout. @@ -901,8 +982,6 @@ class MinidumpMiscInfo : public MinidumpStream { string daylight_name_; string build_string_; string dbg_bld_str_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpMiscInfo); }; @@ -911,8 +990,11 @@ class MinidumpMiscInfo : public MinidumpStream { // at the time the minidump was generated. class MinidumpBreakpadInfo : public MinidumpStream { public: + MinidumpBreakpadInfo(const MinidumpBreakpadInfo&) = delete; + void operator=(const MinidumpBreakpadInfo&) = delete; + const MDRawBreakpadInfo* breakpad_info() const { - return valid_ ? &breakpad_info_ : NULL; + return valid_ ? &breakpad_info_ : nullptr; } // These thread IDs are used to determine if threads deserve special @@ -935,8 +1017,6 @@ class MinidumpBreakpadInfo : public MinidumpStream { bool Read(uint32_t expected_size_) override; MDRawBreakpadInfo breakpad_info_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpBreakpadInfo); }; // MinidumpMemoryInfo wraps MDRawMemoryInfo, which provides information @@ -944,7 +1024,9 @@ class MinidumpBreakpadInfo : public MinidumpStream { // and protection. class MinidumpMemoryInfo : public MinidumpObject { public: - const MDRawMemoryInfo* info() const { return valid_ ? &memory_info_ : NULL; } + const MDRawMemoryInfo* info() const { + return valid_ ? &memory_info_ : nullptr; + } // The address of the base of the memory region. uint64_t GetBase() const { return valid_ ? memory_info_.base_address : 0; } @@ -981,7 +1063,9 @@ class MinidumpMemoryInfo : public MinidumpObject { // info corresponding to a specific address. class MinidumpMemoryInfoList : public MinidumpStream { public: - virtual ~MinidumpMemoryInfoList(); + MinidumpMemoryInfoList(const MinidumpMemoryInfoList&) = delete; + void operator=(const MinidumpMemoryInfoList&) = delete; + ~MinidumpMemoryInfoList() override; unsigned int info_count() const { return valid_ ? info_count_ : 0; } @@ -1007,14 +1091,15 @@ class MinidumpMemoryInfoList : public MinidumpStream { MinidumpMemoryInfos* infos_; uint32_t info_count_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpMemoryInfoList); }; // MinidumpLinuxMaps wraps information about a single mapped memory region // from /proc/self/maps. class MinidumpLinuxMaps : public MinidumpObject { public: + MinidumpLinuxMaps(const MinidumpLinuxMaps&) = delete; + void operator=(const MinidumpLinuxMaps&) = delete; + // The memory address of the base of the mapped region. uint64_t GetBase() const { return valid_ ? region_.start : 0; } // The size of the mapped region. @@ -1060,8 +1145,6 @@ class MinidumpLinuxMaps : public MinidumpObject { // The memory region struct that this class wraps. MappedMemoryRegion region_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpLinuxMaps); }; // MinidumpLinuxMapsList corresponds to the Linux-exclusive MD_LINUX_MAPS @@ -1069,7 +1152,9 @@ class MinidumpLinuxMaps : public MinidumpObject { // the mapped memory regions and their access permissions. class MinidumpLinuxMapsList : public MinidumpStream { public: - virtual ~MinidumpLinuxMapsList(); + MinidumpLinuxMapsList(const MinidumpLinuxMapsList&) = delete; + void operator=(const MinidumpLinuxMapsList&) = delete; + ~MinidumpLinuxMapsList() override; // Get number of mappings. unsigned int get_maps_count() const { return valid_ ? maps_count_ : 0; } @@ -1101,8 +1186,6 @@ class MinidumpLinuxMapsList : public MinidumpStream { MinidumpLinuxMappings* maps_; // The number of mappings. uint32_t maps_count_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpLinuxMapsList); }; // MinidumpCrashpadInfo wraps MDRawCrashpadInfo, which is an optional stream in @@ -1110,8 +1193,19 @@ 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 value; + }; + const MDRawCrashpadInfo* crashpad_info() const { - return valid_ ? &crashpad_info_ : NULL; + return valid_ ? &crashpad_info_ : nullptr; + } + + const std::vector>* + GetModuleCrashpadInfoAnnotationObjects() const { + return valid_ ? &module_crashpad_info_annotation_objects_ : nullptr; } // Print a human-readable representation of the object to stdout. @@ -1132,6 +1226,9 @@ class MinidumpCrashpadInfo : public MinidumpStream { std::vector> module_crashpad_info_list_annotations_; std::vector> module_crashpad_info_simple_annotations_; + std::vector> + module_crashpad_info_annotation_objects_; + std::map simple_annotations_; }; @@ -1149,6 +1246,9 @@ class Minidump { // is valid as long as the Minidump object is. explicit Minidump(std::istream& input); + Minidump(const Minidump&) = delete; + void operator=(const Minidump&) = delete; + virtual ~Minidump(); // path may be empty if the minidump was not opened from a file @@ -1165,7 +1265,9 @@ class Minidump { } static uint32_t max_string_length() { return max_string_length_; } - virtual const MDRawHeader* header() const { return valid_ ? &header_ : NULL; } + virtual const MDRawHeader* header() const { + return valid_ ? &header_ : nullptr; + } // Reads the CPU information from the system info stream and generates the // appropriate CPU flags. The returned context_cpu_flags are the same as @@ -1188,6 +1290,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(); @@ -1240,6 +1343,10 @@ class Minidump { off_t offset, std::map* simple_string_dictionary); + bool ReadCrashpadAnnotationsList( + off_t offset, + std::vector* 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 @@ -1276,7 +1383,7 @@ class Minidump { // the Minidump object locate interesting streams quickly, and // provides a convenient place to stash MinidumpStream objects. struct MinidumpStreamInfo { - MinidumpStreamInfo() : stream_index(0), stream(NULL) {} + MinidumpStreamInfo() : stream_index(0), stream(nullptr) {} ~MinidumpStreamInfo() { delete stream; } // Index into the MinidumpDirectoryEntries vector @@ -1338,8 +1445,6 @@ class Minidump { // Knobs for controlling display of memory printing. bool hexdump_; unsigned int hexdump_width_; - - DISALLOW_COPY_AND_ASSIGN(Minidump); }; diff --git a/src/google_breakpad/processor/minidump_processor.h b/src/google_breakpad/processor/minidump_processor.h index 414050e97..2a5b07499 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. // @@ -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 @@ -125,8 +126,23 @@ class MinidumpProcessor { // does not exist or cannot be determined. static string GetAssertion(Minidump* dump); + // Sets the flag to enable/disable use of objdump during normal crash + // processing. This is independent from the flag for use of objdump during + // exploitability analysis. void set_enable_objdump(bool enabled) { enable_objdump_ = enabled; } + // Sets the flag to enable/disable use of objdump during exploitability + // analysis. This is independent from the flag for use of objdump during + // normal crash processing. + void set_enable_objdump_for_exploitability(bool enabled) { + enable_objdump_for_exploitability_ = enabled; + } + + // Sets the maximum number of threads to process. + void set_max_thread_count(int max_thread_count) { + max_thread_count_ = max_thread_count; + } + private: StackFrameSymbolizer* frame_symbolizer_; // Indicate whether resolver_helper_ is owned by this instance. @@ -137,9 +153,19 @@ class MinidumpProcessor { // memory corruption issue. bool enable_exploitability_; - // This flag permits the exploitability scanner to shell out to objdump - // for purposes of disassembly. + // This flag permits the processor to shell out to objdump for purposes of + // disassembly during normal crash processing, but not during exploitability + // analysis. bool enable_objdump_; + + // This flag permits the exploitability scanner to shell out to objdump for + // purposes of disassembly. This results in significantly more overhead than + // the enable_objdump_ flag. + bool enable_objdump_for_exploitability_; + + // The maximum number of threads to process. This can be exceeded if the + // requesting thread comes after the limit. Setting this to -1 means no limit. + int max_thread_count_; }; } // namespace google_breakpad diff --git a/src/google_breakpad/processor/proc_maps_linux.h b/src/google_breakpad/processor/proc_maps_linux.h index 3045daa5f..b99414c34 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 15c7213e9..780060d9a 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 9bc44c450..50f3d5889 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. // @@ -92,7 +91,7 @@ enum ExploitabilityRating { class ProcessState { public: - ProcessState() : modules_(NULL), unloaded_modules_(NULL) { Clear(); } + ProcessState() : modules_(nullptr), unloaded_modules_(nullptr) { Clear(); } ~ProcessState(); // Resets the ProcessState to its default values @@ -106,11 +105,13 @@ class ProcessState { uint64_t crash_address() const { return crash_address_; } string assertion() const { return assertion_; } int requesting_thread() const { return requesting_thread_; } + int original_thread_count() const { return original_thread_count_; } const ExceptionRecord* exception_record() const { return &exception_record_; } const vector* threads() const { return &threads_; } const vector* thread_memory_regions() const { return &thread_memory_regions_; } + const vector* 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_; } @@ -168,6 +169,11 @@ class ProcessState { // indicating that the dump thread is not available. int requesting_thread_; + // Original thread count. The Processor has limit on how many threads to + // process, so not all threads are processed. This tells you how many threads + // were originally in the minudump. + int original_thread_count_; + // Exception record details: code, flags, address, parameters. ExceptionRecord exception_record_; @@ -176,6 +182,12 @@ class ProcessState { vector threads_; vector 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 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 fea1657c2..4c64bfc91 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 #include #include #include @@ -84,11 +84,15 @@ class SourceLineResolverBase : public SourceLineResolverInterface { virtual void UnloadModule(const CodeModule* module); virtual bool HasModule(const CodeModule* module); virtual bool IsModuleCorrupt(const CodeModule* module); - virtual void FillSourceLineInfo(StackFrame* frame); + virtual void FillSourceLineInfo( + StackFrame* frame, + std::deque>* 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; diff --git a/src/google_breakpad/processor/source_line_resolver_interface.h b/src/google_breakpad/processor/source_line_resolver_interface.h index 990114043..9f1f50c91 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 +#include #include +#include #include "common/using_std_string.h" #include "google_breakpad/common/breakpad_types.h" @@ -91,8 +93,12 @@ class SourceLineResolverInterface { // 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>* inlined_frames) = 0; // If Windows stack walking information is available covering // FRAME's instruction address, return a WindowsFrameInfo structure diff --git a/src/google_breakpad/processor/stack_frame.h b/src/google_breakpad/processor/stack_frame.h index 1491d7882..5960f89b4 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,19 +49,24 @@ 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() : instruction(), - module(NULL), + module(nullptr), 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 dc5d8ae67..086a6f5a4 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. // @@ -73,8 +72,8 @@ struct StackFrameX86 : public StackFrame { StackFrameX86() : context(), context_validity(CONTEXT_VALID_NONE), - windows_frame_info(NULL), - cfi_frame_info(NULL) {} + windows_frame_info(nullptr), + cfi_frame_info(nullptr) {} ~StackFrameX86(); // Overriden to return the return address as saved on the stack. @@ -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 0bbaae0a3..ed342ce65 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 +#include #include #include +#include #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>* 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 daa5039ae..e5d88c806 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. // diff --git a/src/google_breakpad/processor/symbol_supplier.h b/src/google_breakpad/processor/symbol_supplier.h index 6ec017665..b1c235351 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. // diff --git a/src/google_breakpad/processor/system_info.h b/src/google_breakpad/processor/system_info.h index 8d2f60be4..01c48182b 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 96d955ad7..e1b944d1e 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. // diff --git a/src/processor/address_map.h b/src/processor/address_map.h index 87321a7f6..8a4f7ba85 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. // diff --git a/src/processor/address_map_unittest.cc b/src/processor/address_map_unittest.cc index 7c85f5ebd..6ea811257 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. // @@ -31,6 +30,10 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -108,7 +111,7 @@ static bool DoAddressMapTest() { ASSERT_EQ(entry->id(), 1); ASSERT_EQ(address, 10); ASSERT_TRUE(test_map.Retrieve(11, &entry, &address)); - ASSERT_TRUE(test_map.Retrieve(11, &entry, NULL)); // NULL ok here + ASSERT_TRUE(test_map.Retrieve(11, &entry, nullptr)); // nullptr ok here // Add some more elements. ASSERT_TRUE(test_map.Store(5, diff --git a/src/processor/basic_code_module.h b/src/processor/basic_code_module.h index 75272897d..9da62d928 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. // diff --git a/src/processor/basic_code_modules.cc b/src/processor/basic_code_modules.cc index f71aeb747..23008c3fa 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. // @@ -34,6 +33,10 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "processor/basic_code_modules.h" #include @@ -80,7 +83,8 @@ BasicCodeModules::BasicCodeModules(const CodeModules* that, linked_ptr module(that->GetModuleAtIndex(i)->Copy()); uint64_t delta = 0; if (map_.RetrieveRange(module->base_address() + module->size() - 1, - &module, NULL /* base */, &delta, NULL /* size */) && + &module, nullptr /* base */, &delta, + nullptr /* size */) && delta > 0) { BPLOG(INFO) << "The range for module " << module->code_file() << " was shrunk down by " << HexString(delta) << " bytes."; @@ -106,10 +110,10 @@ unsigned int BasicCodeModules::module_count() const { const CodeModule* BasicCodeModules::GetModuleForAddress( uint64_t address) const { linked_ptr module; - if (!map_.RetrieveRange(address, &module, NULL /* base */, NULL /* delta */, - NULL /* size */)) { + if (!map_.RetrieveRange(address, &module, nullptr /* base */, + nullptr /* delta */, nullptr /* size */)) { BPLOG(INFO) << "No module at " << HexString(address); - return NULL; + return nullptr; } return module.get(); @@ -122,10 +126,10 @@ const CodeModule* BasicCodeModules::GetMainModule() const { const CodeModule* BasicCodeModules::GetModuleAtSequence( unsigned int sequence) const { linked_ptr module; - if (!map_.RetrieveRangeAtIndex(sequence, &module, NULL /* base */, - NULL /* delta */, NULL /* size */)) { + if (!map_.RetrieveRangeAtIndex(sequence, &module, nullptr /* base */, + nullptr /* delta */, nullptr /* size */)) { BPLOG(ERROR) << "RetrieveRangeAtIndex failed for sequence " << sequence; - return NULL; + return nullptr; } return module.get(); diff --git a/src/processor/basic_code_modules.h b/src/processor/basic_code_modules.h index 8c26abb1e..2eaf49ecc 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. // @@ -41,8 +40,6 @@ #ifndef PROCESSOR_BASIC_CODE_MODULES_H__ #define PROCESSOR_BASIC_CODE_MODULES_H__ -#include - #include #include "google_breakpad/processor/code_modules.h" diff --git a/src/processor/basic_source_line_resolver.cc b/src/processor/basic_source_line_resolver.cc index 64d400156..20037b1a7 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. // @@ -32,6 +31,10 @@ // See basic_source_line_resolver.h and basic_source_line_resolver_types.h // for documentation. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -40,6 +43,7 @@ #include #include +#include #include #include @@ -49,9 +53,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 { @@ -125,6 +131,7 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory( linked_ptr cur_func; int line_number = 0; int num_errors = 0; + int inline_num_errors = 0; char* save_ptr; // If the length is 0, we can still pretend we have a symbol file. This is @@ -163,7 +170,7 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory( char* buffer; buffer = strtok_r(memory_buffer, "\r\n", &save_ptr); - while (buffer != NULL) { + while (buffer != nullptr) { ++line_number; if (strncmp(buffer, "FILE ", 5) == 0) { @@ -202,6 +209,17 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory( // Ignore these as well, they're similarly just for housekeeping. // // INFO CODE_ID + } else if (strncmp(buffer, "INLINE ", 7) == 0) { + linked_ptr 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", @@ -219,13 +237,73 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory( if (num_errors > kMaxErrorsBeforeBailing) { break; } - buffer = strtok_r(NULL, "\r\n", &save_ptr); + buffer = strtok_r(nullptr, "\r\n", &save_ptr); } is_corrupt_ = num_errors > 0; return true; } -void BasicSourceLineResolver::Module::LookupAddress(StackFrame* frame) const { +void BasicSourceLineResolver::Module::ConstructInlineFrames( + StackFrame* frame, + MemAddr address, + const ContainedRangeMap>& inline_map, + deque>* inlined_frames) const { + vector*> inlines; + if (!inline_map.RetrieveRanges(address, inlines)) { + return; + } + + for (const linked_ptr* const in : inlines) { + unique_ptr new_frame = + unique_ptr(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 = ""; + } + + // 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& 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>* inlined_frames) const { MemAddr address = frame->instruction - frame->module->base_address(); // First, look for a FUNC record that covers address. Use @@ -240,15 +318,16 @@ void BasicSourceLineResolver::Module::LookupAddress(StackFrame* frame) const { MemAddr function_size; MemAddr public_address; if (functions_.RetrieveNearestRange(address, &func, &function_base, - NULL /* delta */, &function_size) && + nullptr /* delta */, &function_size) && 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; MemAddr line_base; - if (func->lines.RetrieveRange(address, &line, &line_base, NULL /* delta */, - NULL /* size */)) { + if (func->lines.RetrieveRange(address, &line, &line_base, + nullptr /* delta */, nullptr /* size */)) { FileMap::const_iterator it = files_.find(line->source_file_id); if (it != files_.end()) { frame->source_file_name = files_.find(line->source_file_id)->second; @@ -256,18 +335,24 @@ 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 { MemAddr address = frame->instruction - frame->module->base_address(); - scoped_ptr result(new WindowsFrameInfo()); + std::unique_ptr result(new WindowsFrameInfo()); // We only know about WindowsFrameInfo::STACK_INFO_FRAME_DATA and // WindowsFrameInfo::STACK_INFO_FPO. Prefer them in this order. @@ -294,7 +379,7 @@ WindowsFrameInfo* BasicSourceLineResolver::Module::FindWindowsFrameInfo( linked_ptr function; MemAddr function_base, function_size; if (functions_.RetrieveNearestRange(address, &function, &function_base, - NULL /* delta */, &function_size) && + nullptr /* delta */, &function_size) && address >= function_base && address - function_base < function_size) { result->parameter_size = function->parameter_size; result->valid |= WindowsFrameInfo::VALID_PARAMETER_SIZE; @@ -310,7 +395,7 @@ WindowsFrameInfo* BasicSourceLineResolver::Module::FindWindowsFrameInfo( result->parameter_size = public_symbol->parameter_size; } - return NULL; + return nullptr; } CFIFrameInfo* BasicSourceLineResolver::Module::FindCFIFrameInfo( @@ -324,15 +409,15 @@ CFIFrameInfo* BasicSourceLineResolver::Module::FindCFIFrameInfo( // forward from the initial rule's starting address to frame's // instruction address, applying delta rules. if (!cfi_initial_rules_.RetrieveRange(address, &initial_rules, &initial_base, - NULL /* delta */, &initial_size)) { - return NULL; + nullptr /* delta */, &initial_size)) { + return nullptr; } // Create a frame info structure, and populate it with the rules from // the STACK CFI INIT record. - scoped_ptr rules(new CFIFrameInfo()); + std::unique_ptr rules(new CFIFrameInfo()); if (!ParseCFIRuleSet(initial_rules, rules.get())) - return NULL; + return nullptr; // Find the first delta rule that falls within the initial rule's range. map::const_iterator delta = @@ -357,6 +442,41 @@ 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::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> 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(new Inline(has_call_site_file_id, + inline_nest_level, call_site_line, + call_site_file_id, origin_id, ranges)); + } + return linked_ptr(); +} + BasicSourceLineResolver::Function* BasicSourceLineResolver::Module::ParseFunction(char* function_line) { bool is_multiple; @@ -368,7 +488,7 @@ BasicSourceLineResolver::Module::ParseFunction(char* function_line) { &size, &stack_param_size, &name)) { return new Function(name, address, size, stack_param_size, is_multiple); } - return NULL; + return nullptr; } BasicSourceLineResolver::Line* BasicSourceLineResolver::Module::ParseLine( @@ -382,7 +502,7 @@ BasicSourceLineResolver::Line* BasicSourceLineResolver::Module::ParseLine( &source_file)) { return new Line(address, size, source_file, line_number); } - return NULL; + return nullptr; } bool BasicSourceLineResolver::Module::ParsePublicSymbol(char* public_line) { @@ -433,7 +553,7 @@ bool BasicSourceLineResolver::Module::ParseStackInfo(char* stack_info_line) { type, rva, code_size)); - if (stack_frame_info == NULL) + if (stack_frame_info == nullptr) return false; // TODO(mmentovai): I wanted to use StoreRange's return value as this @@ -478,30 +598,43 @@ bool BasicSourceLineResolver::Module::ParseCFIFrameInfo( if (strcmp(init_or_address, "INIT") == 0) { // This record has the form "STACK INIT
". - char* address_field = strtok_r(NULL, " \r\n", &cursor); + char* address_field = strtok_r(nullptr, " \r\n", &cursor); if (!address_field) return false; - char* size_field = strtok_r(NULL, " \r\n", &cursor); + char* size_field = strtok_r(nullptr, " \r\n", &cursor); if (!size_field) return false; - char* initial_rules = strtok_r(NULL, "\r\n", &cursor); + char* initial_rules = strtok_r(nullptr, "\r\n", &cursor); if (!initial_rules) return false; - MemAddr address = strtoul(address_field, NULL, 16); - MemAddr size = strtoul(size_field, NULL, 16); + MemAddr address = strtoul(address_field, nullptr, 16); + MemAddr size = strtoul(size_field, nullptr, 16); cfi_initial_rules_.StoreRange(address, size, initial_rules); return true; } // This record has the form "STACK
". char* address_field = init_or_address; - char* delta_rules = strtok_r(NULL, "\r\n", &cursor); + char* delta_rules = strtok_r(nullptr, "\r\n", &cursor); if (!delta_rules) return false; - MemAddr address = strtoul(address_field, NULL, 16); + MemAddr address = strtoul(address_field, nullptr, 16); cfi_delta_rules_[address] = delta_rules; return true; } +bool BasicSourceLineResolver::Function::AppendInline(linked_ptr 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) { @@ -529,6 +662,146 @@ bool SymbolParseHelper::ParseFile(char* file_line, long* index, return true; } +// static +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 + // New INLINE_ORIGIN format: + // INLINE_ORIGIN + assert(strncmp(inline_origin_line, "INLINE_ORIGIN ", 14) == 0); + inline_origin_line += 14; // skip prefix + vector tokens; + // Split the line into two parts so that the first token is "", and + // second token is either " "" or """ 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::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 " " to {"", ""}. + 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::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>* ranges) { + // Old INLINE format: + // INLINE [
]+ + // New INLINE format: + // INLINE + // [
]+ + assert(strncmp(inline_line, "INLINE ", 7) == 0); + inline_line += 7; // skip prefix + + vector 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::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::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::max()) { + return false; + } + } + + *origin_id = strtol(tokens[next_idx++], &after_number, 10); + if (!IsValidAfterNumber(after_number) || *origin_id < 0 || + *origin_id == std::numeric_limits::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::max()) { + return false; + } + MemAddr size = strtoull(tokens[next_idx++], &after_number, 16); + if (!IsValidAfterNumber(after_number) || + size == std::numeric_limits::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, @@ -648,7 +921,8 @@ bool SymbolParseHelper::ParsePublicSymbol(char* public_line, bool* is_multiple, // static bool SymbolParseHelper::IsValidAfterNumber(char* after_number) { - if (after_number != NULL && strchr(kWhitespace, *after_number) != NULL) { + if (after_number != nullptr && + strchr(kWhitespace, *after_number) != nullptr) { return true; } return false; diff --git a/src/processor/basic_source_line_resolver_types.h b/src/processor/basic_source_line_resolver_types.h index c103040dd..66fcbc6b8 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. // @@ -40,7 +39,6 @@ #include #include -#include "common/scoped_ptr.h" #include "google_breakpad/processor/basic_source_line_resolver.h" #include "processor/source_line_resolver_base_types.h" @@ -61,15 +59,27 @@ BasicSourceLineResolver::Function : public SourceLineResolverBase::Function { 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 > 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 in); + + ContainedRangeMap> inlines; + RangeMap> lines; + private: typedef SourceLineResolverBase::Function Base; + + // The last added inline_nest_level from INLINE record. + int last_added_inline_nest_level; }; @@ -92,7 +102,19 @@ 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>* 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>& inline_map, + std::deque>* inline_frames) const; // If Windows stack walking information is available covering ADDRESS, // return a WindowsFrameInfo structure describing it. If the information @@ -125,6 +147,12 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module { // Parses a file declaration bool ParseFile(char* file_line); + // Parses an inline origin declaration. + bool ParseInlineOrigin(char* inline_origin_line); + + // Parses an inline declaration. + linked_ptr ParseInline(char* inline_line); + // Parses a function declaration, returning a new Function object. Function* ParseFunction(char* function_line); @@ -144,6 +172,7 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module { string name_; FileMap files_; + std::map> inline_origins_; RangeMap< MemAddr, linked_ptr > functions_; AddressMap< MemAddr, linked_ptr > 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 2cb2967ca..9cfd915ed 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. // @@ -27,13 +26,17 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include +#include #include #include "breakpad_googletest_includes.h" -#include "common/scoped_ptr.h" #include "common/using_std_string.h" #include "google_breakpad/processor/basic_source_line_resolver.h" #include "google_breakpad/processor/code_module.h" @@ -52,13 +55,11 @@ 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; class TestCodeModule : public CodeModule { public: - TestCodeModule(string code_file) : code_file_(code_file) {} + TestCodeModule(const string& code_file) : code_file_(code_file) {} virtual ~TestCodeModule() {} virtual uint64_t base_address() const { return 0; } @@ -93,12 +94,12 @@ class MockMemoryRegion: public MemoryRegion { } 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; } @@ -158,13 +159,13 @@ static bool VerifyEmpty(const StackFrame& frame) { static void ClearSourceLineInfo(StackFrame* frame) { frame->function_name.clear(); - frame->module = NULL; + frame->module = nullptr; frame->source_file_name.clear(); frame->source_line = 0; } class TestBasicSourceLineResolver : public ::testing::Test { -public: + public: void SetUp() { testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") + "/src/processor/testdata"; @@ -185,20 +186,21 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve) StackFrame frame; - scoped_ptr windows_frame_info; - scoped_ptr cfi_frame_info; + std::unique_ptr windows_frame_info; + std::unique_ptr cfi_frame_info; frame.instruction = 0x1000; - frame.module = NULL; - resolver.FillSourceLineInfo(&frame); + frame.module = nullptr; + 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 +208,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 +219,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 +236,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 +345,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 +364,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,6 +419,96 @@ 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> 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> 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 TEST(SymbolParseHelper, ParseFileValid) { @@ -736,6 +832,176 @@ TEST(SymbolParseHelper, ParsePublicSymbolInvalid) { &name)); } +// Test parsing of valid INLINE_ORIGIN lines. +// The old format: +// INLINE_ORIGIN +// The new format: +// INLINE_ORIGIN +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 +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 [
]+ +// The new format: +// INLINE +// [
]+ +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> 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> 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[]) { diff --git a/src/processor/call_stack.cc b/src/processor/call_stack.cc index f219e8431..6ecae6dcb 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. // @@ -33,6 +32,10 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/stack_frame.h" diff --git a/src/processor/cfi_frame_info-inl.h b/src/processor/cfi_frame_info-inl.h index 52d2f5fc7..acfc4f795 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. // diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc index 280620f23..1aef1e36b 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. // @@ -32,8 +31,13 @@ // cfi_frame_info.cc: Implementation of CFIFrameInfo class. // See cfi_frame_info.h for details. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "processor/cfi_frame_info.h" +#include #include #include @@ -81,7 +85,7 @@ bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap& registers, working = registers; working[".cfa"] = cfa; if (!evaluator.EvaluateForValue(it->second, &value)) - return false; + continue; (*caller_registers)[it->first] = value; } @@ -158,7 +162,7 @@ bool CFIRuleParser::Parse(const string& rule_set) { expression_ += ' '; expression_ += token; } - token = strtok_r(NULL, token_breaks, &cursor); + token = strtok_r(nullptr, token_breaks, &cursor); } } diff --git a/src/processor/cfi_frame_info.h b/src/processor/cfi_frame_info.h index 2bc933360..08f1eb72b 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. // diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_info_unittest.cc index 8111437a6..dcbd7721b 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. // @@ -32,6 +31,10 @@ // cfi_frame_info_unittest.cc: Unit tests for CFIFrameInfo, // CFIRuleParser, CFIFrameInfoParseHandler, and SimpleCFIWalker. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "breakpad_googletest_includes.h" @@ -254,8 +257,9 @@ TEST_F(Scope, RegsLackRA) { cfi.SetCFARule("42740329"); cfi.SetRARule("27045204"); cfi.SetRegisterRule("$r1", ".ra"); - ASSERT_FALSE(cfi.FindCallerRegs(registers, memory, - &caller_registers)); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(caller_registers.end(), caller_registers.find("$r1")); } // Register rules can see the current frame's register values. @@ -439,6 +443,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 +454,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 { @@ -479,11 +485,11 @@ struct SimpleCFIWalkerFixture { SimpleCFIWalkerFixture::CFIWalker::RegisterSet SimpleCFIWalkerFixture::register_map[7] = { - { "r0", NULL, true, R0_VALID, &RawContext::r0 }, - { "r1", NULL, true, R1_VALID, &RawContext::r1 }, - { "r2", NULL, false, R2_VALID, &RawContext::r2 }, - { "r3", NULL, false, R3_VALID, &RawContext::r3 }, - { "r4", NULL, true, R4_VALID, &RawContext::r4 }, + { "r0", nullptr, true, R0_VALID, &RawContext::r0 }, + { "r1", nullptr, true, R1_VALID, &RawContext::r1 }, + { "r2", nullptr, false, R2_VALID, &RawContext::r2 }, + { "r3", nullptr, false, R3_VALID, &RawContext::r3 }, + { "r4", nullptr, true, R4_VALID, &RawContext::r4 }, { "sp", ".cfa", true, SP_VALID, &RawContext::sp }, { "pc", ".ra", true, PC_VALID, &RawContext::pc }, }; diff --git a/src/processor/contained_range_map-inl.h b/src/processor/contained_range_map-inl.h index edd11d7cf..301c62128 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. // @@ -84,10 +83,12 @@ bool ContainedRangeMap::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::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 = nullptr; if (iterator_base != iterator_high) { // The children of this range that are contained by the new range must @@ -141,8 +142,10 @@ bool ContainedRangeMap::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; } @@ -177,6 +180,20 @@ bool ContainedRangeMap::RetrieveRange( return true; } +template +bool ContainedRangeMap::RetrieveRanges( + const AddressType& address, + std::vector& 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 void ContainedRangeMap::Clear() { @@ -186,7 +203,7 @@ void ContainedRangeMap::Clear() { delete child->second; delete map_; - map_ = NULL; + map_ = nullptr; } } diff --git a/src/processor/contained_range_map.h b/src/processor/contained_range_map.h index 18d03af7a..3f5a4959a 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 +#include namespace google_breakpad { @@ -75,7 +75,11 @@ 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_(nullptr), + allow_equal_range_(allow_equal_range) {} ~ContainedRangeMap(); @@ -95,7 +99,12 @@ class ContainedRangeMap { // 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& entries) const; // Removes all children. Note that Clear only removes descendants, // leaving the node on which it is called intact. Because the only @@ -118,9 +127,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 @@ -141,6 +155,12 @@ class ContainedRangeMap { // address. This is a pointer to avoid allocating map structures for // leaf nodes, where they are not needed. 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 a97c5d0f9..1d681fdfd 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. // @@ -31,6 +30,10 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "processor/contained_range_map-inl.h" @@ -51,9 +54,82 @@ namespace { using google_breakpad::ContainedRangeMap; +// The first is the querying address, the second is the entries vector result. +using EntriesTestPair = std::pair>; +using EntriesTestPairVec = std::vector; + +static bool RunTestsWithRetrieveRange( + const ContainedRangeMap& 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 + for (unsigned int address = 0; address < test_length; ++address) { + int value; + if (!crm.RetrieveRange(address, &value)) + value = 0; -static bool RunTests() { +#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& crm, + const EntriesTestPairVec& entries_tests) { + for (const EntriesTestPair& entries_test : entries_tests) { + std::vector 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 crm; // First, do the StoreRange tests. This validates the containment @@ -211,45 +287,89 @@ 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 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(); } diff --git a/src/processor/convert_old_arm64_context.cc b/src/processor/convert_old_arm64_context.cc index d4b749e7f..768475b2f 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "processor/convert_old_arm64_context.h" #include diff --git a/src/processor/convert_old_arm64_context.h b/src/processor/convert_old_arm64_context.h index 8c0dfe900..241b9259b 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 000000000..3e0b6d196 --- /dev/null +++ b/src/processor/disassembler_objdump.cc @@ -0,0 +1,493 @@ +// 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 + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "processor/disassembler_objdump.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "common/linux/eintr_wrapper.h" +#include "common/linux/scoped_pipe.h" +#include "common/linux/scoped_tmpfile.h" +#include "processor/logging.h" + +namespace google_breakpad { +namespace { + +const size_t kMaxX86InstructionLength = 15; + +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, + const 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, + const 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, + const 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, + const 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, + const 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, + const 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 a temporary file for the raw instruction bytes to pass to + // objdump, and write the bytes to the input file. + ScopedTmpFile raw_bytes_file; + if (!raw_bytes_file.InitData(raw_bytes, raw_bytes_len)) { + BPLOG(ERROR) << "Failed creating temporary file."; + return false; + } + + // Create a pipe to use to read the disassembly back from objdump. + ScopedPipe disassembly_pipe; + if (!disassembly_pipe.Init()) { + BPLOG(ERROR) << "Failed creating pipe for output."; + return false; + } + + pid_t child_pid = fork(); + if (child_pid < 0) { + BPLOG(ERROR) << "Fork failed."; + return false; + } + + if (child_pid == 0) { + // In the child process, set up the input and output file descriptors. + if (dup2(raw_bytes_file.GetFd(), STDIN_FILENO) < 0 || + disassembly_pipe.Dup2WriteFd(STDOUT_FILENO) < 0 || + disassembly_pipe.Dup2WriteFd(STDERR_FILENO) < 0) { + BPLOG(ERROR) << "Failed dup'ing file descriptors."; + exit(-1); + } + + // We need to close the read end of the pipe in the child process so that + // when the parent closes it, the pipe is disconnected. + disassembly_pipe.CloseReadFd(); + + // We use "/proc/self/fd/0" here to allow objdump to parse an unnamed file, + // since objdump does not have a mode to read from stdin. This cannot be + // used with a pipe, since objdump requires that the input is a standard + // file. + execlp("objdump", "objdump", "-D", "--no-show-raw-insn", "-b", "binary", + "-M", "intel", "-m", architecture.c_str(), "/proc/self/fd/0", + nullptr); + + BPLOG(ERROR) << "Failed to exec objdump."; + exit(-1); + } else { + // In the parent process, parse the objdump output. + + // 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; + while (disassembly_pipe.ReadLine(line)) { + if (std::regex_match(line, match, instruction_regex)) { + instruction = match[1].str(); + break; + } + } + + // Close the read pipe so that objdump will exit (in case we broke out of + // the loop above before reading all of the output). + disassembly_pipe.CloseReadFd(); + + // Now wait for objdump to exit. + int status = 0; + HANDLE_EINTR(waitpid(child_pid, &status, 0)); + + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + BPLOG(ERROR) << "objdump didn't run successfully."; + return false; + } + + if (instruction == "") { + BPLOG(ERROR) << "Failed to find instruction in objdump output."; + return false; + } + } + + 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 diff --git a/src/processor/disassembler_objdump.h b/src/processor/disassembler_objdump.h new file mode 100644 index 000000000..7db1e1110 --- /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 + +#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 000000000..30a60da5a --- /dev/null +++ b/src/processor/disassembler_objdump_unittest.cc @@ -0,0 +1,468 @@ +// 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include +#include + +#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 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 bytes_; +}; + +TestMemoryRegion::TestMemoryRegion(uint64_t address, std::vector bytes) + : base_(address), bytes_(bytes) {} + +uint64_t TestMemoryRegion::GetBase() const { + return base_; +} + +uint32_t TestMemoryRegion::GetSize() const { + return static_cast(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 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 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 012676785..16d864ca6 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. // @@ -24,6 +33,10 @@ // // Author: Cris Neckar +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "processor/disassembler_x86.h" #include @@ -43,26 +56,26 @@ DisassemblerX86::DisassemblerX86(const uint8_t* bytecode, pushed_bad_value_(false), end_of_block_(false), flags_(0) { - libdis::x86_init(libdis::opt_none, NULL, NULL); + x86_init(opt_none, nullptr, nullptr); } DisassemblerX86::~DisassemblerX86() { if (instr_valid_) - libdis::x86_oplist_free(¤t_instr_); + x86_oplist_free(¤t_instr_); - libdis::x86_cleanup(); + x86_cleanup(); } uint32_t DisassemblerX86::NextInstruction() { if (instr_valid_) - libdis::x86_oplist_free(¤t_instr_); + x86_oplist_free(¤t_instr_); if (current_byte_offset_ >= size_) { instr_valid_ = false; return 0; } uint32_t instr_size = 0; - instr_size = libdis::x86_disasm((unsigned char*)bytecode_, size_, + instr_size = x86_disasm((unsigned char*)bytecode_, size_, virtual_address_, current_byte_offset_, ¤t_instr_); if (instr_size == 0) { @@ -72,39 +85,39 @@ uint32_t DisassemblerX86::NextInstruction() { current_byte_offset_ += instr_size; current_inst_offset_++; - instr_valid_ = libdis::x86_insn_is_valid(¤t_instr_); + instr_valid_ = x86_insn_is_valid(¤t_instr_); if (!instr_valid_) return 0; - if (current_instr_.type == libdis::insn_return) + if (current_instr_.type == 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_); + x86_op_t* src = x86_get_src_operand(¤t_instr_); + x86_op_t* dest = x86_get_dest_operand(¤t_instr_); if (register_valid_) { switch (current_instr_.group) { // Flag branches based off of bad registers and calls that occur // after pushing bad values. - case libdis::insn_controlflow: + case insn_controlflow: switch (current_instr_.type) { - case libdis::insn_jmp: - case libdis::insn_jcc: - case libdis::insn_call: - case libdis::insn_callcc: + case insn_jmp: + case insn_jcc: + case insn_call: + case insn_callcc: if (dest) { switch (dest->type) { - case libdis::op_expression: + case op_expression: if (dest->data.expression.base.id == bad_register_.id) flags_ |= DISX86_BAD_BRANCH_TARGET; break; - case libdis::op_register: + case op_register: if (dest->data.reg.id == bad_register_.id) flags_ |= DISX86_BAD_BRANCH_TARGET; break; default: if (pushed_bad_value_ && - (current_instr_.type == libdis::insn_call || - current_instr_.type == libdis::insn_callcc)) + (current_instr_.type == insn_call || + current_instr_.type == insn_callcc)) flags_ |= DISX86_BAD_ARGUMENT_PASSED; break; } @@ -116,24 +129,24 @@ uint32_t DisassemblerX86::NextInstruction() { break; // Flag block data operations that use bad registers for src or dest. - case libdis::insn_string: - if (dest && dest->type == libdis::op_expression && + case insn_string: + if (dest && dest->type == op_expression && dest->data.expression.base.id == bad_register_.id) flags_ |= DISX86_BAD_BLOCK_WRITE; - if (src && src->type == libdis::op_expression && + if (src && src->type == op_expression && src->data.expression.base.id == bad_register_.id) flags_ |= DISX86_BAD_BLOCK_READ; break; // Flag comparisons based on bad data. - case libdis::insn_comparison: - if ((dest && dest->type == libdis::op_expression && + case insn_comparison: + if ((dest && dest->type == op_expression && dest->data.expression.base.id == bad_register_.id) || - (src && src->type == libdis::op_expression && + (src && src->type == op_expression && src->data.expression.base.id == bad_register_.id) || - (dest && dest->type == libdis::op_register && + (dest && dest->type == op_register && dest->data.reg.id == bad_register_.id) || - (src && src->type == libdis::op_register && + (src && src->type == op_register && src->data.reg.id == bad_register_.id)) flags_ |= DISX86_BAD_COMPARISON; break; @@ -141,10 +154,10 @@ uint32_t DisassemblerX86::NextInstruction() { // Flag any other instruction which derefs a bad register for // src or dest. default: - if (dest && dest->type == libdis::op_expression && + if (dest && dest->type == op_expression && dest->data.expression.base.id == bad_register_.id) flags_ |= DISX86_BAD_WRITE; - if (src && src->type == libdis::op_expression && + if (src && src->type == op_expression && src->data.expression.base.id == bad_register_.id) flags_ |= DISX86_BAD_READ; break; @@ -153,14 +166,14 @@ uint32_t DisassemblerX86::NextInstruction() { // When a register is marked as tainted check if it is pushed. // TODO(cdn): may also want to check for MOVs into EBP offsets. - if (register_valid_ && dest && current_instr_.type == libdis::insn_push) { + if (register_valid_ && dest && current_instr_.type == insn_push) { switch (dest->type) { - case libdis::op_expression: + case op_expression: if (dest->data.expression.base.id == bad_register_.id || dest->data.expression.index.id == bad_register_.id) pushed_bad_value_ = true; break; - case libdis::op_register: + case op_register: if (dest->data.reg.id == bad_register_.id) pushed_bad_value_ = true; break; @@ -174,31 +187,31 @@ uint32_t DisassemblerX86::NextInstruction() { // there is a hit. if (register_valid_) { switch (current_instr_.type) { - case libdis::insn_xor: - if (src && src->type == libdis::op_register && - dest && dest->type == libdis::op_register && + case insn_xor: + if (src && src->type == op_register && + dest && dest->type == op_register && src->data.reg.id == bad_register_.id && src->data.reg.id == dest->data.reg.id) register_valid_ = false; break; - case libdis::insn_pop: - case libdis::insn_mov: - case libdis::insn_movcc: - if (dest && dest->type == libdis::op_register && + case insn_pop: + case insn_mov: + case insn_movcc: + if (dest && dest->type == op_register && dest->data.reg.id == bad_register_.id) register_valid_ = false; break; - case libdis::insn_popregs: + case insn_popregs: register_valid_ = false; break; - case libdis::insn_xchg: - case libdis::insn_xchgcc: - if (dest && dest->type == libdis::op_register && - src && src->type == libdis::op_register) { + case insn_xchg: + case insn_xchgcc: + if (dest && dest->type == op_register && + src && src->type == op_register) { if (dest->data.reg.id == bad_register_.id) - memcpy(&bad_register_, &src->data.reg, sizeof(libdis::x86_reg_t)); + memcpy(&bad_register_, &src->data.reg, sizeof(x86_reg_t)); else if (src->data.reg.id == bad_register_.id) - memcpy(&bad_register_, &dest->data.reg, sizeof(libdis::x86_reg_t)); + memcpy(&bad_register_, &dest->data.reg, sizeof(x86_reg_t)); } break; default: @@ -213,12 +226,12 @@ bool DisassemblerX86::setBadRead() { if (!instr_valid_) return false; - libdis::x86_op_t* operand = libdis::x86_get_src_operand(¤t_instr_); - if (!operand || operand->type != libdis::op_expression) + x86_op_t* operand = x86_get_src_operand(¤t_instr_); + if (!operand || operand->type != op_expression) return false; memcpy(&bad_register_, &operand->data.expression.base, - sizeof(libdis::x86_reg_t)); + sizeof(x86_reg_t)); register_valid_ = true; return true; } @@ -227,12 +240,12 @@ bool DisassemblerX86::setBadWrite() { if (!instr_valid_) return false; - libdis::x86_op_t* operand = libdis::x86_get_dest_operand(¤t_instr_); - if (!operand || operand->type != libdis::op_expression) + x86_op_t* operand = x86_get_dest_operand(¤t_instr_); + if (!operand || operand->type != op_expression) return false; memcpy(&bad_register_, &operand->data.expression.base, - sizeof(libdis::x86_reg_t)); + sizeof(x86_reg_t)); register_valid_ = true; return true; } diff --git a/src/processor/disassembler_x86.h b/src/processor/disassembler_x86.h index ca65b6e89..4f3b6bf57 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. // @@ -36,14 +36,10 @@ #ifndef GOOGLE_BREAKPAD_PROCESSOR_DISASSEMBLER_X86_H_ #define GOOGLE_BREAKPAD_PROCESSOR_DISASSEMBLER_X86_H_ -#include #include #include "google_breakpad/common/breakpad_types.h" - -namespace libdis { #include "third_party/libdisasm/libdis.h" -} namespace google_breakpad { @@ -78,12 +74,12 @@ class DisassemblerX86 { // Returns the current instruction as defined in libdis.h, // or NULL if the current instruction is not valid. - const libdis::x86_insn_t* currentInstruction() { - return instr_valid_ ? ¤t_instr_ : NULL; + const x86_insn_t* currentInstruction() { + return instr_valid_ ? ¤t_instr_ : nullptr; } // Returns the type of the current instruction as defined in libdis.h. - libdis::x86_insn_group currentInstructionGroup() { + x86_insn_group currentInstructionGroup() { return current_instr_.group; } @@ -109,12 +105,12 @@ class DisassemblerX86 { uint32_t current_inst_offset_; bool instr_valid_; - libdis::x86_insn_t current_instr_; + x86_insn_t current_instr_; // TODO(cdn): Maybe also track an expression's index register. // ex: mov eax, [ebx + ecx]; ebx is base, ecx is index. bool register_valid_; - libdis::x86_reg_t bad_register_; + x86_reg_t bad_register_; bool pushed_bad_value_; bool end_of_block_; diff --git a/src/processor/disassembler_x86_unittest.cc b/src/processor/disassembler_x86_unittest.cc index 352905f20..9bb57af88 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,11 @@ // 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif #include @@ -85,13 +88,13 @@ TEST(DisassemblerX86Test, SimpleReturnInstruction) { EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_TRUE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup()); - const libdis::x86_insn_t* instruction = dis.currentInstruction(); - EXPECT_EQ(libdis::insn_controlflow, instruction->group); - EXPECT_EQ(libdis::insn_return, instruction->type); + EXPECT_EQ(insn_controlflow, dis.currentInstructionGroup()); + const x86_insn_t* instruction = dis.currentInstruction(); + EXPECT_EQ(insn_controlflow, instruction->group); + EXPECT_EQ(insn_return, instruction->type); EXPECT_EQ(0U, dis.NextInstruction()); EXPECT_FALSE(dis.currentInstructionValid()); - EXPECT_EQ(NULL, dis.currentInstruction()); + EXPECT_EQ(nullptr, dis.currentInstruction()); } TEST(DisassemblerX86Test, SimpleInvalidInstruction) { @@ -106,18 +109,18 @@ TEST(DisassemblerX86Test, BadReadLeadsToBranch) { EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(insn_move, dis.currentInstructionGroup()); EXPECT_TRUE(dis.setBadRead()); EXPECT_EQ(2U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_logic, dis.currentInstructionGroup()); + EXPECT_EQ(insn_logic, dis.currentInstructionGroup()); EXPECT_EQ(2U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(google_breakpad::DISX86_BAD_BRANCH_TARGET, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup()); + EXPECT_EQ(insn_controlflow, dis.currentInstructionGroup()); } TEST(DisassemblerX86Test, BadWriteLeadsToPushedArg) { @@ -127,13 +130,13 @@ TEST(DisassemblerX86Test, BadWriteLeadsToPushedArg) { EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(insn_move, dis.currentInstructionGroup()); EXPECT_TRUE(dis.setBadWrite()); EXPECT_EQ(3U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup()); + EXPECT_EQ(insn_arithmetic, dis.currentInstructionGroup()); EXPECT_EQ(1U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); @@ -141,7 +144,7 @@ TEST(DisassemblerX86Test, BadWriteLeadsToPushedArg) { EXPECT_EQ(5U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(google_breakpad::DISX86_BAD_ARGUMENT_PASSED, dis.flags()); - EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup()); + EXPECT_EQ(insn_controlflow, dis.currentInstructionGroup()); EXPECT_FALSE(dis.endOfBlock()); } @@ -152,18 +155,18 @@ TEST(DisassemblerX86Test, BadReadLeadsToBlockWrite) { EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(insn_move, dis.currentInstructionGroup()); EXPECT_TRUE(dis.setBadRead()); EXPECT_EQ(2U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(insn_move, dis.currentInstructionGroup()); EXPECT_EQ(2U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(google_breakpad::DISX86_BAD_BLOCK_WRITE, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_string, dis.currentInstructionGroup()); + EXPECT_EQ(insn_string, dis.currentInstructionGroup()); } TEST(DisassemblerX86Test, BadReadClobberThenWrite) { @@ -172,18 +175,18 @@ TEST(DisassemblerX86Test, BadReadClobberThenWrite) { EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup()); + EXPECT_EQ(insn_arithmetic, dis.currentInstructionGroup()); EXPECT_TRUE(dis.setBadRead()); EXPECT_EQ(2U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(insn_move, dis.currentInstructionGroup()); EXPECT_EQ(2U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(insn_move, dis.currentInstructionGroup()); } TEST(DisassemblerX86Test, BadReadXCHGThenWrite) { @@ -192,23 +195,23 @@ TEST(DisassemblerX86Test, BadReadXCHGThenWrite) { EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup()); + EXPECT_EQ(insn_arithmetic, dis.currentInstructionGroup()); EXPECT_TRUE(dis.setBadRead()); EXPECT_EQ(1U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(insn_move, dis.currentInstructionGroup()); EXPECT_EQ(2U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(insn_move, dis.currentInstructionGroup()); EXPECT_EQ(2U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(google_breakpad::DISX86_BAD_WRITE, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(insn_move, dis.currentInstructionGroup()); } TEST(DisassemblerX86Test, BadReadThenCMP) { @@ -217,17 +220,17 @@ TEST(DisassemblerX86Test, BadReadThenCMP) { EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(0U, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup()); + EXPECT_EQ(insn_arithmetic, dis.currentInstructionGroup()); EXPECT_TRUE(dis.setBadRead()); EXPECT_EQ(3U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(google_breakpad::DISX86_BAD_COMPARISON, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_comparison, dis.currentInstructionGroup()); + EXPECT_EQ(insn_comparison, dis.currentInstructionGroup()); EXPECT_EQ(2U, dis.NextInstruction()); EXPECT_TRUE(dis.currentInstructionValid()); EXPECT_EQ(google_breakpad::DISX86_BAD_COMPARISON, dis.flags()); EXPECT_FALSE(dis.endOfBlock()); - EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup()); + EXPECT_EQ(insn_controlflow, dis.currentInstructionGroup()); } } diff --git a/src/processor/dump_context.cc b/src/processor/dump_context.cc index da531b74d..372fee5ee 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. // @@ -31,6 +30,10 @@ // // See dump_context.h for documentation. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/dump_context.h" #include @@ -70,7 +73,7 @@ uint32_t DumpContext::GetContextFlags() const { const MDRawContextX86* DumpContext::GetContextX86() const { if (GetContextCPU() != MD_CONTEXT_X86) { BPLOG(ERROR) << "DumpContext cannot get x86 context"; - return NULL; + return nullptr; } return context_.x86; @@ -79,7 +82,7 @@ const MDRawContextX86* DumpContext::GetContextX86() const { const MDRawContextPPC* DumpContext::GetContextPPC() const { if (GetContextCPU() != MD_CONTEXT_PPC) { BPLOG(ERROR) << "DumpContext cannot get ppc context"; - return NULL; + return nullptr; } return context_.ppc; @@ -88,7 +91,7 @@ const MDRawContextPPC* DumpContext::GetContextPPC() const { const MDRawContextPPC64* DumpContext::GetContextPPC64() const { if (GetContextCPU() != MD_CONTEXT_PPC64) { BPLOG(ERROR) << "DumpContext cannot get ppc64 context"; - return NULL; + return nullptr; } return context_.ppc64; @@ -97,7 +100,7 @@ const MDRawContextPPC64* DumpContext::GetContextPPC64() const { const MDRawContextAMD64* DumpContext::GetContextAMD64() const { if (GetContextCPU() != MD_CONTEXT_AMD64) { BPLOG(ERROR) << "DumpContext cannot get amd64 context"; - return NULL; + return nullptr; } return context_.amd64; @@ -106,7 +109,7 @@ const MDRawContextAMD64* DumpContext::GetContextAMD64() const { const MDRawContextSPARC* DumpContext::GetContextSPARC() const { if (GetContextCPU() != MD_CONTEXT_SPARC) { BPLOG(ERROR) << "DumpContext cannot get sparc context"; - return NULL; + return nullptr; } return context_.ctx_sparc; @@ -115,7 +118,7 @@ const MDRawContextSPARC* DumpContext::GetContextSPARC() const { const MDRawContextARM* DumpContext::GetContextARM() const { if (GetContextCPU() != MD_CONTEXT_ARM) { BPLOG(ERROR) << "DumpContext cannot get arm context"; - return NULL; + return nullptr; } return context_.arm; @@ -124,7 +127,7 @@ const MDRawContextARM* DumpContext::GetContextARM() const { const MDRawContextARM64* DumpContext::GetContextARM64() const { if (GetContextCPU() != MD_CONTEXT_ARM64) { BPLOG(ERROR) << "DumpContext cannot get arm64 context"; - return NULL; + return nullptr; } return context_.arm64; @@ -134,12 +137,30 @@ const MDRawContextMIPS* DumpContext::GetContextMIPS() const { if ((GetContextCPU() != MD_CONTEXT_MIPS) && (GetContextCPU() != MD_CONTEXT_MIPS64)) { BPLOG(ERROR) << "DumpContext cannot get MIPS context"; - return NULL; + return nullptr; } return context_.ctx_mips; } +const MDRawContextRISCV* DumpContext::GetContextRISCV() const { + if (GetContextCPU() != MD_CONTEXT_RISCV) { + BPLOG(ERROR) << "DumpContext cannot get RISCV context"; + return nullptr; + } + + return context_.riscv; +} + +const MDRawContextRISCV64* DumpContext::GetContextRISCV64() const { + if (GetContextCPU() != MD_CONTEXT_RISCV64) { + BPLOG(ERROR) << "DumpContext cannot get RISCV64 context"; + return nullptr; + } + + return context_.riscv64; +} + bool DumpContext::GetInstructionPointer(uint64_t* ip) const { BPLOG_IF(ERROR, !ip) << "DumpContext::GetInstructionPointer requires |ip|"; assert(ip); @@ -176,6 +197,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 +247,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 +297,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 +340,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 @@ -307,7 +356,7 @@ void DumpContext::FreeContext() { } context_flags_ = 0; - context_.base = NULL; + context_.base = nullptr; } void DumpContext::Print() { @@ -655,6 +704,174 @@ 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_CONTEXT_RISCV_FPR_COUNT; + ++freg_index) { + // Breakpad only supports RISCV32 with 32 bit floating point. + uint32_t fp_value = context_riscv->fpregs[freg_index]; + printf(" fpregs[%2d] = 0x%" PRIx32 "\n", freg_index, + fp_value); + } + printf(" fcsr = 0x%" PRIx32 "\n", context_riscv->fcsr); +#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_CONTEXT_RISCV_FPR_COUNT; + ++freg_index) { + // Breakpad only supports RISCV64 with 64 bit floating point. + uint64_t fp_value = context_riscv64->fpregs[freg_index]; + printf(" fpregs[%2d] = 0x%" PRIx64 "\n", freg_index, + fp_value); + } + printf(" fcsr = 0x%" PRIx32 "\n", context_riscv64->fcsr); +#endif + break; + } + default: { break; } diff --git a/src/processor/dump_object.cc b/src/processor/dump_object.cc index 2c82b200b..4050b11e2 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. // @@ -29,6 +28,10 @@ // dump_object.cc: A base class for all mini/micro dump object. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/dump_object.h" namespace google_breakpad { diff --git a/src/processor/exploitability.cc b/src/processor/exploitability.cc index 5f05b5105..5e1639c1e 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. // @@ -34,9 +33,12 @@ // Author: Cris Neckar -#include +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include -#include "common/scoped_ptr.h" #include "google_breakpad/processor/exploitability.h" #include "google_breakpad/processor/minidump.h" #include "google_breakpad/processor/process_state.h" @@ -65,15 +67,15 @@ Exploitability *Exploitability::ExploitabilityForPlatform( Minidump *dump, ProcessState *process_state, bool enable_objdump) { - Exploitability *platform_exploitability = NULL; + Exploitability *platform_exploitability = nullptr; MinidumpSystemInfo *minidump_system_info = dump->GetSystemInfo(); if (!minidump_system_info) - return NULL; + return nullptr; const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info(); if (!raw_system_info) - return NULL; + return nullptr; switch (raw_system_info->platform_id) { case MD_OS_WIN32_NT: @@ -95,7 +97,7 @@ Exploitability *Exploitability::ExploitabilityForPlatform( case MD_OS_PS3: case MD_OS_FUCHSIA: default: { - platform_exploitability = NULL; + platform_exploitability = nullptr; break; } } diff --git a/src/processor/exploitability_linux.cc b/src/processor/exploitability_linux.cc index 798056dfa..c8a5ca59c 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. // @@ -34,16 +33,11 @@ // // Author: Matthew Riley -#include "processor/exploitability_linux.h" - -#ifndef _WIN32 -#include -#include -#include +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif -#include -#include -#endif // _WIN32 +#include "processor/exploitability_linux.h" #include @@ -51,6 +45,9 @@ #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/process_state.h" #include "google_breakpad/processor/stack_frame.h" +#ifdef __linux__ +#include "processor/disassembler_objdump.h" +#endif #include "processor/logging.h" namespace { @@ -68,11 +65,6 @@ 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 { @@ -112,12 +104,12 @@ ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() { // Getting exception data. (It should exist for all minidumps.) MinidumpException* exception = dump_->GetException(); - if (exception == NULL) { + if (exception == nullptr) { BPLOG(INFO) << "No exception record."; return EXPLOITABILITY_ERR_PROCESSING; } const MDRawExceptionStream* raw_exception_stream = exception->exception(); - if (raw_exception_stream == NULL) { + if (raw_exception_stream == nullptr) { BPLOG(INFO) << "No raw exception stream."; return EXPLOITABILITY_ERR_PROCESSING; } @@ -133,7 +125,7 @@ ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() { uint64_t stack_ptr = 0; const MinidumpContext* context = exception->GetContext(); - if (context == NULL) { + if (context == nullptr) { BPLOG(INFO) << "No exception context."; return EXPLOITABILITY_ERR_PROCESSING; } @@ -170,14 +162,15 @@ ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() { } bool ExploitabilityLinux::EndedOnIllegalWrite(uint64_t instruction_ptr) { -#ifdef _WIN32 +#ifndef __linux__ 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 = memory_list ? - memory_list->GetMemoryRegionForAddress(instruction_ptr) : NULL; + memory_list->GetMemoryRegionForAddress(instruction_ptr) : nullptr; if (!memory_region) { BPLOG(INFO) << "No memory region around instruction pointer."; return false; @@ -199,69 +192,30 @@ bool ExploitabilityLinux::EndedOnIllegalWrite(uint64_t instruction_ptr) { 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,269 +223,11 @@ 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."; - 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 tokens; - std::istringstream line_stream(line); - copy(std::istream_iterator(line_stream), - std::istream_iterator(), - 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."; + } else { return false; } - fclose(objdump_fp); - unlink(raw_bytes_tmpfile); - return true; +#endif // __linux__ } -#endif // _WIN32 bool ExploitabilityLinux::StackPointerOffStack(uint64_t stack_ptr) { MinidumpLinuxMapsList* linux_maps_list = dump_->GetLinuxMapsList(); @@ -577,7 +273,7 @@ bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) { MinidumpLinuxMapsList* linux_maps_list = dump_->GetLinuxMapsList(); const MinidumpLinuxMaps* linux_maps = linux_maps_list ? - linux_maps_list->GetLinuxMapsForAddress(instruction_ptr) : NULL; + linux_maps_list->GetLinuxMapsForAddress(instruction_ptr) : nullptr; return linux_maps ? linux_maps->IsExecutable() : false; } @@ -616,10 +312,8 @@ bool ExploitabilityLinux::BenignCrashTrigger( 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 366479591..7603e4565 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. // @@ -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 528ee5f21..aa7514ae2 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,16 @@ // 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif #include #include +#include #include #include "breakpad_googletest_includes.h" @@ -37,26 +41,17 @@ #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( - const MDRawContextAMD64& context) : MinidumpContext(NULL) { + const MDRawContextAMD64& context) : MinidumpContext(nullptr) { valid_ = true; SetContextAMD64(new MDRawContextAMD64(context)); SetContextFlags(MD_CONTEXT_AMD64); @@ -64,15 +59,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; @@ -90,7 +84,7 @@ ExploitabilityFor(const string& filename) { SimpleSymbolSupplier supplier(TestDataDir() + "/symbols"); BasicSourceLineResolver resolver; MinidumpProcessor processor(&supplier, &resolver, true); - processor.set_enable_objdump(true); + processor.set_enable_objdump_for_exploitability(true); ProcessState state; string minidump_file = TestDataDir() + "/" + filename; @@ -171,7 +165,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 +176,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 b74a74965..fb0a1c76c 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. // @@ -34,11 +33,14 @@ // // Author: Cris Neckar +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "processor/exploitability_win.h" -#include "common/scoped_ptr.h" #include "google_breakpad/common/minidump_exception_win32.h" #include "google_breakpad/processor/minidump.h" #include "processor/disassembler_x86.h" @@ -193,7 +195,6 @@ ExploitabilityRating ExploitabilityWin::CheckPlatformExploitability() { default: BPLOG(INFO) << "Unrecognized access violation type."; return EXPLOITABILITY_ERR_PROCESSING; - break; } MinidumpMemoryRegion* instruction_region = 0; if (memory_available) { @@ -225,10 +226,10 @@ ExploitabilityRating ExploitabilityWin::CheckPlatformExploitability() { // Check if the faulting instruction falls into one of // several interesting groups. switch (disassembler.currentInstructionGroup()) { - case libdis::insn_controlflow: + case insn_controlflow: exploitability_weight += kLargeBump; break; - case libdis::insn_string: + case insn_string: exploitability_weight += kHugeBump; break; default: diff --git a/src/processor/exploitability_win.h b/src/processor/exploitability_win.h index 4e08aef03..52cff8b75 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 3f8ec5082..99fca9c76 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. // @@ -37,20 +36,28 @@ // // Author: Siyang Xie (lambxsy@google.com) +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/fast_source_line_resolver.h" -#include "processor/fast_source_line_resolver_types.h" + +#include +#include #include +#include #include #include -#include "common/scoped_ptr.h" #include "common/using_std_string.h" +#include "processor/fast_source_line_resolver_types.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 +68,9 @@ bool FastSourceLineResolver::ShouldDeleteMemoryBufferAfterLoadModule() { return false; } -void FastSourceLineResolver::Module::LookupAddress(StackFrame* frame) const { +void FastSourceLineResolver::Module::LookupAddress( + StackFrame* frame, + std::deque>* inlined_frames) const { MemAddr address = frame->instruction - frame->module->base_address(); // First, look for a FUNC record that covers address. Use @@ -70,9 +79,9 @@ void FastSourceLineResolver::Module::LookupAddress(StackFrame* frame) const { // extent of the PUBLIC symbol we find, below. This does mean we // need to check that address indeed falls within the function we // find; do the range comparison in an overflow-friendly way. - scoped_ptr func(new Function); + std::unique_ptr func(new Function); const Function* func_ptr = 0; - scoped_ptr public_symbol(new PublicSymbol); + std::unique_ptr public_symbol(new PublicSymbol); const PublicSymbol* public_symbol_ptr = 0; MemAddr function_base; MemAddr function_size; @@ -81,15 +90,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(new Line); + std::unique_ptr 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); + if (func->lines.RetrieveRange(address, line_ptr, &line_base, nullptr)) { + line->CopyFrom(line_ptr); FileMap::iterator it = files_.find(line->source_file_id); if (it != files_.end()) { frame->source_file_name = @@ -98,12 +108,79 @@ 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& inline_map, + std::deque>* inlined_frames) const { + std::vector inline_ptrs; + if (!inline_map.RetrieveRanges(address, inline_ptrs)) { + return; + } + + for (const char* inline_ptr : inline_ptrs) { + std::unique_ptr in(new Inline); + in->CopyFrom(inline_ptr); + unique_ptr new_frame = + unique_ptr(new StackFrame(*frame)); + auto origin_iter = inline_origins_.find(in->origin_id); + if (origin_iter != inline_origins_.end()) { + std::unique_ptr origin(new InlineOrigin); + origin->CopyFrom(origin_iter.GetValuePtr()); + new_frame->function_name = origin->name; + } else { + new_frame->function_name = ""; + } + + // 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 address 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& 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); + } } } @@ -153,19 +230,32 @@ bool FastSourceLineResolver::Module::LoadMapFromMemory( const char* mem_buffer = memory_buffer; mem_buffer = SimpleSerializer::Read(mem_buffer, &is_corrupt_); - const uint32_t* map_sizes = reinterpret_cast(mem_buffer); + const uint64_t* map_sizes = reinterpret_cast(mem_buffer); - unsigned int header_size = kNumberMaps_ * sizeof(unsigned int); + unsigned int header_size = kNumberMaps_ * sizeof(uint64_t); // offsets[]: an array of offset addresses (with respect to mem_buffer), // for each "Static***Map" component of Module. // "Static***Map": static version of std::map or map wrapper, i.e., StaticMap, // StaticAddressMap, StaticContainedRangeMap, and StaticRangeMap. - unsigned int offsets[kNumberMaps_]; + uint64_t offsets[kNumberMaps_]; offsets[0] = header_size; for (int i = 1; i < kNumberMaps_; ++i) { offsets[i] = offsets[i - 1] + map_sizes[i - 1]; } + size_t 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,21 +264,22 @@ bool FastSourceLineResolver::Module::LoadMapFromMemory( StaticRangeMap(mem_buffer + offsets[map_id++]); public_symbols_ = StaticAddressMap(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(mem_buffer + offsets[map_id++]); + } cfi_initial_rules_ = StaticRangeMap(mem_buffer + offsets[map_id++]); cfi_delta_rules_ = StaticMap(mem_buffer + offsets[map_id++]); - + inline_origins_ = StaticMap(mem_buffer + offsets[map_id++]); return true; } WindowsFrameInfo* FastSourceLineResolver::Module::FindWindowsFrameInfo( const StackFrame* frame) const { MemAddr address = frame->instruction - frame->module->base_address(); - scoped_ptr result(new WindowsFrameInfo()); + std::unique_ptr result(new WindowsFrameInfo()); // We only know about WindowsFrameInfo::STACK_INFO_FRAME_DATA and // WindowsFrameInfo::STACK_INFO_FPO. Prefer them in this order. @@ -212,13 +303,13 @@ WindowsFrameInfo* FastSourceLineResolver::Module::FindWindowsFrameInfo( // below. However, this does mean we need to check that ADDRESS // falls within the retrieved function's range; do the range // comparison in an overflow-friendly way. - scoped_ptr function(new Function); + std::unique_ptr function(new Function); const Function* function_ptr = 0; MemAddr function_base, function_size; 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(); @@ -226,23 +317,23 @@ WindowsFrameInfo* FastSourceLineResolver::Module::FindWindowsFrameInfo( // PUBLIC symbols might have a parameter size. Use the function we // found above to limit the range the public symbol covers. - scoped_ptr public_symbol(new PublicSymbol); + std::unique_ptr public_symbol(new PublicSymbol); const PublicSymbol* public_symbol_ptr = 0; 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; + return nullptr; } 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; + const char* initial_rules = nullptr; // Find the initial rule whose range covers this address. That // provides an initial set of register recovery rules. Then, walk @@ -250,14 +341,14 @@ CFIFrameInfo* FastSourceLineResolver::Module::FindCFIFrameInfo( // instruction address, applying delta rules. if (!cfi_initial_rules_.RetrieveRange(address, initial_rules, &initial_base, &initial_size)) { - return NULL; + return nullptr; } // Create a frame info structure, and populate it with the rules from // the STACK CFI INIT record. - scoped_ptr rules(new CFIFrameInfo()); + std::unique_ptr rules(new CFIFrameInfo()); if (!ParseCFIRuleSet(initial_rules, rules.get())) - return NULL; + return nullptr; // Find the first delta rule that falls within the initial rule's range. StaticMap::iterator delta = diff --git a/src/processor/fast_source_line_resolver_types.h b/src/processor/fast_source_line_resolver_types.h index 2b2b58275..ae58d7525 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,17 @@ #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 #include #include +#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,6 +55,10 @@ namespace google_breakpad { +#define DESERIALIZE(raw_ptr, field) \ + field = *(reinterpret_cast(raw_ptr)); \ + raw_ptr += sizeof(field); + struct FastSourceLineResolver::Line : public SourceLineResolverBase::Line { void CopyFrom(const Line* line_ptr) { const char* raw = reinterpret_cast(line_ptr); @@ -61,12 +67,10 @@ struct FastSourceLineResolver::Line : public SourceLineResolverBase::Line { // De-serialize the memory data of a Line. void CopyFrom(const char* raw) { - address = *(reinterpret_cast(raw)); - size = *(reinterpret_cast(raw + sizeof(address))); - source_file_id = *(reinterpret_cast( - raw + 2 * sizeof(address))); - line = *(reinterpret_cast( - raw + 2 * sizeof(address) + sizeof(source_file_id))); + DESERIALIZE(raw, address); + DESERIALIZE(raw, size); + DESERIALIZE(raw, source_file_id); + DESERIALIZE(raw, line); } }; @@ -81,18 +85,60 @@ public SourceLineResolverBase::Function { void CopyFrom(const char* raw) { size_t name_size = strlen(raw) + 1; name = raw; - address = *(reinterpret_cast(raw + name_size)); - size = *(reinterpret_cast( - raw + name_size + sizeof(MemAddr))); - parameter_size = *(reinterpret_cast( - raw + name_size + 2 * sizeof(MemAddr))); - lines = StaticRangeMap( - raw + name_size + 2 * sizeof(MemAddr) + sizeof(int32_t)); + raw += name_size; + DESERIALIZE(raw, address); + DESERIALIZE(raw, size); + DESERIALIZE(raw, parameter_size); + raw = SimpleSerializer::Read(raw, &is_multiple); + int32_t inline_size; + DESERIALIZE(raw, inline_size); + inlines = StaticContainedRangeMap(raw); + lines = StaticRangeMap(raw + inline_size); } + StaticContainedRangeMap inlines; StaticRangeMap lines; }; +struct FastSourceLineResolver::Inline : public SourceLineResolverBase::Inline { + void CopyFrom(const Inline* inline_ptr) { + const char* raw = reinterpret_cast(inline_ptr); + CopyFrom(raw); + } + + // De-serialize the memory data of a Inline. + void CopyFrom(const char* raw) { + raw = SimpleSerializer::Read(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 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(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) { @@ -104,12 +150,15 @@ public SourceLineResolverBase::PublicSymbol { void CopyFrom(const char* raw) { size_t name_size = strlen(raw) + 1; name = raw; - address = *(reinterpret_cast(raw + name_size)); - parameter_size = *(reinterpret_cast( - raw + name_size + sizeof(MemAddr))); + raw += name_size; + DESERIALIZE(raw, address); + DESERIALIZE(raw, parameter_size); + raw = SimpleSerializer::Read(raw, &is_multiple); } }; +#undef DESERIALIZE + class FastSourceLineResolver::Module: public SourceLineResolverBase::Module { public: explicit Module(const string& name) : name_(name), is_corrupt_(false) { } @@ -117,7 +166,19 @@ class FastSourceLineResolver::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>* 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& inline_map, + std::deque>* inlined_frames) const; // Loads a map from the given buffer in char* type. virtual bool LoadMapFromMemory(char* memory_buffer, @@ -141,7 +202,7 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module { 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 +239,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 cfi_delta_rules_; + + // INLINE_ORIGIN records: used as a function name string pool for INLINE + // records. + StaticMap 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 0ec5f91d4..4baee92f1 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. // @@ -37,9 +36,14 @@ // // Author: Siyang Xie (lambxsy@google.com) +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include +#include #include #include @@ -64,12 +68,10 @@ 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 { public: - explicit TestCodeModule(string code_file) : code_file_(code_file) {} + explicit TestCodeModule(const string& code_file) : code_file_(code_file) {} virtual ~TestCodeModule() {} virtual uint64_t base_address() const { return 0; } @@ -168,7 +170,7 @@ static bool VerifyEmpty(const StackFrame& frame) { static void ClearSourceLineInfo(StackFrame* frame) { frame->function_name.clear(); - frame->module = NULL; + frame->module = nullptr; frame->source_file_name.clear(); frame->source_line = 0; } @@ -213,20 +215,21 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) { ASSERT_TRUE(fast_resolver.HasModule(&module2)); StackFrame frame; - scoped_ptr windows_frame_info; - scoped_ptr cfi_frame_info; + std::unique_ptr windows_frame_info; + std::unique_ptr cfi_frame_info; frame.instruction = 0x1000; - frame.module = NULL; - fast_resolver.FillSourceLineInfo(&frame); + frame.module = nullptr; + 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 +237,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 +247,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 +264,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 +373,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 +392,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> 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> 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, diff --git a/src/processor/linked_ptr.h b/src/processor/linked_ptr.h index 72fbba84a..c67e36b25 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. // @@ -98,7 +97,7 @@ class linked_ptr { // Take over ownership of a raw pointer. This should happen as soon as // possible after the object is created. - explicit linked_ptr(T* ptr = NULL) { capture(ptr); } + explicit linked_ptr(T* ptr = nullptr) { capture(ptr); } ~linked_ptr() { depart(); } // Copy an existing linked_ptr<>, adding ourselves to the list of references. @@ -121,7 +120,7 @@ class linked_ptr { } // Smart pointer members. - void reset(T* ptr = NULL) { depart(); capture(ptr); } + void reset(T* ptr = nullptr) { depart(); capture(ptr); } T* get() const { return value_; } T* operator->() const { return value_; } T& operator*() const { return *value_; } @@ -130,7 +129,7 @@ class linked_ptr { T* release() { link_.depart(); T* v = value_; - value_ = NULL; + value_ = nullptr; return v; } diff --git a/src/processor/logging.cc b/src/processor/logging.cc index 3c5b16165..46386eb5f 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. // @@ -33,6 +32,10 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include diff --git a/src/processor/logging.h b/src/processor/logging.h index e6c6eee2a..519c852f5 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. // @@ -58,7 +57,9 @@ #define PROCESSOR_LOGGING_H__ #include +#include #include +#include #include "common/using_std_string.h" #include "google_breakpad/common/breakpad_types.h" @@ -120,9 +121,12 @@ class LogMessageVoidify { }; // Returns number formatted as a hexadecimal string, such as "0x7b". -string HexString(uint32_t number); -string HexString(uint64_t number); -string HexString(int number); +template +string HexString(T number) { + std::stringstream stream; + stream << "0x" << std::hex << number; + return stream.str(); +} // Returns the error code as set in the global errno variable, and sets // error_string, a required argument, to a string describing that error diff --git a/src/processor/map_serializers-inl.h b/src/processor/map_serializers-inl.h index 4933f907b..e86ffe382 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. // @@ -55,7 +54,7 @@ template size_t StdMapSerializer::SizeOf( const std::map& m) const { size_t size = 0; - size_t header_size = (1 + m.size()) * sizeof(uint32_t); + size_t header_size = (1 + m.size()) * sizeof(uint64_t); size += header_size; typename std::map::const_iterator iter; @@ -71,25 +70,25 @@ char* StdMapSerializer::Write(const std::map& m, char* dest) const { if (!dest) { BPLOG(ERROR) << "StdMapSerializer failed: write to NULL address."; - return NULL; + return nullptr; } char* start_address = dest; // Write header: // Number of nodes. - dest = SimpleSerializer::Write(m.size(), dest); + dest = SimpleSerializer::Write(m.size(), dest); // Nodes offsets. - uint32_t* offsets = reinterpret_cast(dest); - dest += sizeof(uint32_t) * m.size(); + uint64_t* offsets = reinterpret_cast(dest); + dest += sizeof(uint64_t) * m.size(); char* key_address = dest; dest += sizeof(Key) * m.size(); // Traverse map. typename std::map::const_iterator iter; - int index = 0; + int64_t index = 0; for (iter = m.begin(); iter != m.end(); ++iter, ++index) { - offsets[index] = static_cast(dest - start_address); + offsets[index] = static_cast(dest - start_address); key_address = key_serializer_.Write(iter->first, key_address); dest = value_serializer_.Write(iter->second, dest); } @@ -98,15 +97,15 @@ char* StdMapSerializer::Write(const std::map& m, template char* StdMapSerializer::Serialize( - const std::map& m, unsigned int* size) const { + const std::map& m, uint64_t* size) const { // Compute size of memory to be allocated. - unsigned int size_to_alloc = SizeOf(m); + uint64_t size_to_alloc = SizeOf(m); // Allocate memory. char* serialized_data = new char[size_to_alloc]; if (!serialized_data) { BPLOG(INFO) << "StdMapSerializer memory allocation failed."; if (size) *size = 0; - return NULL; + return nullptr; } // Write serialized data into memory. Write(m, serialized_data); @@ -119,7 +118,7 @@ template size_t RangeMapSerializer::SizeOf( const RangeMap& m) const { size_t size = 0; - size_t header_size = (1 + m.map_.size()) * sizeof(uint32_t); + size_t header_size = (1 + m.map_.size()) * sizeof(uint64_t); size += header_size; typename std::map::const_iterator iter; @@ -139,25 +138,25 @@ char* RangeMapSerializer::Write( const RangeMap& m, char* dest) const { if (!dest) { BPLOG(ERROR) << "RangeMapSerializer failed: write to NULL address."; - return NULL; + return nullptr; } char* start_address = dest; // Write header: // Number of nodes. - dest = SimpleSerializer::Write(m.map_.size(), dest); + dest = SimpleSerializer::Write(m.map_.size(), dest); // Nodes offsets. - uint32_t* offsets = reinterpret_cast(dest); - dest += sizeof(uint32_t) * m.map_.size(); + uint64_t* offsets = reinterpret_cast(dest); + dest += sizeof(uint64_t) * m.map_.size(); char* key_address = dest; dest += sizeof(Address) * m.map_.size(); // Traverse map. typename std::map::const_iterator iter; - int index = 0; + int64_t index = 0; for (iter = m.map_.begin(); iter != m.map_.end(); ++iter, ++index) { - offsets[index] = static_cast(dest - start_address); + offsets[index] = static_cast(dest - start_address); key_address = address_serializer_.Write(iter->first, key_address); dest = address_serializer_.Write(iter->second.base(), dest); dest = entry_serializer_.Write(iter->second.entry(), dest); @@ -167,15 +166,15 @@ char* RangeMapSerializer::Write( template char* RangeMapSerializer::Serialize( - const RangeMap& m, unsigned int* size) const { + const RangeMap& m, uint64_t* size) const { // Compute size of memory to be allocated. - unsigned int size_to_alloc = SizeOf(m); + uint64_t size_to_alloc = SizeOf(m); // Allocate memory. char* serialized_data = new char[size_to_alloc]; if (!serialized_data) { BPLOG(INFO) << "RangeMapSerializer memory allocation failed."; if (size) *size = 0; - return NULL; + return nullptr; } // Write serialized data into memory. @@ -192,12 +191,12 @@ size_t ContainedRangeMapSerializer::SizeOf( size_t size = 0; size_t header_size = addr_serializer_.SizeOf(m->base_) + entry_serializer_.SizeOf(m->entry_) - + sizeof(uint32_t); + + sizeof(uint64_t); size += header_size; // In case m.map_ == NULL, we treat it as an empty map: - size += sizeof(uint32_t); + size += sizeof(uint64_t); if (m->map_) { - size += m->map_->size() * sizeof(uint32_t); + size += m->map_->size() * sizeof(uint64_t); typename Map::const_iterator iter; for (iter = m->map_->begin(); iter != m->map_->end(); ++iter) { size += addr_serializer_.SizeOf(iter->first); @@ -213,30 +212,30 @@ char* ContainedRangeMapSerializer::Write( const ContainedRangeMap* m, char* dest) const { if (!dest) { BPLOG(ERROR) << "StdMapSerializer failed: write to NULL address."; - return NULL; + return nullptr; } dest = addr_serializer_.Write(m->base_, dest); - dest = SimpleSerializer::Write(entry_serializer_.SizeOf(m->entry_), + dest = SimpleSerializer::Write(entry_serializer_.SizeOf(m->entry_), dest); dest = entry_serializer_.Write(m->entry_, dest); // Write map<: char* map_address = dest; - if (m->map_ == NULL) { - dest = SimpleSerializer::Write(0, dest); + if (m->map_ == nullptr) { + dest = SimpleSerializer::Write(0, dest); } else { - dest = SimpleSerializer::Write(m->map_->size(), dest); - uint32_t* offsets = reinterpret_cast(dest); - dest += sizeof(uint32_t) * m->map_->size(); + dest = SimpleSerializer::Write(m->map_->size(), dest); + uint64_t* offsets = reinterpret_cast(dest); + dest += sizeof(uint64_t) * m->map_->size(); char* key_address = dest; dest += sizeof(AddrType) * m->map_->size(); // Traverse map. typename Map::const_iterator iter; - int index = 0; + int64_t index = 0; for (iter = m->map_->begin(); iter != m->map_->end(); ++iter, ++index) { - offsets[index] = static_cast(dest - map_address); + offsets[index] = static_cast(dest - map_address); key_address = addr_serializer_.Write(iter->first, key_address); // Recursively write. dest = Write(iter->second, dest); @@ -247,14 +246,14 @@ char* ContainedRangeMapSerializer::Write( template char* ContainedRangeMapSerializer::Serialize( - const ContainedRangeMap* m, unsigned int* size) const { - unsigned int size_to_alloc = SizeOf(m); + const ContainedRangeMap* m, uint64_t* size) const { + uint64_t size_to_alloc = SizeOf(m); // Allocating memory. char* serialized_data = new char[size_to_alloc]; if (!serialized_data) { BPLOG(INFO) << "ContainedRangeMapSerializer memory allocation failed."; if (size) *size = 0; - return NULL; + return nullptr; } Write(m, serialized_data); if (size) *size = size_to_alloc; diff --git a/src/processor/map_serializers.h b/src/processor/map_serializers.h index 3d504158e..933ff6fde 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. // @@ -66,7 +65,7 @@ class StdMapSerializer { // 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& m, unsigned int* size) const; + char* Serialize(const std::map& m, uint64_t* size) const; private: SimpleSerializer key_serializer_; @@ -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& m, unsigned int* size) const { + char* Serialize(const AddressMap& m, uint64_t* size) const { return std_map_serializer_.Serialize(m.map_, size); } @@ -121,7 +120,7 @@ class RangeMapSerializer { // 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& m, unsigned int* size) const; + char* Serialize(const RangeMap& m, uint64_t* size) const; private: // Convenient type name for Range. @@ -152,7 +151,7 @@ class ContainedRangeMapSerializer { // to the size of serialized data, i.e., SizeOf(m). // Caller has the ownership of memory allocated as "new char[]". char* Serialize(const ContainedRangeMap* m, - unsigned int* size) const; + uint64_t* 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 48b9c4b24..2a421ef73 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. // @@ -32,7 +31,15 @@ // // Author: Siyang Xie (lambxsy@google.com) -#include +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "map_serializers-inl.h" + +#include +#include + #include #include #include @@ -40,20 +47,18 @@ #include #include "breakpad_googletest_includes.h" -#include "map_serializers-inl.h" - #include "processor/address_map-inl.h" #include "processor/range_map-inl.h" #include "processor/contained_range_map-inl.h" -typedef int32_t AddrType; -typedef int32_t EntryType; +typedef int64_t AddrType; +typedef int64_t EntryType; class TestStdMapSerializer : public ::testing::Test { protected: void SetUp() { serialized_size_ = 0; - serialized_data_ = NULL; + serialized_data_ = nullptr; } void TearDown() { @@ -62,13 +67,13 @@ class TestStdMapSerializer : public ::testing::Test { std::map std_map_; google_breakpad::StdMapSerializer serializer_; - uint32_t serialized_size_; + uint64_t serialized_size_; char* serialized_data_; }; TEST_F(TestStdMapSerializer, EmptyMapTestCase) { - const int32_t correct_data[] = { 0 }; - uint32_t correct_size = sizeof(correct_data); + const int64_t correct_data[] = { 0 }; + uint64_t correct_size = sizeof(correct_data); // std_map_ is empty. serialized_data_ = serializer_.Serialize(std_map_, &serialized_size_); @@ -78,17 +83,17 @@ TEST_F(TestStdMapSerializer, EmptyMapTestCase) { } TEST_F(TestStdMapSerializer, MapWithTwoElementsTestCase) { - const int32_t correct_data[] = { + const int64_t correct_data[] = { // # of nodes 2, // Offsets - 20, 24, + 40, 48, // Keys 1, 3, // Values 2, 6 }; - uint32_t correct_size = sizeof(correct_data); + uint64_t correct_size = sizeof(correct_data); std_map_.insert(std::make_pair(1, 2)); std_map_.insert(std::make_pair(3, 6)); @@ -100,17 +105,17 @@ TEST_F(TestStdMapSerializer, MapWithTwoElementsTestCase) { } TEST_F(TestStdMapSerializer, MapWithFiveElementsTestCase) { - const int32_t correct_data[] = { + const int64_t correct_data[] = { // # of nodes 5, // Offsets - 44, 48, 52, 56, 60, + 88, 96, 104, 112, 120, // Keys 1, 2, 3, 4, 5, // Values 11, 12, 13, 14, 15 }; - uint32_t correct_size = sizeof(correct_data); + uint64_t correct_size = sizeof(correct_data); for (int i = 1; i < 6; ++i) std_map_.insert(std::make_pair(i, 10 + i)); @@ -134,13 +139,13 @@ class TestAddressMapSerializer : public ::testing::Test { google_breakpad::AddressMap address_map_; google_breakpad::AddressMapSerializer serializer_; - uint32_t serialized_size_; + uint64_t serialized_size_; char* serialized_data_; }; TEST_F(TestAddressMapSerializer, EmptyMapTestCase) { - const int32_t correct_data[] = { 0 }; - uint32_t correct_size = sizeof(correct_data); + const int64_t correct_data[] = { 0 }; + uint64_t correct_size = sizeof(correct_data); // std_map_ is empty. serialized_data_ = serializer_.Serialize(address_map_, &serialized_size_); @@ -150,17 +155,17 @@ TEST_F(TestAddressMapSerializer, EmptyMapTestCase) { } TEST_F(TestAddressMapSerializer, MapWithTwoElementsTestCase) { - const int32_t correct_data[] = { + const int64_t correct_data[] = { // # of nodes 2, // Offsets - 20, 24, + 40, 48, // Keys 1, 3, // Values 2, 6 }; - uint32_t correct_size = sizeof(correct_data); + uint64_t correct_size = sizeof(correct_data); address_map_.Store(1, 2); address_map_.Store(3, 6); @@ -172,17 +177,17 @@ TEST_F(TestAddressMapSerializer, MapWithTwoElementsTestCase) { } TEST_F(TestAddressMapSerializer, MapWithFourElementsTestCase) { - const int32_t correct_data[] = { + const int64_t correct_data[] = { // # of nodes 4, // Offsets - 36, 40, 44, 48, + 72, 80, 88, 96, // Keys -6, -4, 8, 123, // Values 2, 3, 5, 8 }; - uint32_t correct_size = sizeof(correct_data); + uint64_t correct_size = sizeof(correct_data); address_map_.Store(-6, 2); address_map_.Store(-4, 3); @@ -209,13 +214,13 @@ class TestRangeMapSerializer : public ::testing::Test { google_breakpad::RangeMap range_map_; google_breakpad::RangeMapSerializer serializer_; - uint32_t serialized_size_; + uint64_t serialized_size_; char* serialized_data_; }; TEST_F(TestRangeMapSerializer, EmptyMapTestCase) { - const int32_t correct_data[] = { 0 }; - uint32_t correct_size = sizeof(correct_data); + const int64_t correct_data[] = { 0 }; + uint64_t correct_size = sizeof(correct_data); // range_map_ is empty. serialized_data_ = serializer_.Serialize(range_map_, &serialized_size_); @@ -225,17 +230,17 @@ TEST_F(TestRangeMapSerializer, EmptyMapTestCase) { } TEST_F(TestRangeMapSerializer, MapWithOneRangeTestCase) { - const int32_t correct_data[] = { + const int64_t correct_data[] = { // # of nodes 1, // Offsets - 12, + 24, // Keys: high address 10, // Values: (low address, entry) pairs 1, 6 }; - uint32_t correct_size = sizeof(correct_data); + uint64_t correct_size = sizeof(correct_data); range_map_.StoreRange(1, 10, 6); @@ -246,17 +251,17 @@ TEST_F(TestRangeMapSerializer, MapWithOneRangeTestCase) { } TEST_F(TestRangeMapSerializer, MapWithThreeRangesTestCase) { - const int32_t correct_data[] = { + const int64_t correct_data[] = { // # of nodes 3, // Offsets - 28, 36, 44, + 56, 72, 88, // Keys: high address - 5, 9, 20, + 5, 9, 20, // Values: (low address, entry) pairs - 2, 1, 6, 2, 10, 3 + 2, 1, 6, 2, 10, 3 }; - uint32_t correct_size = sizeof(correct_data); + uint64_t correct_size = sizeof(correct_data); ASSERT_TRUE(range_map_.StoreRange(2, 4, 1)); ASSERT_TRUE(range_map_.StoreRange(6, 4, 2)); @@ -282,18 +287,18 @@ class TestContainedRangeMapSerializer : public ::testing::Test { google_breakpad::ContainedRangeMap crm_map_; google_breakpad::ContainedRangeMapSerializer serializer_; - uint32_t serialized_size_; + uint64_t serialized_size_; char* serialized_data_; }; TEST_F(TestContainedRangeMapSerializer, EmptyMapTestCase) { - const int32_t correct_data[] = { + const int64_t correct_data[] = { 0, // base address of root - 4, // size of entry + 8, // size of entry 0, // entry stored at root 0 // empty map stored at root }; - uint32_t correct_size = sizeof(correct_data); + uint64_t correct_size = sizeof(correct_data); // crm_map_ is empty. serialized_data_ = serializer_.Serialize(&crm_map_, &serialized_size_); @@ -303,21 +308,21 @@ TEST_F(TestContainedRangeMapSerializer, EmptyMapTestCase) { } TEST_F(TestContainedRangeMapSerializer, MapWithOneRangeTestCase) { - const int32_t correct_data[] = { + const int64_t correct_data[] = { 0, // base address of root - 4, // size of entry + 8, // size of entry 0, // entry stored at root // Map stored at root node: 1, // # of nodes - 12, // offset + 24, // offset 9, // key // value: a child ContainedRangeMap 3, // base address of child CRM - 4, // size of entry + 8, // size of entry -1, // entry stored in child CRM 0 // empty sub-map stored in child CRM }; - uint32_t correct_size = sizeof(correct_data); + uint64_t correct_size = sizeof(correct_data); crm_map_.StoreRange(3, 7, -1); @@ -339,27 +344,27 @@ TEST_F(TestContainedRangeMapSerializer, MapWithTwoLevelsTestCase) { // / \ | // 3~4 6~7 16-20 level 2: grandchild1, grandchild2, grandchild3 - const int32_t correct_data[] = { + const int64_t correct_data[] = { // root: base, entry_size, entry - 0, 4, 0, + 0, 8, 0, // root's map: # of nodes, offset1, offset2, key1, key2 - 2, 20, 84, 8, 20, + 2, 40, 168, 8, 20, // child1: base, entry_size, entry: - 2, 4, -1, + 2, 8, -1, // child1's map: # of nodes, offset1, offset2, key1, key2 - 2, 20, 36, 4, 7, + 2, 40, 72, 4, 7, // grandchild1: base, entry_size, entry, empty_map - 3, 4, -1, 0, + 3, 8, -1, 0, // grandchild2: base, entry_size, entry, empty_map - 6, 4, -1, 0, + 6, 8, -1, 0, // child2: base, entry_size, entry: - 10, 4, -1, + 10, 8, -1, // child2's map: # of nodes, offset1, key1 - 1, 12, 20, + 1, 24, 20, // grandchild3: base, entry_size, entry, empty_map - 16, 4, -1, 0 + 16, 8, -1, 0 }; - uint32_t correct_size = sizeof(correct_data); + uint64_t correct_size = sizeof(correct_data); // Store child1. ASSERT_TRUE(crm_map_.StoreRange(2, 7, -1)); diff --git a/src/processor/microdump.cc b/src/processor/microdump.cc index d8141a2a8..ec2314570 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. // @@ -31,8 +30,13 @@ // // See microdump.h for documentation. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/microdump.h" +#include #include #include diff --git a/src/processor/microdump_processor.cc b/src/processor/microdump_processor.cc index 2d3a9558a..a38f199e2 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. // @@ -31,10 +30,15 @@ // // See microdump_processor.h for documentation. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/microdump_processor.h" #include +#include #include #include "common/using_std_string.h" @@ -61,16 +65,16 @@ ProcessResult MicrodumpProcessor::Process(Microdump *microdump, process_state->Clear(); process_state->modules_ = microdump->GetModules()->Copy(); - scoped_ptr stackwalker( + std::unique_ptr stackwalker( Stackwalker::StackwalkerForCPU( &process_state->system_info_, microdump->GetContext(), microdump->GetMemory(), process_state->modules_, - /* unloaded_modules= */ NULL, + /* unloaded_modules= */ nullptr, frame_symbolizer_)); - scoped_ptr stack(new CallStack()); + std::unique_ptr stack(new CallStack()); if (stackwalker.get()) { if (!stackwalker->Walk(stack.get(), &process_state->modules_without_symbols_, diff --git a/src/processor/microdump_processor_unittest.cc b/src/processor/microdump_processor_unittest.cc index 00f23f553..5379def8d 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. // @@ -29,6 +28,12 @@ // Unit test for MicrodumpProcessor. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + #include #include #include @@ -232,7 +237,7 @@ TEST_F(MicrodumpProcessorTest, TestProcessMultiple) { ASSERT_EQ("arm", state.system_info()->cpu); ASSERT_EQ("lge/p1_tmo_us/p1:6.0/MRA58K/1603210524c8d:user/release-keys", state.system_info()->os_version); - ASSERT_EQ(6U, state.threads()->at(0)->frames()->size()); + ASSERT_EQ(5U, state.threads()->at(0)->frames()->size()); } TEST_F(MicrodumpProcessorTest, TestProcessMips) { diff --git a/src/processor/microdump_stackwalk.cc b/src/processor/microdump_stackwalk.cc index 03fa77e1a..585c40c93 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. // @@ -30,16 +29,20 @@ // microdump_stackwalk.cc: Process a microdump with MicrodumpProcessor, printing // the results, including stack traces. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include #include +#include #include #include #include "common/path_helper.h" -#include "common/scoped_ptr.h" #include "common/using_std_string.h" #include "google_breakpad/processor/basic_source_line_resolver.h" #include "google_breakpad/processor/microdump.h" @@ -66,7 +69,6 @@ using google_breakpad::Microdump; using google_breakpad::MicrodumpProcessor; using google_breakpad::ProcessResult; using google_breakpad::ProcessState; -using google_breakpad::scoped_ptr; using google_breakpad::SimpleSymbolSupplier; using google_breakpad::StackFrameSymbolizer; @@ -93,7 +95,7 @@ int PrintMicrodumpProcess(const Options& options) { file_stream.read(&bytes[0], bytes.size()); string microdump_content(&bytes[0], bytes.size()); - scoped_ptr symbol_supplier; + std::unique_ptr symbol_supplier; if (!options.symbol_paths.empty()) { symbol_supplier.reset(new SimpleSymbolSupplier(options.symbol_paths)); } @@ -110,7 +112,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; } diff --git a/src/processor/microdump_stackwalk_machine_readable_test b/src/processor/microdump_stackwalk_machine_readable_test index f5614e20f..a08984663 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 e18976566..cb8950820 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 1f4795589..43db2a20e 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. // @@ -33,11 +32,22 @@ // // Author: Mark Mentovai +// For PRI* macros, before anything else might #include it. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif /* __STDC_FORMAT_MACROS */ + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/minidump.h" #include #include +#include #include +#include #include #include @@ -50,10 +60,9 @@ #include #include #include +#include #include -#include "processor/range_map-inl.h" - #include "common/macros.h" #include "common/scoped_ptr.h" #include "common/stdio_wrapper.h" @@ -62,6 +71,7 @@ #include "processor/basic_code_modules.h" #include "processor/convert_old_arm64_context.h" #include "processor/logging.h" +#include "processor/range_map-inl.h" namespace google_breakpad { @@ -72,6 +82,11 @@ using std::vector; namespace { +// Limit arrived at by adding up possible states in Intel Ch. 13.5 X-SAVE +// MANAGED STATE +// (~ 3680 bytes) plus some extra for the future. +const uint32_t kMaxXSaveAreaSize = 16384; + // Returns true iff |context_size| matches exactly one of the sizes of the // various MDRawContext* types. // TODO(blundell): This function can be removed once @@ -96,6 +111,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 +231,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++) { @@ -234,7 +259,7 @@ inline void Swap(uint16_t* data, size_t size_in_bytes) { // CPU's endianness into consideration. It doesn't seems worth the trouble // of making it a dependency when we don't care about anything but UTF-16. string* UTF16ToUTF8(const vector& in, bool swap) { - scoped_ptr out(new string()); + std::unique_ptr out(new string()); // Set the string's initial capacity to the number of UTF-16 characters, // because the UTF-8 representation will always be at least this long. @@ -254,14 +279,14 @@ string* UTF16ToUTF8(const vector& in, bool swap) { if (in_word >= 0xdc00 && in_word <= 0xdcff) { BPLOG(ERROR) << "UTF16ToUTF8 found low surrogate " << HexString(in_word) << " without high"; - return NULL; + return nullptr; } else if (in_word >= 0xd800 && in_word <= 0xdbff) { // High surrogate. unichar = (in_word - 0xd7c0) << 10; if (++iterator == in.end()) { BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " << HexString(in_word) << " at end of string"; - return NULL; + return nullptr; } uint32_t high_word = in_word; in_word = *iterator; @@ -269,7 +294,7 @@ string* UTF16ToUTF8(const vector& in, bool swap) { BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " << HexString(high_word) << " without low " << HexString(in_word); - return NULL; + return nullptr; } unichar |= in_word & 0x03ff; } else { @@ -297,7 +322,7 @@ string* UTF16ToUTF8(const vector& in, bool swap) { } else { BPLOG(ERROR) << "UTF16ToUTF8 cannot represent high value " << HexString(unichar) << " in UTF-8"; - return NULL; + return nullptr; } } @@ -338,7 +363,7 @@ void ConvertUTF16BufferToUTF8String(const uint16_t* utf16_data, size_t byte_length = word_length * sizeof(utf16_data[0]); vector utf16_vector(word_length); memcpy(&utf16_vector[0], &utf16_data[0], byte_length); - scoped_ptr temp(UTF16ToUTF8(utf16_vector, swap)); + std::unique_ptr temp(UTF16ToUTF8(utf16_vector, swap)); if (temp.get()) { utf8_result->assign(*temp); } @@ -470,27 +495,47 @@ 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 context_amd64(new MDRawContextAMD64()); + std::unique_ptr context_amd64(new MDRawContextAMD64()); if (!minidump_->ReadBytes(context_amd64.get(), sizeof(MDRawContextAMD64))) { BPLOG(ERROR) << "MinidumpContext could not read amd64 context"; 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); + if (bytes_left > kMaxXSaveAreaSize) { + BPLOG(ERROR) << "MinidumpContext oversized xstate area"; + return false; + } + std::vector 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) { @@ -584,7 +629,7 @@ bool MinidumpContext::Read(uint32_t expected_size) { Swap(&context_flags); uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK; - scoped_ptr context_ppc64(new MDRawContextPPC64()); + std::unique_ptr context_ppc64(new MDRawContextPPC64()); if (cpu_type == 0) { if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { @@ -680,7 +725,7 @@ bool MinidumpContext::Read(uint32_t expected_size) { if (minidump_->swap()) Swap(&context_flags); - scoped_ptr context_arm64(new MDRawContextARM64_Old()); + std::unique_ptr context_arm64(new MDRawContextARM64_Old()); uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK; if (cpu_type == 0) { @@ -739,7 +784,7 @@ bool MinidumpContext::Read(uint32_t expected_size) { } } - scoped_ptr new_context(new MDRawContextARM64()); + std::unique_ptr new_context(new MDRawContextARM64()); ConvertOldARM64Context(*context_arm64.get(), new_context.get()); SetContextFlags(new_context->context_flags); SetContextARM64(new_context.release()); @@ -765,13 +810,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 @@ -781,12 +823,22 @@ bool MinidumpContext::Read(uint32_t expected_size) { switch (cpu_type) { case MD_CONTEXT_X86: { if (expected_size != sizeof(MDRawContextX86)) { - BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " << - expected_size << " != " << sizeof(MDRawContextX86); - return false; + // Context may include xsave registers and so be larger than + // sizeof(MDRawContextX86). For now we skip this extended data. + if (context_flags & MD_CONTEXT_X86_XSTATE) { + int64_t bytes_left = expected_size - sizeof(MDRawContextX86); + if (bytes_left > kMaxXSaveAreaSize) { + BPLOG(ERROR) << "MinidumpContext oversized xstate area"; + return false; + } + } else { + BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " + << expected_size << " != " << sizeof(MDRawContextX86); + return false; + } } - scoped_ptr context_x86(new MDRawContextX86()); + std::unique_ptr context_x86(new MDRawContextX86()); // Set the context_flags member, which has already been read, and // read the rest of the structure beginning with the first member @@ -849,6 +901,16 @@ bool MinidumpContext::Read(uint32_t expected_size) { SetContextX86(context_x86.release()); + // Skip extended xstate data if present in X86 context. + if (context_flags & MD_CONTEXT_X86_XSTATE) { + if (!minidump_->SeekSet( + (minidump_->Tell() - sizeof(MDRawContextX86)) + + expected_size)) { + BPLOG(ERROR) << "MinidumpContext cannot seek to past xstate data"; + return false; + } + } + break; } @@ -859,7 +921,7 @@ bool MinidumpContext::Read(uint32_t expected_size) { return false; } - scoped_ptr context_ppc(new MDRawContextPPC()); + std::unique_ptr context_ppc(new MDRawContextPPC()); // Set the context_flags member, which has already been read, and // read the rest of the structure beginning with the first member @@ -935,7 +997,7 @@ bool MinidumpContext::Read(uint32_t expected_size) { return false; } - scoped_ptr context_sparc(new MDRawContextSPARC()); + std::unique_ptr context_sparc(new MDRawContextSPARC()); // Set the context_flags member, which has already been read, and // read the rest of the structure beginning with the first member @@ -991,7 +1053,7 @@ bool MinidumpContext::Read(uint32_t expected_size) { return false; } - scoped_ptr context_arm(new MDRawContextARM()); + std::unique_ptr context_arm(new MDRawContextARM()); // Set the context_flags member, which has already been read, and // read the rest of the structure beginning with the first member @@ -1046,7 +1108,7 @@ bool MinidumpContext::Read(uint32_t expected_size) { return false; } - scoped_ptr context_arm64(new MDRawContextARM64()); + std::unique_ptr context_arm64(new MDRawContextARM64()); // Set the context_flags member, which has already been read, and // read the rest of the structure beginning with the first member @@ -1101,7 +1163,7 @@ bool MinidumpContext::Read(uint32_t expected_size) { return false; } - scoped_ptr context_mips(new MDRawContextMIPS()); + std::unique_ptr context_mips(new MDRawContextMIPS()); // Set the context_flags member, which has already been read, and // read the rest of the structure beginning with the first member @@ -1157,13 +1219,167 @@ 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; + } + + std::unique_ptr 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(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_CONTEXT_RISCV_FPR_COUNT; + ++fpr_index) { + Swap(&context_riscv->fpregs[fpr_index]); + } + Swap(&context_riscv->fcsr); + } + 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; + } + + std::unique_ptr 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(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_CONTEXT_RISCV_FPR_COUNT; + ++fpr_index) { + Swap(&context_riscv64->fpregs[fpr_index]); + } + Swap(&context_riscv64->fcsr); + } + 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 +1466,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 " << @@ -1271,8 +1497,8 @@ uint32_t MinidumpMemoryRegion::max_bytes_ = 64 * 1024 * 1024; // 64MB MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump) : MinidumpObject(minidump), - descriptor_(NULL), - memory_(NULL) { + descriptor_(nullptr), + memory_(nullptr) { hexdump_width_ = minidump_ ? minidump_->HexdumpMode() : 0; hexdump_ = hexdump_width_ != 0; } @@ -1295,33 +1521,33 @@ void MinidumpMemoryRegion::SetDescriptor(MDMemoryDescriptor* descriptor) { const uint8_t* MinidumpMemoryRegion::GetMemory() const { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetMemory"; - return NULL; + return nullptr; } if (!memory_) { if (descriptor_->memory.data_size == 0) { BPLOG(ERROR) << "MinidumpMemoryRegion is empty"; - return NULL; + return nullptr; } if (!minidump_->SeekSet(descriptor_->memory.rva)) { BPLOG(ERROR) << "MinidumpMemoryRegion could not seek to memory region"; - return NULL; + return nullptr; } if (descriptor_->memory.data_size > max_bytes_) { BPLOG(ERROR) << "MinidumpMemoryRegion size " << descriptor_->memory.data_size << " exceeds maximum " << max_bytes_; - return NULL; + return nullptr; } - scoped_ptr< vector > memory( + std::unique_ptr< vector > memory( new vector(descriptor_->memory.data_size)); if (!minidump_->ReadBytes(&(*memory)[0], descriptor_->memory.data_size)) { BPLOG(ERROR) << "MinidumpMemoryRegion could not read memory region"; - return NULL; + return nullptr; } memory_ = memory.release(); @@ -1353,7 +1579,7 @@ uint32_t MinidumpMemoryRegion::GetSize() const { void MinidumpMemoryRegion::FreeMemory() { delete memory_; - memory_ = NULL; + memory_ = nullptr; } @@ -1512,8 +1738,8 @@ void MinidumpMemoryRegion::SetPrintMode(bool hexdump, MinidumpThread::MinidumpThread(Minidump* minidump) : MinidumpObject(minidump), thread_(), - memory_(NULL), - context_(NULL) { + memory_(nullptr), + context_(nullptr) { } @@ -1526,9 +1752,9 @@ MinidumpThread::~MinidumpThread() { bool MinidumpThread::Read() { // Invalidate cached data. delete memory_; - memory_ = NULL; + memory_ = nullptr; delete context_; - context_ = NULL; + context_ = nullptr; valid_ = false; @@ -1578,7 +1804,7 @@ uint64_t MinidumpThread::GetStartOfStackMemoryRange() const { MinidumpMemoryRegion* MinidumpThread::GetMemory() { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpThread for GetMemory"; - return NULL; + return nullptr; } return memory_; @@ -1588,20 +1814,20 @@ MinidumpMemoryRegion* MinidumpThread::GetMemory() { MinidumpContext* MinidumpThread::GetContext() { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpThread for GetContext"; - return NULL; + return nullptr; } if (!context_) { if (!minidump_->SeekSet(thread_.thread_context.rva)) { BPLOG(ERROR) << "MinidumpThread cannot seek to context"; - return NULL; + return nullptr; } - scoped_ptr context(new MinidumpContext(minidump_)); + std::unique_ptr context(new MinidumpContext(minidump_)); if (!context->Read(thread_.thread_context.data_size)) { BPLOG(ERROR) << "MinidumpThread cannot read context"; - return NULL; + return nullptr; } context_ = context.release(); @@ -1680,7 +1906,7 @@ uint32_t MinidumpThreadList::max_threads_ = 4096; MinidumpThreadList::MinidumpThreadList(Minidump* minidump) : MinidumpStream(minidump), id_to_thread_map_(), - threads_(NULL), + threads_(nullptr), thread_count_(0) { } @@ -1694,7 +1920,7 @@ bool MinidumpThreadList::Read(uint32_t expected_size) { // Invalidate cached data. id_to_thread_map_.clear(); delete threads_; - threads_ = NULL; + threads_ = nullptr; thread_count_ = 0; valid_ = false; @@ -1746,7 +1972,7 @@ bool MinidumpThreadList::Read(uint32_t expected_size) { } if (thread_count != 0) { - scoped_ptr threads( + std::unique_ptr threads( new MinidumpThreads(thread_count, MinidumpThread(minidump_))); for (unsigned int thread_index = 0; @@ -1792,13 +2018,13 @@ MinidumpThread* MinidumpThreadList::GetThreadAtIndex(unsigned int index) const { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpThreadList for GetThreadAtIndex"; - return NULL; + return nullptr; } if (index >= thread_count_) { BPLOG(ERROR) << "MinidumpThreadList index out of range: " << index << "/" << thread_count_; - return NULL; + return nullptr; } return &(*threads_)[index]; @@ -1831,6 +2057,229 @@ void MinidumpThreadList::Print() { } } +// +// MinidumpThreadName +// + +MinidumpThreadName::MinidumpThreadName(Minidump* minidump) + : MinidumpObject(minidump), + thread_name_valid_(false), + thread_name_(), + name_(nullptr) {} + +MinidumpThreadName::~MinidumpThreadName() { + delete name_; +} + +bool MinidumpThreadName::Read() { + // Invalidate cached data. + delete name_; + name_ = nullptr; + + 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::max()) { + BPLOG(ERROR) << "MinidumpThreadName RVA64 out of range"; + return false; + } + + // Read the thread name. + const off_t thread_name_rva_offset = + static_cast(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_(nullptr), thread_name_count_(0) {} + +MinidumpThreadNameList::~MinidumpThreadNameList() { + delete thread_names_; +} + +bool MinidumpThreadNameList::Read(uint32_t expected_size) { + // Invalidate cached data. + delete thread_names_; + thread_names_ = nullptr; + 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::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) { + std::unique_ptr 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 nullptr; + } + + if (index >= thread_name_count_) { + BPLOG(ERROR) << "MinidumpThreadNameList index out of range: " << index + << "/" << thread_name_count_; + return nullptr; + } + + 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 @@ -1846,10 +2295,10 @@ MinidumpModule::MinidumpModule(Minidump* minidump) module_valid_(false), has_debug_info_(false), module_(), - name_(NULL), - cv_record_(NULL), + name_(nullptr), + cv_record_(nullptr), cv_record_signature_(MD_CVINFOUNKNOWN_SIGNATURE), - misc_record_(NULL) { + misc_record_(nullptr) { } @@ -1863,12 +2312,12 @@ MinidumpModule::~MinidumpModule() { bool MinidumpModule::Read() { // Invalidate cached data. delete name_; - name_ = NULL; + name_ = nullptr; delete cv_record_; - cv_record_ = NULL; + cv_record_ = nullptr; cv_record_signature_ = MD_CVINFOUNKNOWN_SIGNATURE; delete misc_record_; - misc_record_ = NULL; + misc_record_ = nullptr; module_valid_ = false; has_debug_info_ = false; @@ -1937,13 +2386,13 @@ bool MinidumpModule::ReadAuxiliaryData() { // CodeView and miscellaneous debug records are only required if the // module indicates that they exist. - if (module_.cv_record.data_size && !GetCVRecord(NULL)) { + if (module_.cv_record.data_size && !GetCVRecord(nullptr)) { BPLOG(ERROR) << "MinidumpModule has no CodeView record, " "but one was expected"; return false; } - if (module_.misc_record.data_size && !GetMiscRecord(NULL)) { + if (module_.misc_record.data_size && !GetMiscRecord(nullptr)) { BPLOG(ERROR) << "MinidumpModule has no miscellaneous debug record, " "but one was expected"; return false; @@ -2020,7 +2469,7 @@ string MinidumpModule::code_identifier() const { break; } // Otherwise fall through to the case below. - BP_FALLTHROUGH; + [[fallthrough]]; } case MD_OS_MAC_OS_X: @@ -2120,9 +2569,9 @@ string MinidumpModule::debug_file() const { // GetMiscRecord already byte-swapped the data[] field if it contains // UTF-16, so pass false as the swap argument. - scoped_ptr new_file(UTF16ToUTF8(string_utf16, false)); + std::unique_ptr new_file(UTF16ToUTF8(string_utf16, false)); if (new_file.get() != nullptr) { - file = *new_file; + file = string(*new_file); } } } @@ -2277,26 +2726,26 @@ void MinidumpModule::SetShrinkDownDelta(uint64_t shrink_down_delta) { const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) { if (!module_valid_) { BPLOG(ERROR) << "Invalid MinidumpModule for GetCVRecord"; - return NULL; + return nullptr; } if (!cv_record_) { // This just guards against 0-sized CodeView records; more specific checks // are used when the signature is checked against various structure types. if (module_.cv_record.data_size == 0) { - return NULL; + return nullptr; } if (!minidump_->SeekSet(module_.cv_record.rva)) { BPLOG(ERROR) << "MinidumpModule could not seek to CodeView record"; - return NULL; + return nullptr; } if (module_.cv_record.data_size > max_cv_bytes_) { BPLOG(ERROR) << "MinidumpModule CodeView record size " << module_.cv_record.data_size << " exceeds maximum " << max_cv_bytes_; - return NULL; + return nullptr; } // Allocating something that will be accessed as MDCVInfoPDB70 or @@ -2306,12 +2755,12 @@ const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) { // variable-sized due to their pdb_file_name fields; these structures // are not MDCVInfoPDB70_minsize or MDCVInfoPDB20_minsize and treating // them as such would result in incomplete structures or overruns. - scoped_ptr< vector > cv_record( + std::unique_ptr< vector > cv_record( new vector(module_.cv_record.data_size)); if (!minidump_->ReadBytes(&(*cv_record)[0], module_.cv_record.data_size)) { BPLOG(ERROR) << "MinidumpModule could not read CodeView record"; - return NULL; + return nullptr; } uint32_t signature = MD_CVINFOUNKNOWN_SIGNATURE; @@ -2330,7 +2779,7 @@ const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) { BPLOG(ERROR) << "MinidumpModule CodeView7 record size mismatch, " << MDCVInfoPDB70_minsize << " > " << module_.cv_record.data_size; - return NULL; + return nullptr; } if (minidump_->swap()) { @@ -2348,7 +2797,7 @@ const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) { if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') { BPLOG(ERROR) << "MinidumpModule CodeView7 record string is not " "0-terminated"; - return NULL; + return nullptr; } } else if (signature == MD_CVINFOPDB20_SIGNATURE) { // Now that the structure type is known, recheck the size, @@ -2357,7 +2806,7 @@ const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) { BPLOG(ERROR) << "MinidumpModule CodeView2 record size mismatch, " << MDCVInfoPDB20_minsize << " > " << module_.cv_record.data_size; - return NULL; + return nullptr; } if (minidump_->swap()) { MDCVInfoPDB20* cv_record_20 = @@ -2375,7 +2824,7 @@ const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) { if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') { BPLOG(ERROR) << "MindumpModule CodeView2 record string is not " "0-terminated"; - return NULL; + return nullptr; } } else if (signature == MD_CVINFOELF_SIGNATURE) { // Now that the structure type is known, recheck the size. @@ -2383,7 +2832,7 @@ const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) { BPLOG(ERROR) << "MinidumpModule CodeViewELF record size mismatch, " << MDCVInfoELF_minsize << " > " << module_.cv_record.data_size; - return NULL; + return nullptr; } if (minidump_->swap()) { MDCVInfoELF* cv_record_elf = @@ -2414,32 +2863,32 @@ const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) { const MDImageDebugMisc* MinidumpModule::GetMiscRecord(uint32_t* size) { if (!module_valid_) { BPLOG(ERROR) << "Invalid MinidumpModule for GetMiscRecord"; - return NULL; + return nullptr; } if (!misc_record_) { if (module_.misc_record.data_size == 0) { - return NULL; + return nullptr; } if (MDImageDebugMisc_minsize > module_.misc_record.data_size) { BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record " "size mismatch, " << MDImageDebugMisc_minsize << " > " << module_.misc_record.data_size; - return NULL; + return nullptr; } if (!minidump_->SeekSet(module_.misc_record.rva)) { BPLOG(ERROR) << "MinidumpModule could not seek to miscellaneous " "debugging record"; - return NULL; + return nullptr; } if (module_.misc_record.data_size > max_misc_bytes_) { BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record size " << module_.misc_record.data_size << " exceeds maximum " << max_misc_bytes_; - return NULL; + return nullptr; } // Allocating something that will be accessed as MDImageDebugMisc but @@ -2448,7 +2897,7 @@ const MDImageDebugMisc* MinidumpModule::GetMiscRecord(uint32_t* size) { // because the MDImageDebugMisc is variable-sized due to its data field; // this structure is not MDImageDebugMisc_minsize and treating it as such // would result in an incomplete structure or an overrun. - scoped_ptr< vector > misc_record_mem( + std::unique_ptr< vector > misc_record_mem( new vector(module_.misc_record.data_size)); MDImageDebugMisc* misc_record = reinterpret_cast(&(*misc_record_mem)[0]); @@ -2456,7 +2905,7 @@ const MDImageDebugMisc* MinidumpModule::GetMiscRecord(uint32_t* size) { if (!minidump_->ReadBytes(misc_record, module_.misc_record.data_size)) { BPLOG(ERROR) << "MinidumpModule could not read miscellaneous debugging " "record"; - return NULL; + return nullptr; } if (minidump_->swap()) { @@ -2479,7 +2928,7 @@ const MDImageDebugMisc* MinidumpModule::GetMiscRecord(uint32_t* size) { BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record data " "size mismatch, " << module_.misc_record.data_size << " != " << misc_record->length; - return NULL; + return nullptr; } // Store the vector type because that's how storage was allocated, but @@ -2607,7 +3056,7 @@ void MinidumpModule::Print() { printf(" (cv_record) = (null)\n"); } - const MDImageDebugMisc* misc_record = GetMiscRecord(NULL); + const MDImageDebugMisc* misc_record = GetMiscRecord(nullptr); if (misc_record) { printf(" (misc_record).data_type = 0x%x\n", misc_record->data_type); @@ -2651,7 +3100,7 @@ uint32_t MinidumpModuleList::max_modules_ = 2048; MinidumpModuleList::MinidumpModuleList(Minidump* minidump) : MinidumpStream(minidump), range_map_(new RangeMap()), - modules_(NULL), + modules_(nullptr), module_count_(0) { MDOSPlatform platform; if (minidump_->GetPlatform(&platform) && @@ -2671,7 +3120,7 @@ bool MinidumpModuleList::Read(uint32_t expected_size) { // Invalidate cached data. range_map_->Clear(); delete modules_; - modules_ = NULL; + modules_ = nullptr; module_count_ = 0; valid_ = false; @@ -2722,7 +3171,7 @@ bool MinidumpModuleList::Read(uint32_t expected_size) { } if (module_count != 0) { - scoped_ptr modules( + std::unique_ptr modules( new MinidumpModules(module_count, MinidumpModule(minidump_))); for (uint32_t module_index = 0; module_index < module_count; @@ -2851,15 +3300,15 @@ const MinidumpModule* MinidumpModuleList::GetModuleForAddress( uint64_t address) const { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleForAddress"; - return NULL; + return nullptr; } unsigned int module_index; - if (!range_map_->RetrieveRange(address, &module_index, NULL /* base */, - NULL /* delta */, NULL /* size */)) { + if (!range_map_->RetrieveRange(address, &module_index, nullptr /* base */, + nullptr /* delta */, nullptr /* size */)) { BPLOG(INFO) << "MinidumpModuleList has no module at " << HexString(address); - return NULL; + return nullptr; } return GetModuleAtIndex(module_index); @@ -2869,7 +3318,7 @@ const MinidumpModule* MinidumpModuleList::GetModuleForAddress( const MinidumpModule* MinidumpModuleList::GetMainModule() const { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpModuleList for GetMainModule"; - return NULL; + return nullptr; } // The main code module is the first one present in a minidump file's @@ -2882,21 +3331,21 @@ const MinidumpModule* MinidumpModuleList::GetModuleAtSequence( unsigned int sequence) const { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtSequence"; - return NULL; + return nullptr; } if (sequence >= module_count_) { BPLOG(ERROR) << "MinidumpModuleList sequence out of range: " << sequence << "/" << module_count_; - return NULL; + return nullptr; } unsigned int module_index; if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index, - NULL /* base */, NULL /* delta */, - NULL /* size */)) { + nullptr /* base */, nullptr /* delta */, + nullptr /* size */)) { BPLOG(ERROR) << "MinidumpModuleList has no module at sequence " << sequence; - return NULL; + return nullptr; } return GetModuleAtIndex(module_index); @@ -2907,13 +3356,13 @@ const MinidumpModule* MinidumpModuleList::GetModuleAtIndex( unsigned int index) const { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtIndex"; - return NULL; + return nullptr; } if (index >= module_count_) { BPLOG(ERROR) << "MinidumpModuleList index out of range: " << index << "/" << module_count_; - return NULL; + return nullptr; } return &(*modules_)[index]; @@ -2960,8 +3409,8 @@ uint32_t MinidumpMemoryList::max_regions_ = 4096; MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump) : MinidumpStream(minidump), range_map_(new RangeMap()), - descriptors_(NULL), - regions_(NULL), + descriptors_(nullptr), + regions_(nullptr), region_count_(0) { } @@ -2976,9 +3425,9 @@ MinidumpMemoryList::~MinidumpMemoryList() { bool MinidumpMemoryList::Read(uint32_t expected_size) { // Invalidate cached data. delete descriptors_; - descriptors_ = NULL; + descriptors_ = nullptr; delete regions_; - regions_ = NULL; + regions_ = nullptr; range_map_->Clear(); region_count_ = 0; @@ -3031,7 +3480,7 @@ bool MinidumpMemoryList::Read(uint32_t expected_size) { } if (region_count != 0) { - scoped_ptr descriptors( + std::unique_ptr descriptors( new MemoryDescriptors(region_count)); // Read the entire array in one fell swoop, instead of reading one entry @@ -3042,7 +3491,7 @@ bool MinidumpMemoryList::Read(uint32_t expected_size) { return false; } - scoped_ptr regions( + std::unique_ptr regions( new MemoryRegions(region_count, MinidumpMemoryRegion(minidump_))); for (unsigned int region_index = 0; @@ -3092,13 +3541,13 @@ MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionAtIndex( unsigned int index) { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionAtIndex"; - return NULL; + return nullptr; } if (index >= region_count_) { BPLOG(ERROR) << "MinidumpMemoryList index out of range: " << index << "/" << region_count_; - return NULL; + return nullptr; } return &(*regions_)[index]; @@ -3109,15 +3558,15 @@ MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionForAddress( uint64_t address) { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionForAddress"; - return NULL; + return nullptr; } unsigned int region_index; - if (!range_map_->RetrieveRange(address, ®ion_index, NULL /* base */, - NULL /* delta */, NULL /* size */)) { + if (!range_map_->RetrieveRange(address, ®ion_index, nullptr /* base */, + nullptr /* delta */, nullptr /* size */)) { BPLOG(INFO) << "MinidumpMemoryList has no memory region at " << HexString(address); - return NULL; + return nullptr; } return GetMemoryRegionAtIndex(region_index); @@ -3164,7 +3613,7 @@ void MinidumpMemoryList::Print() { MinidumpException::MinidumpException(Minidump* minidump) : MinidumpStream(minidump), exception_(), - context_(NULL) { + context_(nullptr) { } @@ -3176,7 +3625,7 @@ MinidumpException::~MinidumpException() { bool MinidumpException::Read(uint32_t expected_size) { // Invalidate cached data. delete context_; - context_ = NULL; + context_ = nullptr; valid_ = false; @@ -3234,22 +3683,22 @@ bool MinidumpException::GetThreadID(uint32_t* thread_id) const { MinidumpContext* MinidumpException::GetContext() { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpException for GetContext"; - return NULL; + return nullptr; } if (!context_) { if (!minidump_->SeekSet(exception_.thread_context.rva)) { BPLOG(ERROR) << "MinidumpException cannot seek to context"; - return NULL; + return nullptr; } - scoped_ptr context(new MinidumpContext(minidump_)); + std::unique_ptr context(new MinidumpContext(minidump_)); // Don't log as an error if we can still fall back on the thread's context // (which must be possible if we got this far.) if (!context->Read(exception_.thread_context.data_size)) { BPLOG(INFO) << "MinidumpException cannot read context"; - return NULL; + return nullptr; } context_ = context.release(); @@ -3380,8 +3829,8 @@ void MinidumpAssertion::Print() { MinidumpSystemInfo::MinidumpSystemInfo(Minidump* minidump) : MinidumpStream(minidump), system_info_(), - csd_version_(NULL), - cpu_vendor_(NULL) { + csd_version_(nullptr), + cpu_vendor_(nullptr) { } @@ -3394,9 +3843,9 @@ MinidumpSystemInfo::~MinidumpSystemInfo() { bool MinidumpSystemInfo::Read(uint32_t expected_size) { // Invalidate cached data. delete csd_version_; - csd_version_ = NULL; + csd_version_ = nullptr; delete cpu_vendor_; - cpu_vendor_ = NULL; + cpu_vendor_ = nullptr; valid_ = false; @@ -3538,6 +3987,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); @@ -3551,7 +4008,7 @@ string MinidumpSystemInfo::GetCPU() { const string* MinidumpSystemInfo::GetCSDVersion() { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCSDVersion"; - return NULL; + return nullptr; } if (!csd_version_) @@ -3567,7 +4024,7 @@ const string* MinidumpSystemInfo::GetCSDVersion() { const string* MinidumpSystemInfo::GetCPUVendor() { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPUVendor"; - return NULL; + return nullptr; } // CPU vendor information can only be determined from x86 minidumps. @@ -3603,8 +4060,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 +4076,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", @@ -3676,7 +4133,7 @@ MinidumpUnloadedModule::MinidumpUnloadedModule(Minidump* minidump) : MinidumpObject(minidump), module_valid_(false), unloaded_module_(), - name_(NULL) { + name_(nullptr) { } @@ -3858,7 +4315,7 @@ uint32_t MinidumpUnloadedModuleList::max_modules_ = 2048; MinidumpUnloadedModuleList::MinidumpUnloadedModuleList(Minidump* minidump) : MinidumpStream(minidump), range_map_(new RangeMap()), - unloaded_modules_(NULL), + unloaded_modules_(nullptr), module_count_(0) { range_map_->SetMergeStrategy(MergeRangeStrategy::kTruncateLower); } @@ -3872,7 +4329,7 @@ MinidumpUnloadedModuleList::~MinidumpUnloadedModuleList() { bool MinidumpUnloadedModuleList::Read(uint32_t expected_size) { range_map_->Clear(); delete unloaded_modules_; - unloaded_modules_ = NULL; + unloaded_modules_ = nullptr; module_count_ = 0; valid_ = false; @@ -3927,7 +4384,7 @@ bool MinidumpUnloadedModuleList::Read(uint32_t expected_size) { } if (number_of_entries != 0) { - scoped_ptr modules( + std::unique_ptr modules( new MinidumpUnloadedModules(number_of_entries, MinidumpUnloadedModule(minidump_))); @@ -3975,15 +4432,15 @@ const MinidumpUnloadedModule* MinidumpUnloadedModuleList::GetModuleForAddress( if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpUnloadedModuleList for GetModuleForAddress"; - return NULL; + return nullptr; } unsigned int module_index; - if (!range_map_->RetrieveRange(address, &module_index, NULL /* base */, - NULL /* delta */, NULL /* size */)) { + if (!range_map_->RetrieveRange(address, &module_index, nullptr /* base */, + nullptr /* delta */, nullptr /* size */)) { BPLOG(INFO) << "MinidumpUnloadedModuleList has no module at " << HexString(address); - return NULL; + return nullptr; } return GetModuleAtIndex(module_index); @@ -3991,7 +4448,7 @@ const MinidumpUnloadedModule* MinidumpUnloadedModuleList::GetModuleForAddress( const MinidumpUnloadedModule* MinidumpUnloadedModuleList::GetMainModule() const { - return NULL; + return nullptr; } const MinidumpUnloadedModule* @@ -3999,22 +4456,22 @@ MinidumpUnloadedModuleList::GetModuleAtSequence(unsigned int sequence) const { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpUnloadedModuleList for GetModuleAtSequence"; - return NULL; + return nullptr; } if (sequence >= module_count_) { BPLOG(ERROR) << "MinidumpUnloadedModuleList sequence out of range: " << sequence << "/" << module_count_; - return NULL; + return nullptr; } unsigned int module_index; if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index, - NULL /* base */, NULL /* delta */, - NULL /* size */)) { + nullptr /* base */, nullptr /* delta */, + nullptr /* size */)) { BPLOG(ERROR) << "MinidumpUnloadedModuleList has no module at sequence " << sequence; - return NULL; + return nullptr; } return GetModuleAtIndex(module_index); @@ -4025,13 +4482,13 @@ MinidumpUnloadedModuleList::GetModuleAtIndex( unsigned int index) const { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpUnloadedModuleList for GetModuleAtIndex"; - return NULL; + return nullptr; } if (index >= module_count_) { BPLOG(ERROR) << "MinidumpUnloadedModuleList index out of range: " << index << "/" << module_count_; - return NULL; + return nullptr; } return &(*unloaded_modules_)[index]; @@ -4513,7 +4970,7 @@ void MinidumpMemoryInfo::Print() { MinidumpMemoryInfoList::MinidumpMemoryInfoList(Minidump* minidump) : MinidumpStream(minidump), range_map_(new RangeMap()), - infos_(NULL), + infos_(nullptr), info_count_(0) { } @@ -4527,7 +4984,7 @@ MinidumpMemoryInfoList::~MinidumpMemoryInfoList() { bool MinidumpMemoryInfoList::Read(uint32_t expected_size) { // Invalidate cached data. delete infos_; - infos_ = NULL; + infos_ = nullptr; range_map_->Clear(); info_count_ = 0; @@ -4596,7 +5053,7 @@ bool MinidumpMemoryInfoList::Read(uint32_t expected_size) { } if (header.number_of_entries != 0) { - scoped_ptr infos( + std::unique_ptr infos( new MinidumpMemoryInfos(header_number_of_entries, MinidumpMemoryInfo(minidump_))); @@ -4639,13 +5096,13 @@ const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoAtIndex( unsigned int index) const { if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for GetMemoryInfoAtIndex"; - return NULL; + return nullptr; } if (index >= info_count_) { BPLOG(ERROR) << "MinidumpMemoryInfoList index out of range: " << index << "/" << info_count_; - return NULL; + return nullptr; } return &(*infos_)[index]; @@ -4657,15 +5114,15 @@ const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoForAddress( if (!valid_) { BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for" " GetMemoryInfoForAddress"; - return NULL; + return nullptr; } unsigned int info_index; - if (!range_map_->RetrieveRange(address, &info_index, NULL /* base */, - NULL /* delta */, NULL /* size */)) { + if (!range_map_->RetrieveRange(address, &info_index, nullptr /* base */, + nullptr /* delta */, nullptr /* size */)) { BPLOG(INFO) << "MinidumpMemoryInfoList has no memory info at " << HexString(address); - return NULL; + return nullptr; } return GetMemoryInfoAtIndex(info_index); @@ -4713,7 +5170,7 @@ void MinidumpLinuxMaps::Print() const { MinidumpLinuxMapsList::MinidumpLinuxMapsList(Minidump* minidump) : MinidumpStream(minidump), - maps_(NULL), + maps_(nullptr), maps_count_(0) { } @@ -4728,9 +5185,9 @@ MinidumpLinuxMapsList::~MinidumpLinuxMapsList() { const MinidumpLinuxMaps* MinidumpLinuxMapsList::GetLinuxMapsForAddress( uint64_t address) const { - if (!valid_ || (maps_ == NULL)) { + if (!valid_ || (maps_ == nullptr)) { BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsForAddress"; - return NULL; + return nullptr; } // Search every memory mapping. @@ -4745,23 +5202,23 @@ const MinidumpLinuxMaps* MinidumpLinuxMapsList::GetLinuxMapsForAddress( // No mapping encloses the memory address. BPLOG(ERROR) << "MinidumpLinuxMapsList has no mapping at " << HexString(address); - return NULL; + return nullptr; } const MinidumpLinuxMaps* MinidumpLinuxMapsList::GetLinuxMapsAtIndex( unsigned int index) const { - if (!valid_ || (maps_ == NULL)) { + if (!valid_ || (maps_ == nullptr)) { BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsAtIndex"; - return NULL; + return nullptr; } // Index out of bounds. - if (index >= maps_count_ || (maps_ == NULL)) { + if (index >= maps_count_ || (maps_ == nullptr)) { BPLOG(ERROR) << "MinidumpLinuxMapsList index of out range: " << index << "/" << maps_count_; - return NULL; + return nullptr; } return (*maps_)[index]; } @@ -4774,7 +5231,7 @@ bool MinidumpLinuxMapsList::Read(uint32_t expected_size) { } delete maps_; } - maps_ = NULL; + maps_ = nullptr; maps_count_ = 0; valid_ = false; @@ -4808,11 +5265,11 @@ bool MinidumpLinuxMapsList::Read(uint32_t expected_size) { return false; } - scoped_ptr maps(new MinidumpLinuxMappings()); + std::unique_ptr maps(new MinidumpLinuxMappings()); // Push mapping data into wrapper classes. for (size_t i = 0; i < all_regions.size(); i++) { - scoped_ptr ele(new MinidumpLinuxMaps(minidump_)); + std::unique_ptr ele(new MinidumpLinuxMaps(minidump_)); ele->region_ = all_regions[i]; ele->valid_ = true; maps->push_back(ele.release()); @@ -4826,7 +5283,7 @@ bool MinidumpLinuxMapsList::Read(uint32_t expected_size) { } void MinidumpLinuxMapsList::Print() const { - if (!valid_ || (maps_ == NULL)) { + if (!valid_ || (maps_ == nullptr)) { BPLOG(ERROR) << "MinidumpLinuxMapsList cannot print valid data"; return; } @@ -4847,6 +5304,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 +5312,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 +5365,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 +5430,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 list_annotations; @@ -4958,11 +5455,26 @@ bool MinidumpCrashpadInfo::Read(uint32_t expected_size) { } } + std::vector 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_list_annotations_.push_back(std::move( + list_annotations)); + module_crashpad_info_simple_annotations_.push_back(std::move( + simple_annotations)); + module_crashpad_info_annotation_objects_.push_back(std::move( + annotation_objects)); } } @@ -4983,12 +5495,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::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 +5506,41 @@ 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::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()); + } + const auto& crashpad_annots = + module_crashpad_info_annotation_objects_[module_index]; + for (const AnnotationObject& annot : crashpad_annots) { + std::string str_value; + if (annot.type == 1) { + // Value represents a C-style string. + for (const uint8_t& v : annot.value) { + str_value.append(1, static_cast(v)); + } + } else { + // Value represents something else. + char buffer[3]; + for (const uint8_t& v : annot.value) { + snprintf(buffer, sizeof(buffer), "%02X", v); + str_value.append(buffer); + } + } + printf( + " module_list[%d].crashpad_annotations[\"%s\"] (type = %u) = %s\n", + module_index, annot.name.c_str(), annot.type, str_value.c_str()); } + printf(" address_mask = %" PRIu64 "\n", crashpad_info_.address_mask); } printf("\n"); @@ -5032,10 +5558,10 @@ unsigned int Minidump::max_string_length_ = 1024; Minidump::Minidump(const string& path, bool hexdump, unsigned int hexdump_width) : header_(), - directory_(NULL), + directory_(nullptr), stream_map_(new MinidumpStreamMap()), path_(path), - stream_(NULL), + stream_(nullptr), swap_(false), is_big_endian_(false), valid_(false), @@ -5045,7 +5571,7 @@ Minidump::Minidump(const string& path, bool hexdump, unsigned int hexdump_width) Minidump::Minidump(istream& stream) : header_(), - directory_(NULL), + directory_(nullptr), stream_map_(new MinidumpStreamMap()), path_(), stream_(&stream), @@ -5069,7 +5595,7 @@ Minidump::~Minidump() { bool Minidump::Open() { - if (stream_ != NULL) { + if (stream_ != nullptr) { BPLOG(INFO) << "Minidump reopening minidump " << path_; // The file is already open. Seek to the beginning, which is the position @@ -5103,9 +5629,9 @@ bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t* context_cpu_flags) { } const MDRawSystemInfo* system_info = - GetSystemInfo() ? GetSystemInfo()->system_info() : NULL; + GetSystemInfo() ? GetSystemInfo()->system_info() : nullptr; - if (system_info != NULL) { + if (system_info != nullptr) { switch (system_info->processor_architecture) { case MD_CPU_ARCHITECTURE_X86: *context_cpu_flags = MD_CONTEXT_X86; @@ -5155,6 +5681,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; @@ -5172,7 +5704,7 @@ bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t* context_cpu_flags) { bool Minidump::Read() { // Invalidate cached data. delete directory_; - directory_ = NULL; + directory_ = nullptr; stream_map_->clear(); valid_ = false; @@ -5250,7 +5782,7 @@ bool Minidump::Read() { } if (header_.stream_count != 0) { - scoped_ptr directory( + std::unique_ptr directory( new MinidumpDirectoryEntries(header_.stream_count)); // Read the entire array in one fell swoop, instead of reading one entry @@ -5276,6 +5808,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: @@ -5290,7 +5823,7 @@ bool Minidump::Read() { stream_type << ", but can only deal with one"; return false; } - BP_FALLTHROUGH; + [[fallthrough]]; } default: { @@ -5314,6 +5847,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; @@ -5383,7 +5920,7 @@ bool Minidump::GetPlatform(MDOSPlatform* platform) { return false; } const MDRawSystemInfo* system_info = - GetSystemInfo() ? GetSystemInfo()->system_info() : NULL; + GetSystemInfo() ? GetSystemInfo()->system_info() : nullptr; // Restore position and return if (!SeekSet(saved_position)) { @@ -5413,6 +5950,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: @@ -5531,13 +6070,13 @@ const MDRawDirectory* Minidump::GetDirectoryEntryAtIndex(unsigned int index) const { if (!valid_) { BPLOG(ERROR) << "Invalid Minidump for GetDirectoryEntryAtIndex"; - return NULL; + return nullptr; } if (index >= header_.stream_count) { BPLOG(ERROR) << "Minidump stream directory index out of range: " << index << "/" << header_.stream_count; - return NULL; + return nullptr; } return &(*directory_)[index]; @@ -5612,18 +6151,18 @@ off_t Minidump::Tell() { string* Minidump::ReadString(off_t offset) { if (!valid_) { BPLOG(ERROR) << "Invalid Minidump for ReadString"; - return NULL; + return nullptr; } if (!SeekSet(offset)) { BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset; - return NULL; + return nullptr; } uint32_t bytes; if (!ReadBytes(&bytes, sizeof(bytes))) { BPLOG(ERROR) << "ReadString could not read string size at offset " << offset; - return NULL; + return nullptr; } if (swap_) Swap(&bytes); @@ -5631,7 +6170,7 @@ string* Minidump::ReadString(off_t offset) { if (bytes % 2 != 0) { BPLOG(ERROR) << "ReadString found odd-sized " << bytes << "-byte string at offset " << offset; - return NULL; + return nullptr; } unsigned int utf16_words = bytes / 2; @@ -5639,7 +6178,7 @@ string* Minidump::ReadString(off_t offset) { BPLOG(ERROR) << "ReadString string length " << utf16_words << " exceeds maximum " << max_string_length_ << " at offset " << offset; - return NULL; + return nullptr; } vector string_utf16(utf16_words); @@ -5648,7 +6187,7 @@ string* Minidump::ReadString(off_t offset) { if (!ReadBytes(&string_utf16[0], bytes)) { BPLOG(ERROR) << "ReadString could not read " << bytes << "-byte string at offset " << offset; - return NULL; + return nullptr; } } @@ -5737,7 +6276,7 @@ bool Minidump::ReadStringList( return false; } - string_list->push_back(entry); + string_list->push_back(std::move(entry)); } return true; @@ -5807,6 +6346,73 @@ bool Minidump::ReadSimpleStringDictionary( return true; } +bool Minidump::ReadCrashpadAnnotationsList( + off_t offset, + std::vector* 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 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 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(std::move(object)); + } + + return true; +} bool Minidump::SeekToStreamType(uint32_t stream_type, uint32_t* stream_length) { @@ -5858,18 +6464,18 @@ T* Minidump::GetStream(T** stream) { BPLOG_IF(ERROR, !stream) << "Minidump::GetStream type " << stream_type << " requires |stream|"; assert(stream); - *stream = NULL; + *stream = nullptr; if (!valid_) { BPLOG(ERROR) << "Invalid Minidump for GetStream type " << stream_type; - return NULL; + return nullptr; } MinidumpStreamMap::iterator iterator = stream_map_->find(stream_type); if (iterator == stream_map_->end()) { // This stream type didn't exist in the directory. BPLOG(INFO) << "GetStream: type " << stream_type << " not present"; - return NULL; + return nullptr; } // Get a pointer so that the stored stream field can be altered. @@ -5885,14 +6491,14 @@ T* Minidump::GetStream(T** stream) { uint32_t stream_length; if (!SeekToStreamType(stream_type, &stream_length)) { BPLOG(ERROR) << "GetStream could not seek to stream type " << stream_type; - return NULL; + return nullptr; } - scoped_ptr new_stream(new T(this)); + std::unique_ptr new_stream(new T(this)); if (!new_stream->Read(stream_length)) { BPLOG(ERROR) << "GetStream could not read stream type " << stream_type; - return NULL; + return nullptr; } *stream = new_stream.release(); diff --git a/src/processor/minidump_dump.cc b/src/processor/minidump_dump.cc index 06802f24f..914d6b765 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. // @@ -32,11 +31,15 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include -#include "common/scoped_ptr.h" +#include "common/path_helper.h" #include "google_breakpad/processor/minidump.h" #include "processor/logging.h" @@ -44,6 +47,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; @@ -93,7 +97,7 @@ static void DumpRawStream(Minidump *minidump, printf("%.*s", int_remaining, &contents[current_offset]); char *next_null = reinterpret_cast( memchr(&contents[current_offset], 0, remaining)); - if (next_null == NULL) + if (next_null == nullptr) break; printf("\\0\n"); size_t null_offset = next_null - &contents[0]; @@ -121,6 +125,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 +242,7 @@ Usage(int argc, char *argv[], bool error) { " 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()); } //============================================================================= diff --git a/src/processor/minidump_dump_test b/src/processor/minidump_dump_test index fb62ace73..32ae38c5c 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 04b7e129e..463b09793 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. // @@ -27,14 +26,23 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/minidump_processor.h" #include +#include +#include #include +#include +#include +#include #include +#include -#include "common/scoped_ptr.h" #include "common/stdio_wrapper.h" #include "common/using_std_string.h" #include "google_breakpad/processor/call_stack.h" @@ -46,6 +54,10 @@ #include "processor/stackwalker_x86.h" #include "processor/symbolic_constants_win.h" +#ifdef __linux__ +#include "processor/disassembler_objdump.h" +#endif + namespace google_breakpad { MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier, @@ -53,7 +65,9 @@ MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier, : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), own_frame_symbolizer_(true), enable_exploitability_(false), - enable_objdump_(false) { + enable_objdump_(false), + enable_objdump_for_exploitability_(false), + max_thread_count_(-1) { } MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier, @@ -62,7 +76,9 @@ MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier, : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), own_frame_symbolizer_(true), enable_exploitability_(enable_exploitability), - enable_objdump_(false) { + enable_objdump_(false), + enable_objdump_for_exploitability_(false), + max_thread_count_(-1) { } MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer* frame_symbolizer, @@ -70,7 +86,9 @@ MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer* frame_symbolizer, : frame_symbolizer_(frame_symbolizer), own_frame_symbolizer_(false), enable_exploitability_(enable_exploitability), - enable_objdump_(false) { + enable_objdump_(false), + enable_objdump_for_exploitability_(false), + max_thread_count_(-1) { assert(frame_symbolizer_); } @@ -116,7 +134,7 @@ ProcessResult MinidumpProcessor::Process( 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, @@ -182,23 +200,48 @@ ProcessResult MinidumpProcessor::Process( } BPLOG(INFO) << "Minidump " << dump->path() << " has " << - (has_cpu_info ? "" : "no ") << "CPU info, " << - (has_os_info ? "" : "no ") << "OS info, " << - (breakpad_info != NULL ? "" : "no ") << "Breakpad info, " << - (exception != NULL ? "" : "no ") << "exception, " << - (module_list != NULL ? "" : "no ") << "module list, " << - (threads != NULL ? "" : "no ") << "thread list, " << - (has_dump_thread ? "" : "no ") << "dump thread, " << - (has_requesting_thread ? "" : "no ") << "requesting thread, and " << - (has_process_create_time ? "" : "no ") << "process create time"; + (has_cpu_info ? "" : "no ") << "CPU info, " << + (has_os_info ? "" : "no ") << "OS info, " << + (breakpad_info != nullptr ? "" : "no ") << "Breakpad info, " << + (exception != nullptr ? "" : "no ") << "exception, " << + (module_list != nullptr ? "" : "no ") << "module list, " << + (threads != nullptr ? "" : "no ") << "thread list, " << + (has_dump_thread ? "" : "no ") << "dump thread, " << + (has_requesting_thread ? "" : "no ") << "requesting thread, and " << + (has_process_create_time ? "" : "no ") << "process create time"; bool interrupted = false; bool found_requesting_thread = false; unsigned int thread_count = threads->thread_count(); + process_state->original_thread_count_ = thread_count; // Reset frame_symbolizer_ at the beginning of stackwalk for each minidump. frame_symbolizer_->Reset(); + MinidumpThreadNameList* thread_names = dump->GetThreadNameList(); + std::map 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) { @@ -220,6 +263,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,6 +278,7 @@ ProcessResult MinidumpProcessor::Process( // dump of itself (when both its context and its stack are in flux), // processing that stack wouldn't provide much useful data. if (has_dump_thread && thread_id == dump_thread_id) { + process_state->original_thread_count_--; continue; } @@ -247,6 +299,13 @@ ProcessResult MinidumpProcessor::Process( // be the index of the current thread when it's pushed into the // vector. process_state->requesting_thread_ = process_state->threads_.size(); + if (max_thread_count_ >= 0) { + thread_count = + std::min(thread_count, + std::max(static_cast( + process_state->requesting_thread_ + 1), + static_cast(max_thread_count_))); + } found_requesting_thread = true; @@ -285,7 +344,7 @@ ProcessResult MinidumpProcessor::Process( // returns. process_state->modules_ is owned by the ProcessState object // (just like the StackFrame objects), and is much more suitable for this // task. - scoped_ptr stackwalker( + std::unique_ptr stackwalker( Stackwalker::StackwalkerForCPU(process_state->system_info(), context, thread_memory, @@ -293,7 +352,7 @@ ProcessResult MinidumpProcessor::Process( process_state->unloaded_modules_, frame_symbolizer_)); - scoped_ptr stack(new CallStack()); + std::unique_ptr stack(new CallStack()); if (stackwalker.get()) { if (!stackwalker->Walk(stack.get(), &process_state->modules_without_symbols_, @@ -311,6 +370,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(std::move(thread_name)); } if (interrupted) { @@ -333,12 +393,11 @@ ProcessResult MinidumpProcessor::Process( // If an exploitability run was requested we perform the platform specific // rating. if (enable_exploitability_) { - scoped_ptr exploitability( - Exploitability::ExploitabilityForPlatform(dump, - process_state, - enable_objdump_)); + std::unique_ptr exploitability( + Exploitability::ExploitabilityForPlatform( + dump, process_state, enable_objdump_for_exploitability_)); // The engine will be null if the platform is not supported - if (exploitability != NULL) { + if (exploitability != nullptr) { process_state->exploitability_ = exploitability->CheckExploitability(); } else { process_state->exploitability_ = EXPLOITABILITY_ERR_NOENGINE; @@ -369,7 +428,7 @@ static const MDRawSystemInfo* GetSystemInfo(Minidump* dump, MinidumpSystemInfo** system_info) { MinidumpSystemInfo* minidump_system_info = dump->GetSystemInfo(); if (!minidump_system_info) - return NULL; + return nullptr; if (system_info) *system_info = minidump_system_info; @@ -402,7 +461,7 @@ static uint64_t GetAddressForArchitecture(const MDCPUArchitecture architecture, // cpu_info: address of target string, cpu info text will be appended to it. static void GetARMCpuInfo(const MDRawSystemInfo* raw_info, string* cpu_info) { - assert(raw_info != NULL && cpu_info != NULL); + assert(raw_info != nullptr && cpu_info != nullptr); // Write ARM architecture version. char cpu_string[32]; @@ -472,7 +531,7 @@ static void GetARMCpuInfo(const MDRawSystemInfo* raw_info, uint32_t cpuid = raw_info->cpu.arm_cpu_info.cpuid; if (cpuid != 0) { // Extract vendor name from CPUID - const char* vendor = NULL; + const char* vendor = nullptr; uint32_t vendor_id = (cpuid >> 24) & 0xff; for (size_t i = 0; i < sizeof(vendors)/sizeof(vendors[0]); ++i) { if (vendors[i].id == vendor_id) { @@ -490,7 +549,7 @@ static void GetARMCpuInfo(const MDRawSystemInfo* raw_info, // Extract part name from CPUID uint32_t part_id = (cpuid & 0xff00fff0); - const char* part = NULL; + const char* part = nullptr; for (size_t i = 0; i < sizeof(parts)/sizeof(parts[0]); ++i) { if (parts[i].id == part_id) { part = parts[i].name; @@ -498,7 +557,7 @@ static void GetARMCpuInfo(const MDRawSystemInfo* raw_info, } } cpu_info->append(" "); - if (part != NULL) { + if (part != nullptr) { cpu_info->append(part); } else { snprintf(cpu_string, sizeof(cpu_string), "part(0x%x)", part_id); @@ -592,6 +651,16 @@ bool MinidumpProcessor::GetCPUInfo(Minidump* dump, SystemInfo* info) { break; } + case MD_CPU_ARCHITECTURE_RISCV: { + info->cpu = "riscv"; + break; + } + + case MD_CPU_ARCHITECTURE_RISCV64: { + info->cpu = "riscv64"; + break; + } + default: { // Assign the numeric architecture ID into the CPU string. char cpu_string[7]; @@ -726,8 +795,83 @@ bool MinidumpProcessor::GetProcessCreateTime(Minidump* dump, return true; } +#ifdef __linux__ + +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 == nullptr) { + BPLOG(INFO) << "Failed to get exception."; + return; + } + + MinidumpContext* context = exception->GetContext(); + if (context == nullptr) { + 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) : nullptr; + if (!memory_region) { + BPLOG(INFO) << "No memory region around instruction pointer."; + return; + } + + DisassemblerObjdump disassembler(context->GetContextCPU(), memory_region, + instruction_ptr); + 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; + } +} +#endif // __linux__ + // static -string MinidumpProcessor::GetCrashReason(Minidump* dump, uint64_t* address) { +string MinidumpProcessor::GetCrashReason(Minidump* dump, uint64_t* address, + bool enable_objdump) { MinidumpException* exception = dump->GetException(); if (!exception) return ""; @@ -752,7 +896,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, nullptr); if (!raw_system_info) return reason; @@ -1135,9 +1279,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; } @@ -1202,7 +1357,7 @@ string MinidumpProcessor::GetCrashReason(Minidump* dump, uint64_t* address) { // an attempt to read data, 1 if it was an attempt to write data, // and 8 if this was a data execution violation. // exception_information[2] contains the underlying NTSTATUS code, - // which is the explanation for why this error occured. + // which is the explanation for why this error occurred. // This information is useful in addition to the code address, which // will be present in the crash thread's instruction field anyway. if (raw_exception->exception_record.number_parameters >= 1) { @@ -1294,7 +1449,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( + 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"; @@ -1444,6 +1812,21 @@ string MinidumpProcessor::GetCrashReason(Minidump* dump, uint64_t* address) { case MD_EXCEPTION_FLAG_LIN_SEGV_PKUERR: reason.append("SEGV_PKUERR"); break; + case MD_EXCEPTION_FLAG_LIN_SEGV_ACCADI: + reason.append("SEGV_ACCADI"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_ADIDERR: + reason.append("SEGV_ADIDERR"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_ADIPERR: + reason.append("SEGV_ADIPERR"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_MTEAERR: + reason.append("SEGV_MTEAERR"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_MTESERR: + reason.append("SEGV_MTESERR"); + break; default: reason.append(flags_string); BPLOG(INFO) << "Unknown exception reason " << reason; @@ -1737,6 +2120,17 @@ string MinidumpProcessor::GetCrashReason(Minidump* dump, uint64_t* address) { *address = GetAddressForArchitecture( static_cast(raw_system_info->processor_architecture), *address); + +#ifdef __linux__ + // 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::max() == *address) { + CalculateFaultAddressFromInstruction(dump, address); + } +#endif // __linux__ } return reason; diff --git a/src/processor/minidump_processor_unittest.cc b/src/processor/minidump_processor_unittest.cc index 306c2f0b0..c95cdd9df 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. // @@ -30,6 +29,10 @@ // Unit test for MinidumpProcessor. Uses a pre-generated minidump and // corresponding symbol file, and checks the stack frames for correctness. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -39,7 +42,6 @@ #include #include "breakpad_googletest_includes.h" -#include "common/scoped_ptr.h" #include "common/using_std_string.h" #include "google_breakpad/processor/basic_source_line_resolver.h" #include "google_breakpad/processor/call_stack.h" @@ -77,12 +79,12 @@ class MockMinidump : public Minidump { class MockMinidumpUnloadedModule : public MinidumpUnloadedModule { public: - MockMinidumpUnloadedModule() : MinidumpUnloadedModule(NULL) {} + MockMinidumpUnloadedModule() : MinidumpUnloadedModule(nullptr) {} }; class MockMinidumpUnloadedModuleList : public MinidumpUnloadedModuleList { public: - MockMinidumpUnloadedModuleList() : MinidumpUnloadedModuleList(NULL) {} + MockMinidumpUnloadedModuleList() : MinidumpUnloadedModuleList(nullptr) {} ~MockMinidumpUnloadedModuleList() {} MOCK_CONST_METHOD0(Copy, CodeModules*()); @@ -92,7 +94,7 @@ class MockMinidumpUnloadedModuleList : public MinidumpUnloadedModuleList { class MockMinidumpThreadList : public MinidumpThreadList { public: - MockMinidumpThreadList() : MinidumpThreadList(NULL) {} + MockMinidumpThreadList() : MinidumpThreadList(nullptr) {} MOCK_CONST_METHOD0(thread_count, unsigned int()); MOCK_CONST_METHOD1(GetThreadAtIndex, MinidumpThread*(unsigned int)); @@ -100,14 +102,14 @@ class MockMinidumpThreadList : public MinidumpThreadList { class MockMinidumpMemoryList : public MinidumpMemoryList { public: - MockMinidumpMemoryList() : MinidumpMemoryList(NULL) {} + MockMinidumpMemoryList() : MinidumpMemoryList(nullptr) {} MOCK_METHOD1(GetMemoryRegionForAddress, MinidumpMemoryRegion*(uint64_t)); }; class MockMinidumpThread : public MinidumpThread { public: - MockMinidumpThread() : MinidumpThread(NULL) {} + MockMinidumpThread() : MinidumpThread(nullptr) {} MOCK_CONST_METHOD1(GetThreadID, bool(uint32_t*)); MOCK_METHOD0(GetContext, MinidumpContext*()); @@ -120,7 +122,7 @@ class MockMinidumpThread : public MinidumpThread { class MockMinidumpMemoryRegion : public MinidumpMemoryRegion { public: MockMinidumpMemoryRegion(uint64_t base, const string& contents) : - MinidumpMemoryRegion(NULL) { + MinidumpMemoryRegion(nullptr) { region_.Init(base, contents); } @@ -148,7 +150,7 @@ class MockMinidumpMemoryRegion : public MinidumpMemoryRegion { class TestMinidumpMiscInfo : public MinidumpMiscInfo { public: explicit TestMinidumpMiscInfo(const MDRawMiscInfo& misc_info) : - MinidumpMiscInfo(NULL) { + MinidumpMiscInfo(nullptr) { valid_ = true; misc_info_ = misc_info; } @@ -176,7 +178,6 @@ using google_breakpad::MockMinidumpThreadList; using google_breakpad::MockMinidumpUnloadedModule; using google_breakpad::MockMinidumpUnloadedModuleList; using google_breakpad::ProcessState; -using google_breakpad::scoped_ptr; using google_breakpad::SymbolSupplier; using google_breakpad::SystemInfo; using ::testing::_; @@ -294,7 +295,7 @@ SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData( if (s == FOUND) { *symbol_data_size = symbol_data_string.size() + 1; *symbol_data = new char[*symbol_data_size]; - if (*symbol_data == NULL) { + if (*symbol_data == nullptr) { BPLOG(ERROR) << "Memory allocation failed for module: " << module->code_file() << " size: " << *symbol_data_size; return INTERRUPT; @@ -320,7 +321,7 @@ void TestSymbolSupplier::FreeSymbolData(const CodeModule* module) { class TestMinidumpSystemInfo : public MinidumpSystemInfo { public: explicit TestMinidumpSystemInfo(MDRawSystemInfo info) : - MinidumpSystemInfo(NULL) { + MinidumpSystemInfo(nullptr) { valid_ = true; system_info_ = info; csd_version_ = new string(""); @@ -332,7 +333,7 @@ class TestMinidumpSystemInfo : public MinidumpSystemInfo { class TestMinidumpContext : public MinidumpContext { public: explicit TestMinidumpContext(const MDRawContextX86& context) : - MinidumpContext(NULL) { + MinidumpContext(nullptr) { valid_ = true; SetContextX86(new MDRawContextX86(context)); SetContextFlags(MD_CONTEXT_X86); @@ -414,7 +415,7 @@ TEST_F(MinidumpProcessorTest, TestUnloadedModules) { EXPECT_CALL(*unloaded_module_list_copy, GetModuleForAddress(kExpectedEIP)). WillOnce(Return(&unloaded_module)); - MinidumpProcessor processor(reinterpret_cast(NULL), NULL); + MinidumpProcessor processor(static_cast(nullptr), nullptr); ProcessState state; EXPECT_EQ(processor.Process(&dump, &state), google_breakpad::PROCESS_OK); @@ -442,16 +443,16 @@ TEST_F(MinidumpProcessorTest, TestCorruptMinidumps) { MDRawHeader fakeHeader; fakeHeader.time_date_stamp = 0; EXPECT_CALL(dump, header()). - WillOnce(Return(reinterpret_cast(NULL))). + WillOnce(Return(static_cast(nullptr))). WillRepeatedly(Return(&fakeHeader)); EXPECT_EQ(processor.Process(&dump, &state), google_breakpad::PROCESS_ERROR_NO_MINIDUMP_HEADER); EXPECT_CALL(dump, GetThreadList()). - WillOnce(Return(reinterpret_cast(NULL))); + WillOnce(Return(static_cast(nullptr))); EXPECT_CALL(dump, GetSystemInfo()). - WillRepeatedly(Return(reinterpret_cast(NULL))); + WillRepeatedly(Return(static_cast(nullptr))); EXPECT_EQ(processor.Process(&dump, &state), google_breakpad::PROCESS_ERROR_NO_THREAD_LIST); @@ -615,13 +616,13 @@ TEST_F(MinidumpProcessorTest, TestThreadMissingMemory) { WillRepeatedly(DoAll(SetArgumentPointee<0>(1), Return(true))); EXPECT_CALL(no_memory_thread, GetMemory()). - WillRepeatedly(Return(reinterpret_cast(NULL))); + WillRepeatedly(Return(static_cast(nullptr))); const uint64_t kTestStartOfMemoryRange = 0x1234; EXPECT_CALL(no_memory_thread, GetStartOfStackMemoryRange()). WillRepeatedly(Return(kTestStartOfMemoryRange)); EXPECT_CALL(memory_list, GetMemoryRegionForAddress(kTestStartOfMemoryRange)). - WillRepeatedly(Return(reinterpret_cast(NULL))); + WillRepeatedly(Return(static_cast(nullptr))); MDRawContextX86 no_memory_thread_raw_context; memset(&no_memory_thread_raw_context, 0, @@ -638,7 +639,7 @@ TEST_F(MinidumpProcessorTest, TestThreadMissingMemory) { EXPECT_CALL(thread_list, GetThreadAtIndex(0)). WillOnce(Return(&no_memory_thread)); - MinidumpProcessor processor(reinterpret_cast(NULL), NULL); + MinidumpProcessor processor(static_cast(nullptr), nullptr); ProcessState state; EXPECT_EQ(processor.Process(&dump, &state), google_breakpad::PROCESS_OK); @@ -674,7 +675,7 @@ TEST_F(MinidumpProcessorTest, GetProcessCreateTime) { EXPECT_CALL(dump, GetThreadList()).WillOnce(Return(&thread_list)); EXPECT_CALL(thread_list, thread_count()).WillRepeatedly(Return(0)); - MinidumpProcessor processor(reinterpret_cast(NULL), NULL); + MinidumpProcessor processor(static_cast(nullptr), nullptr); ProcessState state; EXPECT_EQ(google_breakpad::PROCESS_OK, processor.Process(&dump, &state)); @@ -715,7 +716,7 @@ TEST_F(MinidumpProcessorTest, TestThreadMissingContext) { WillRepeatedly(DoAll(SetArgumentPointee<0>(1), Return(true))); EXPECT_CALL(no_context_thread, GetContext()). - WillRepeatedly(Return(reinterpret_cast(NULL))); + WillRepeatedly(Return(static_cast(nullptr))); // The memory contents don't really matter here, since it won't be used. MockMinidumpMemoryRegion no_context_thread_memory(0x1234, "xxx"); @@ -731,7 +732,7 @@ TEST_F(MinidumpProcessorTest, TestThreadMissingContext) { EXPECT_CALL(thread_list, GetThreadAtIndex(0)). WillOnce(Return(&no_context_thread)); - MinidumpProcessor processor(reinterpret_cast(NULL), NULL); + MinidumpProcessor processor(static_cast(nullptr), nullptr); ProcessState state; EXPECT_EQ(processor.Process(&dump, &state), google_breakpad::PROCESS_OK); @@ -761,6 +762,87 @@ TEST_F(MinidumpProcessorTest, Test32BitCrashingAddress) { ASSERT_EQ(state.crash_address(), 0x45U); } +TEST_F(MinidumpProcessorTest, TestXStateX86ContextMinidump) { + // 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-x86.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.22631 "); + ASSERT_EQ(state.system_info()->cpu, "x86"); + ASSERT_EQ(state.system_info()->cpu_info, + "GenuineIntel family 6 model 151 stepping 2"); + ASSERT_FALSE(state.crashed()); + ASSERT_EQ(state.threads()->size(), size_t(3)); + + // TODO: verify cetumsr and cetussp once these are supported by + // breakpad. +} + +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[]) { diff --git a/src/processor/minidump_stackwalk.cc b/src/processor/minidump_stackwalk.cc index aedd0271d..7fab30f4b 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. // @@ -32,16 +31,20 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include #include +#include #include #include #include "common/path_helper.h" -#include "common/scoped_ptr.h" #include "common/using_std_string.h" #include "google_breakpad/processor/basic_source_line_resolver.h" #include "google_breakpad/processor/minidump.h" @@ -57,6 +60,8 @@ namespace { struct Options { bool machine_readable; bool output_stack_contents; + bool output_requesting_thread_only; + bool brief; string minidump_file; std::vector symbol_paths; @@ -69,7 +74,6 @@ using google_breakpad::MinidumpThreadList; using google_breakpad::MinidumpProcessor; using google_breakpad::ProcessState; using google_breakpad::SimpleSymbolSupplier; -using google_breakpad::scoped_ptr; // Processes |options.minidump_file| using MinidumpProcessor. // |options.symbol_path|, if non-empty, is the base directory of a @@ -83,7 +87,7 @@ using google_breakpad::scoped_ptr; // call stacks for each thread contained in the minidump. All information // is printed to stdout. bool PrintMinidumpProcess(const Options& options) { - scoped_ptr symbol_supplier; + std::unique_ptr symbol_supplier; if (!options.symbol_paths.empty()) { // TODO(mmentovai): check existence of symbol_path if specified? symbol_supplier.reset(new SimpleSymbolSupplier(options.symbol_paths)); @@ -110,8 +114,11 @@ bool PrintMinidumpProcess(const Options& options) { if (options.machine_readable) { PrintProcessStateMachineReadable(process_state); + } else if (options.brief) { + PrintRequestingThreadBrief(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 +135,9 @@ 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" + " -b Brief of the thread that causes crash or dump\n", google_breakpad::BaseName(argv[0]).c_str()); } @@ -137,14 +146,22 @@ 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; + options->brief = false; - while ((ch = getopt(argc, (char * const*)argv, "hms")) != -1) { + while ((ch = getopt(argc, (char* const*)argv, "bchms")) != -1) { switch (ch) { case 'h': Usage(argc, argv, false); exit(0); break; + case 'b': + options->brief = true; + 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 2aadb2412..84672183b 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 f97902791..c7da9c4af 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 49b007fed..e91ff26a7 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. // @@ -30,6 +29,10 @@ // Unit test for Minidump. Uses a pre-generated minidump and // verifies that certain streams are correct. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -48,6 +51,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; @@ -92,13 +96,13 @@ TEST_F(MinidumpTest, TestMinidumpFromFile) { ASSERT_EQ(minidump.path(), minidump_file_); ASSERT_TRUE(minidump.Read()); const MDRawHeader* header = minidump.header(); - ASSERT_NE(header, (MDRawHeader*)NULL); + ASSERT_NE(header, (MDRawHeader*)nullptr); ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE)); MinidumpModuleList* md_module_list = minidump.GetModuleList(); - ASSERT_TRUE(md_module_list != NULL); + ASSERT_TRUE(md_module_list != nullptr); const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); - ASSERT_TRUE(md_module != NULL); + ASSERT_TRUE(md_module != nullptr); ASSERT_EQ("c:\\test_app.exe", md_module->code_file()); ASSERT_EQ("c:\\test_app.pdb", md_module->debug_file()); ASSERT_EQ("45D35F6C2d000", md_module->code_identifier()); @@ -107,7 +111,7 @@ TEST_F(MinidumpTest, TestMinidumpFromFile) { TEST_F(MinidumpTest, TestMinidumpFromStream) { // read minidump contents into memory, construct a stringstream around them - ifstream file_stream(minidump_file_.c_str(), std::ios::in); + ifstream file_stream(minidump_file_.c_str(), std::ios::in | std::ios::binary); ASSERT_TRUE(file_stream.good()); vector bytes; file_stream.seekg(0, std::ios_base::end); @@ -126,11 +130,47 @@ TEST_F(MinidumpTest, TestMinidumpFromStream) { ASSERT_EQ(minidump.path(), ""); ASSERT_TRUE(minidump.Read()); const MDRawHeader* header = minidump.header(); - ASSERT_NE(header, (MDRawHeader*)NULL); + ASSERT_NE(header, (MDRawHeader*)nullptr); ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE)); //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 != nullptr); + + const std::vector>* + annotation_objects_list = + crashpad_info->GetModuleCrashpadInfoAnnotationObjects(); + ASSERT_EQ(2U, annotation_objects_list->size()); + + std::vector annotation_objects = + annotation_objects_list->at(0); + ASSERT_EQ(5U, annotation_objects.size()); + + std::vector 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 expected_strings{ + "exceptionReason", "exceptionName", "firstexception_bt", "firstexception", + "CounterAnnotation"}; + ASSERT_EQ(annotation_names, expected_strings); +} + TEST(Dump, ReadBackEmpty) { Dump dump(0); dump.Finish(); @@ -168,7 +208,7 @@ TEST(Dump, OneStream) { ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0); - ASSERT_TRUE(dir != NULL); + ASSERT_TRUE(dir != nullptr); EXPECT_EQ(0xfbb7fa2bU, dir->stream_type); uint32_t stream_length; @@ -204,11 +244,11 @@ TEST(Dump, OneMemory) { ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0); - ASSERT_TRUE(dir != NULL); + ASSERT_TRUE(dir != nullptr); EXPECT_EQ((uint32_t) MD_MEMORY_LIST_STREAM, dir->stream_type); MinidumpMemoryList* memory_list = minidump.GetMemoryList(); - ASSERT_TRUE(memory_list != NULL); + ASSERT_TRUE(memory_list != nullptr); ASSERT_EQ(1U, memory_list->region_count()); MinidumpMemoryRegion* region1 = memory_list->GetMemoryRegionAtIndex(0); @@ -258,7 +298,7 @@ TEST(Dump, OneThread) { ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); MinidumpMemoryList* md_memory_list = minidump.GetMemoryList(); - ASSERT_TRUE(md_memory_list != NULL); + ASSERT_TRUE(md_memory_list != nullptr); ASSERT_EQ(1U, md_memory_list->region_count()); MinidumpMemoryRegion* md_region = md_memory_list->GetMemoryRegionAtIndex(0); @@ -268,23 +308,23 @@ TEST(Dump, OneThread) { ASSERT_TRUE(memcmp("stack for thread", region_bytes, 16) == 0); MinidumpThreadList* thread_list = minidump.GetThreadList(); - ASSERT_TRUE(thread_list != NULL); + ASSERT_TRUE(thread_list != nullptr); ASSERT_EQ(1U, thread_list->thread_count()); MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0); - ASSERT_TRUE(md_thread != NULL); + ASSERT_TRUE(md_thread != nullptr); uint32_t thread_id; ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); ASSERT_EQ(0xa898f11bU, thread_id); MinidumpMemoryRegion* md_stack = md_thread->GetMemory(); - ASSERT_TRUE(md_stack != NULL); + ASSERT_TRUE(md_stack != nullptr); ASSERT_EQ(0x2326a0faU, md_stack->GetBase()); ASSERT_EQ(16U, md_stack->GetSize()); 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(); - ASSERT_TRUE(md_context != NULL); + ASSERT_TRUE(md_context != nullptr); ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); uint64_t eip; @@ -292,7 +332,7 @@ TEST(Dump, OneThread) { EXPECT_EQ(kExpectedEIP, eip); const MDRawContextX86* md_raw_context = md_context->GetContextX86(); - ASSERT_TRUE(md_raw_context != NULL); + ASSERT_TRUE(md_raw_context != nullptr); ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), (md_raw_context->context_flags & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL))); @@ -338,21 +378,21 @@ TEST(Dump, ThreadMissingMemory) { // This should succeed even though the thread has no stack memory. MinidumpThreadList* thread_list = minidump.GetThreadList(); - ASSERT_TRUE(thread_list != NULL); + ASSERT_TRUE(thread_list != nullptr); ASSERT_EQ(1U, thread_list->thread_count()); MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0); - ASSERT_TRUE(md_thread != NULL); + ASSERT_TRUE(md_thread != nullptr); uint32_t thread_id; ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); ASSERT_EQ(0xa898f11bU, thread_id); MinidumpContext* md_context = md_thread->GetContext(); - ASSERT_NE(reinterpret_cast(NULL), md_context); + ASSERT_NE(static_cast(nullptr), md_context); MinidumpMemoryRegion* md_stack = md_thread->GetMemory(); - ASSERT_EQ(reinterpret_cast(NULL), md_stack); + ASSERT_EQ(static_cast(nullptr), md_stack); } TEST(Dump, ThreadMissingContext) { @@ -381,20 +421,20 @@ TEST(Dump, ThreadMissingContext) { // This should succeed even though the thread has no stack memory. MinidumpThreadList* thread_list = minidump.GetThreadList(); - ASSERT_TRUE(thread_list != NULL); + ASSERT_TRUE(thread_list != nullptr); ASSERT_EQ(1U, thread_list->thread_count()); MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0); - ASSERT_TRUE(md_thread != NULL); + ASSERT_TRUE(md_thread != nullptr); uint32_t thread_id; ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); ASSERT_EQ(0xa898f11bU, thread_id); MinidumpMemoryRegion* md_stack = md_thread->GetMemory(); - ASSERT_NE(reinterpret_cast(NULL), md_stack); + ASSERT_NE(static_cast(nullptr), md_stack); MinidumpContext* md_context = md_thread->GetContext(); - ASSERT_EQ(reinterpret_cast(NULL), md_context); + ASSERT_EQ(static_cast(nullptr), md_context); } TEST(Dump, OneUnloadedModule) { @@ -426,17 +466,17 @@ TEST(Dump, OneUnloadedModule) { ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(1); - ASSERT_TRUE(dir != NULL); + ASSERT_TRUE(dir != nullptr); EXPECT_EQ((uint32_t) MD_UNLOADED_MODULE_LIST_STREAM, dir->stream_type); MinidumpUnloadedModuleList* md_unloaded_module_list = minidump.GetUnloadedModuleList(); - ASSERT_TRUE(md_unloaded_module_list != NULL); + ASSERT_TRUE(md_unloaded_module_list != nullptr); ASSERT_EQ(1U, md_unloaded_module_list->module_count()); const MinidumpUnloadedModule* md_unloaded_module = md_unloaded_module_list->GetModuleAtIndex(0); - ASSERT_TRUE(md_unloaded_module != NULL); + ASSERT_TRUE(md_unloaded_module != nullptr); ASSERT_EQ(0xa90206ca83eb2852ULL, md_unloaded_module->base_address()); ASSERT_EQ(0xada542bd, md_unloaded_module->size()); ASSERT_EQ("unloaded module", md_unloaded_module->code_file()); @@ -447,7 +487,7 @@ TEST(Dump, OneUnloadedModule) { const MDRawUnloadedModule* md_raw_unloaded_module = md_unloaded_module->module(); - ASSERT_TRUE(md_raw_unloaded_module != NULL); + ASSERT_TRUE(md_raw_unloaded_module != nullptr); ASSERT_EQ(0xb1054d2aU, md_raw_unloaded_module->time_date_stamp); ASSERT_EQ(0x34571371U, md_raw_unloaded_module->checksum); } @@ -507,15 +547,15 @@ TEST(Dump, OneModule) { ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(1); - ASSERT_TRUE(dir != NULL); + ASSERT_TRUE(dir != nullptr); EXPECT_EQ((uint32_t) MD_MODULE_LIST_STREAM, dir->stream_type); MinidumpModuleList* md_module_list = minidump.GetModuleList(); - ASSERT_TRUE(md_module_list != NULL); + ASSERT_TRUE(md_module_list != nullptr); ASSERT_EQ(1U, md_module_list->module_count()); const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); - ASSERT_TRUE(md_module != NULL); + ASSERT_TRUE(md_module != nullptr); ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address()); ASSERT_EQ(0xada542bd, md_module->size()); ASSERT_EQ("single module", md_module->code_file()); @@ -525,7 +565,7 @@ TEST(Dump, OneModule) { ASSERT_EQ("ABCD1234F00DBEEF01020304050607081", md_module->debug_identifier()); const MDRawModule* md_raw_module = md_module->module(); - ASSERT_TRUE(md_raw_module != NULL); + ASSERT_TRUE(md_raw_module != nullptr); ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp); ASSERT_EQ(0x34571371U, md_raw_module->checksum); ASSERT_TRUE(memcmp(&md_raw_module->version_info, &fixed_file_info, @@ -589,11 +629,11 @@ TEST(Dump, OneModuleCVELF) { ASSERT_TRUE(minidump.Read()); MinidumpModuleList* md_module_list = minidump.GetModuleList(); - ASSERT_TRUE(md_module_list != NULL); + ASSERT_TRUE(md_module_list != nullptr); ASSERT_EQ(1U, md_module_list->module_count()); const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); - ASSERT_TRUE(md_module != NULL); + ASSERT_TRUE(md_module != nullptr); ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address()); ASSERT_EQ(0xada542bd, md_module->size()); ASSERT_EQ("elf module", md_module->code_file()); @@ -607,7 +647,7 @@ TEST(Dump, OneModuleCVELF) { ASSERT_EQ("B4CDA95F53101BDF86FAB733B4DF37380", md_module->debug_identifier()); const MDRawModule* md_raw_module = md_module->module(); - ASSERT_TRUE(md_raw_module != NULL); + ASSERT_TRUE(md_raw_module != nullptr); ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp); ASSERT_EQ(0x34571371U, md_raw_module->checksum); ASSERT_TRUE(memcmp(&md_raw_module->version_info, &fixed_file_info, @@ -671,11 +711,11 @@ TEST(Dump, CVELFShort) { ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); MinidumpModuleList* md_module_list = minidump.GetModuleList(); - ASSERT_TRUE(md_module_list != NULL); + ASSERT_TRUE(md_module_list != nullptr); ASSERT_EQ(1U, md_module_list->module_count()); const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); - ASSERT_TRUE(md_module != NULL); + ASSERT_TRUE(md_module != nullptr); // just the build_id, directly ASSERT_EQ("5fa9cdb4", md_module->code_identifier()); // build_id expanded to GUID length and treated as such, with zero @@ -743,11 +783,11 @@ TEST(Dump, CVELFLong) { ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); MinidumpModuleList* md_module_list = minidump.GetModuleList(); - ASSERT_TRUE(md_module_list != NULL); + ASSERT_TRUE(md_module_list != nullptr); ASSERT_EQ(1U, md_module_list->module_count()); const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); - ASSERT_TRUE(md_module != NULL); + ASSERT_TRUE(md_module != nullptr); // just the build_id, directly ASSERT_EQ( "5fa9cdb41053df1b86fab733b4df3738cea34a870102030405060708090a0b0c0d0e0f", @@ -774,11 +814,11 @@ TEST(Dump, OneSystemInfo) { ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0); - ASSERT_TRUE(dir != NULL); + ASSERT_TRUE(dir != nullptr); EXPECT_EQ((uint32_t) MD_SYSTEM_INFO_STREAM, dir->stream_type); MinidumpSystemInfo* md_system_info = minidump.GetSystemInfo(); - ASSERT_TRUE(md_system_info != NULL); + ASSERT_TRUE(md_system_info != nullptr); ASSERT_EQ("windows", md_system_info->GetOS()); ASSERT_EQ("x86", md_system_info->GetCPU()); ASSERT_EQ("Petulant Pierogi", *md_system_info->GetCSDVersion()); @@ -913,7 +953,7 @@ TEST(Dump, BigDump) { // Check the threads. MinidumpThreadList* thread_list = minidump.GetThreadList(); - ASSERT_TRUE(thread_list != NULL); + ASSERT_TRUE(thread_list != nullptr); ASSERT_EQ(5U, thread_list->thread_count()); uint32_t thread_id; ASSERT_TRUE(thread_list->GetThreadAtIndex(0)->GetThreadID(&thread_id)); @@ -958,7 +998,7 @@ TEST(Dump, BigDump) { // Check the modules. MinidumpModuleList* md_module_list = minidump.GetModuleList(); - ASSERT_TRUE(md_module_list != NULL); + ASSERT_TRUE(md_module_list != nullptr); ASSERT_EQ(3U, md_module_list->module_count()); EXPECT_EQ(0xeb77da57b5d4cbdaULL, md_module_list->GetModuleAtIndex(0)->base_address()); @@ -970,7 +1010,7 @@ TEST(Dump, BigDump) { // Check unloaded modules MinidumpUnloadedModuleList* md_unloaded_module_list = minidump.GetUnloadedModuleList(); - ASSERT_TRUE(md_unloaded_module_list != NULL); + ASSERT_TRUE(md_unloaded_module_list != nullptr); ASSERT_EQ(3U, md_unloaded_module_list->module_count()); EXPECT_EQ(umodule1_base, md_unloaded_module_list->GetModuleAtIndex(0)->base_address()); @@ -987,7 +1027,7 @@ TEST(Dump, BigDump) { umodule = md_unloaded_module_list->GetModuleAtSequence(0); EXPECT_EQ(umodule1_base, umodule->base_address()); - EXPECT_EQ(NULL, md_unloaded_module_list->GetMainModule()); + EXPECT_EQ(nullptr, md_unloaded_module_list->GetMainModule()); } @@ -1026,11 +1066,11 @@ TEST(Dump, OneMemoryInfo) { ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0); - ASSERT_TRUE(dir != NULL); + ASSERT_TRUE(dir != nullptr); EXPECT_EQ((uint32_t) MD_MEMORY_INFO_LIST_STREAM, dir->stream_type); MinidumpMemoryInfoList* info_list = minidump.GetMemoryInfoList(); - ASSERT_TRUE(info_list != NULL); + ASSERT_TRUE(info_list != nullptr); ASSERT_EQ(1U, info_list->info_count()); const MinidumpMemoryInfo* info1 = info_list->GetMemoryInfoAtIndex(0); @@ -1084,24 +1124,24 @@ TEST(Dump, OneExceptionX86) { ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); MinidumpException* md_exception = minidump.GetException(); - ASSERT_TRUE(md_exception != NULL); + ASSERT_TRUE(md_exception != nullptr); uint32_t thread_id; ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); ASSERT_EQ(0x1234abcdU, thread_id); const MDRawExceptionStream* raw_exception = md_exception->exception(); - ASSERT_TRUE(raw_exception != NULL); + ASSERT_TRUE(raw_exception != nullptr); EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, raw_exception->exception_record.exception_address); MinidumpContext* md_context = md_exception->GetContext(); - ASSERT_TRUE(md_context != NULL); + ASSERT_TRUE(md_context != nullptr); ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); const MDRawContextX86* md_raw_context = md_context->GetContextX86(); - ASSERT_TRUE(md_raw_context != NULL); + ASSERT_TRUE(md_raw_context != nullptr); ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), (md_raw_context->context_flags & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL))); @@ -1158,24 +1198,24 @@ TEST(Dump, OneExceptionX86XState) { ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); MinidumpException* md_exception = minidump.GetException(); - ASSERT_TRUE(md_exception != NULL); + ASSERT_TRUE(md_exception != nullptr); uint32_t thread_id; ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); ASSERT_EQ(0x1234abcdU, thread_id); const MDRawExceptionStream* raw_exception = md_exception->exception(); - ASSERT_TRUE(raw_exception != NULL); + ASSERT_TRUE(raw_exception != nullptr); EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, raw_exception->exception_record.exception_address); MinidumpContext* md_context = md_exception->GetContext(); - ASSERT_TRUE(md_context != NULL); + ASSERT_TRUE(md_context != nullptr); ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); const MDRawContextX86* md_raw_context = md_context->GetContextX86(); - ASSERT_TRUE(md_raw_context != NULL); + ASSERT_TRUE(md_raw_context != nullptr); ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), (md_raw_context->context_flags & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL))); @@ -1243,25 +1283,25 @@ TEST(Dump, OneExceptionX86NoCPUFlags) { ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); MinidumpException* md_exception = minidump.GetException(); - ASSERT_TRUE(md_exception != NULL); + ASSERT_TRUE(md_exception != nullptr); uint32_t thread_id; ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); ASSERT_EQ(0x1234abcdU, thread_id); const MDRawExceptionStream* raw_exception = md_exception->exception(); - ASSERT_TRUE(raw_exception != NULL); + ASSERT_TRUE(raw_exception != nullptr); EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, raw_exception->exception_record.exception_address); MinidumpContext* md_context = md_exception->GetContext(); - ASSERT_TRUE(md_context != NULL); + ASSERT_TRUE(md_context != nullptr); ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); const MDRawContextX86* md_raw_context = md_context->GetContextX86(); - ASSERT_TRUE(md_raw_context != NULL); + ASSERT_TRUE(md_raw_context != nullptr); // Even though the CPU flags were missing from the context_flags, the // GetContext call above is expected to load the missing CPU flags from the @@ -1325,14 +1365,14 @@ TEST(Dump, OneExceptionX86NoCPUFlagsNoSystemInfo) { ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); MinidumpException* md_exception = minidump.GetException(); - ASSERT_TRUE(md_exception != NULL); + ASSERT_TRUE(md_exception != nullptr); uint32_t thread_id; ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); ASSERT_EQ(0x1234abcdU, thread_id); const MDRawExceptionStream* raw_exception = md_exception->exception(); - ASSERT_TRUE(raw_exception != NULL); + ASSERT_TRUE(raw_exception != nullptr); EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, @@ -1342,7 +1382,7 @@ TEST(Dump, OneExceptionX86NoCPUFlagsNoSystemInfo) { // 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(); - ASSERT_EQ(NULL, md_context); + ASSERT_EQ(nullptr, md_context); } TEST(Dump, OneExceptionARM) { @@ -1388,24 +1428,24 @@ TEST(Dump, OneExceptionARM) { ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); MinidumpException* md_exception = minidump.GetException(); - ASSERT_TRUE(md_exception != NULL); + ASSERT_TRUE(md_exception != nullptr); uint32_t thread_id; ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); ASSERT_EQ(0x1234abcdU, thread_id); const MDRawExceptionStream* raw_exception = md_exception->exception(); - ASSERT_TRUE(raw_exception != NULL); + ASSERT_TRUE(raw_exception != nullptr); EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, raw_exception->exception_record.exception_address); MinidumpContext* md_context = md_exception->GetContext(); - ASSERT_TRUE(md_context != NULL); + ASSERT_TRUE(md_context != nullptr); ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU()); const MDRawContextARM* md_raw_context = md_context->GetContextARM(); - ASSERT_TRUE(md_raw_context != NULL); + ASSERT_TRUE(md_raw_context != nullptr); ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER, (md_raw_context->context_flags & MD_CONTEXT_ARM_INTEGER)); @@ -1472,24 +1512,24 @@ TEST(Dump, OneExceptionARMOldFlags) { ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); MinidumpException* md_exception = minidump.GetException(); - ASSERT_TRUE(md_exception != NULL); + ASSERT_TRUE(md_exception != nullptr); uint32_t thread_id; ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); ASSERT_EQ(0x1234abcdU, thread_id); const MDRawExceptionStream* raw_exception = md_exception->exception(); - ASSERT_TRUE(raw_exception != NULL); + ASSERT_TRUE(raw_exception != nullptr); EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, raw_exception->exception_record.exception_address); MinidumpContext* md_context = md_exception->GetContext(); - ASSERT_TRUE(md_context != NULL); + ASSERT_TRUE(md_context != nullptr); ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU()); const MDRawContextARM* md_raw_context = md_context->GetContextARM(); - ASSERT_TRUE(md_raw_context != NULL); + ASSERT_TRUE(md_raw_context != nullptr); ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER, (md_raw_context->context_flags & MD_CONTEXT_ARM_INTEGER)); @@ -1571,24 +1611,24 @@ TEST(Dump, OneExceptionMIPS) { ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); MinidumpException* md_exception = minidump.GetException(); - ASSERT_TRUE(md_exception != NULL); + ASSERT_TRUE(md_exception != nullptr); uint32_t thread_id; ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); ASSERT_EQ(0x1234abcdU, thread_id); const MDRawExceptionStream* raw_exception = md_exception->exception(); - ASSERT_TRUE(raw_exception != NULL); + ASSERT_TRUE(raw_exception != nullptr); EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); EXPECT_EQ(0x0919a9b9U, raw_exception->exception_record.exception_address); MinidumpContext* md_context = md_exception->GetContext(); - ASSERT_TRUE(md_context != NULL); + ASSERT_TRUE(md_context != nullptr); ASSERT_EQ((uint32_t) MD_CONTEXT_MIPS, md_context->GetContextCPU()); const MDRawContextMIPS* md_raw_context = md_context->GetContextMIPS(); - ASSERT_TRUE(md_raw_context != NULL); + ASSERT_TRUE(md_raw_context != nullptr); ASSERT_EQ((uint32_t) MD_CONTEXT_MIPS_INTEGER, (md_raw_context->context_flags & MD_CONTEXT_MIPS_INTEGER)); EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]); diff --git a/src/processor/module_comparer.cc b/src/processor/module_comparer.cc index 669f11335..ccc2e4724 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. // @@ -32,9 +31,14 @@ // // Author: lambxsy@google.com (Siyang Xie) +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "processor/module_comparer.h" #include +#include #include #include "common/scoped_ptr.h" @@ -53,8 +57,8 @@ namespace google_breakpad { bool ModuleComparer::Compare(const string& symbol_data) { - scoped_ptr basic_module(new BasicModule("test_module")); - scoped_ptr fast_module(new FastModule("test_module")); + std::unique_ptr basic_module(new BasicModule("test_module")); + std::unique_ptr fast_module(new FastModule("test_module")); // Load symbol data into basic_module scoped_array buffer(new char[symbol_data.size() + 1]); @@ -65,7 +69,7 @@ bool ModuleComparer::Compare(const string& symbol_data) { buffer.reset(); // Serialize BasicSourceLineResolver::Module. - unsigned int serialized_size = 0; + size_t serialized_size = 0; scoped_array serialized_data( serializer_.Serialize(*(basic_module.get()), &serialized_size)); ASSERT_TRUE(serialized_data.get()); diff --git a/src/processor/module_comparer.h b/src/processor/module_comparer.h index 3691081d0..6bd3e7b8a 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. // diff --git a/src/processor/module_factory.h b/src/processor/module_factory.h index c6465f42d..3df85a60c 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. // diff --git a/src/processor/module_serializer.cc b/src/processor/module_serializer.cc index 04cadc80d..ba374ce97 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. // @@ -33,20 +32,41 @@ // // Author: Siyang Xie (lambxsy@google.com) +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "processor/module_serializer.h" +#include +#include + #include +#include #include +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/fast_source_line_resolver.h" #include "processor/basic_code_module.h" +#include "processor/linked_ptr.h" #include "processor/logging.h" +#include "processor/map_serializers.h" +#include "processor/simple_serializer.h" +#include "processor/windows_frame_info.h" namespace google_breakpad { -// Definition of static member variable in SimplerSerializer, which -// is declared in file "simple_serializer-inl.h" -RangeMapSerializer< MemAddr, linked_ptr > -SimpleSerializer::range_map_serializer_; +// Definition of static member variables in SimplerSerializer and +// SimplerSerializer, which are declared in file +// "simple_serializer-inl.h" +RangeMapSerializer> + SimpleSerializer::range_map_serializer_; +ContainedRangeMapSerializer> + SimpleSerializer< + BasicSourceLineResolver::Function>::inline_range_map_serializer_; size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module& module) { size_t total_size_alloc_ = 0; @@ -66,9 +86,11 @@ 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); + total_size_alloc_ += kNumberMaps_ * sizeof(uint64_t); for (int i = 0; i < kNumberMaps_; ++i) { total_size_alloc_ += map_sizes_[i]; @@ -85,8 +107,8 @@ char* ModuleSerializer::Write(const BasicSourceLineResolver::Module& module, // Write the is_corrupt flag. dest = SimpleSerializer::Write(module.is_corrupt_, dest); // Write header. - memcpy(dest, map_sizes_, kNumberMaps_ * sizeof(uint32_t)); - dest += kNumberMaps_ * sizeof(uint32_t); + memcpy(dest, map_sizes_, kNumberMaps_ * sizeof(uint64_t)); + dest += kNumberMaps_ * sizeof(uint64_t); // Write each map. dest = files_serializer_.Write(module.files_, dest); dest = functions_serializer_.Write(module.functions_, dest); @@ -95,15 +117,16 @@ 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::Write(0, dest); return dest; } -char* ModuleSerializer::Serialize( - const BasicSourceLineResolver::Module& module, unsigned int* size) { +char* ModuleSerializer::Serialize(const BasicSourceLineResolver::Module& module, + size_t* size) { // Compute size of memory to allocate. - unsigned int size_to_alloc = SizeOf(module); + const size_t size_to_alloc = SizeOf(module); // Allocate memory for serialized data. char* serialized_data = new char[size_to_alloc]; @@ -111,14 +134,14 @@ char* ModuleSerializer::Serialize( BPLOG(ERROR) << "ModuleSerializer: memory allocation failed, " << "size to alloc: " << size_to_alloc; if (size) *size = 0; - return NULL; + return nullptr; } // Write serialized data to allocated memory chunk. 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(end_address - serialized_data); + const size_t size_written = + static_cast(end_address - serialized_data); if (size_to_alloc != size_written) { BPLOG(ERROR) << "size_to_alloc differs from size_written: " << size_to_alloc << " vs " << size_written; @@ -127,6 +150,7 @@ char* ModuleSerializer::Serialize( // Set size and return the start address of memory chunk. if (size) *size = size_to_alloc; + return serialized_data; } @@ -139,7 +163,7 @@ bool ModuleSerializer::SerializeModuleAndLoadIntoFastResolver( BasicSourceLineResolver::Module* basic_module = dynamic_cast(iter->second); - unsigned int size = 0; + size_t size = 0; scoped_array symbol_data(Serialize(*basic_module, &size)); if (!symbol_data.get()) { BPLOG(ERROR) << "Serialization failed for module: " << basic_module->name_; @@ -149,11 +173,11 @@ bool ModuleSerializer::SerializeModuleAndLoadIntoFastResolver( // Copy the data into string. // Must pass string to LoadModuleUsingMapBuffer(), instead of passing char* to - // LoadModuleUsingMemoryBuffer(), becaused of data ownership/lifetime issue. + // LoadModuleUsingMemoryBuffer(), because of data ownership/lifetime issue. string symbol_data_string(symbol_data.get(), size); symbol_data.reset(); - scoped_ptr code_module( + std::unique_ptr code_module( new BasicCodeModule(0, 0, iter->first, "", "", "", "")); return fast_resolver->LoadModuleUsingMapBuffer(code_module.get(), @@ -190,18 +214,18 @@ bool ModuleSerializer::ConvertOneModule( return SerializeModuleAndLoadIntoFastResolver(iter, fast_resolver); } -char* ModuleSerializer::SerializeSymbolFileData( - const string& symbol_data, unsigned int* size) { - scoped_ptr module( +char* ModuleSerializer::SerializeSymbolFileData(const string& symbol_data, + size_t* size) { + std::unique_ptr module( new BasicSourceLineResolver::Module("no name")); scoped_array buffer(new char[symbol_data.size() + 1]); memcpy(buffer.get(), symbol_data.c_str(), symbol_data.size()); buffer.get()[symbol_data.size()] = '\0'; if (!module->LoadMapFromMemory(buffer.get(), symbol_data.size() + 1)) { - return NULL; + return nullptr; } - buffer.reset(NULL); - return Serialize(*(module.get()), size); + buffer.reset(nullptr); + return Serialize(*module, size); } } // namespace google_breakpad diff --git a/src/processor/module_serializer.h b/src/processor/module_serializer.h index 932ac3d76..eefe2857d 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. // @@ -37,6 +36,8 @@ #ifndef PROCESSOR_MODULE_SERIALIZER_H__ #define PROCESSOR_MODULE_SERIALIZER_H__ +#include + #include #include @@ -73,13 +74,13 @@ class ModuleSerializer { // 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); + size_t* size = nullptr); // 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); + size_t* size = nullptr); // Serializes one loaded module with given moduleid in the basic source line // resolver, and loads the serialized data into the fast source line resolver. @@ -99,6 +100,7 @@ class ModuleSerializer { 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( @@ -110,7 +112,7 @@ class ModuleSerializer { FastSourceLineResolver::Module::kNumberMaps_; // Memory sizes required to serialize map components in Module. - uint32_t map_sizes_[kNumberMaps_]; + uint64_t map_sizes_[kNumberMaps_]; // Serializers for each individual map component in Module class. StdMapSerializer files_serializer_; @@ -120,6 +122,7 @@ class ModuleSerializer { linked_ptr > wfi_serializer_; RangeMapSerializer cfi_init_rules_serializer_; StdMapSerializer cfi_delta_rules_serializer_; + StdMapSerializer> inline_origin_serializer_; }; } // namespace google_breakpad diff --git a/src/processor/pathname_stripper.cc b/src/processor/pathname_stripper.cc index c425b46a1..11dc6974e 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. // @@ -33,6 +32,10 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "processor/pathname_stripper.h" namespace google_breakpad { diff --git a/src/processor/pathname_stripper.h b/src/processor/pathname_stripper.h index fdf15e03b..62c9bdddc 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. // diff --git a/src/processor/pathname_stripper_unittest.cc b/src/processor/pathname_stripper_unittest.cc index 61f74fa5e..c5c39cc80 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. // @@ -27,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "processor/pathname_stripper.h" diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evaluator-inl.h index f567b1c8d..61e044e81 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. // @@ -176,7 +175,7 @@ bool PostfixEvaluator::EvaluateToken( // The identifier must name a variable, not a constant. Variables // begin with '$'. string identifier; - if (PopValueOrIdentifier(NULL, &identifier) != POP_RESULT_IDENTIFIER) { + if (PopValueOrIdentifier(nullptr, &identifier) != POP_RESULT_IDENTIFIER) { BPLOG(ERROR) << "PopValueOrIdentifier returned a value, but an " "identifier is needed to assign " << HexString(value) << ": " << expression; @@ -255,7 +254,7 @@ bool PostfixEvaluator::EvaluateForValue(const string& expression, // Ensure that the stack is cleared before returning. AutoStackClearer clearer(&stack_); - if (!EvaluateInternal(expression, NULL)) + if (!EvaluateInternal(expression, nullptr)) return false; // A successful execution should leave exactly one value on the stack. diff --git a/src/processor/postfix_evaluator.h b/src/processor/postfix_evaluator.h index d847a9b16..b6f718ab0 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. // diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix_evaluator_unittest.cc index 5a01584a0..969ed0ca4 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. // @@ -31,6 +30,10 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -222,7 +225,7 @@ static bool RunTests() { FakeMemoryRegion fake_memory; PostfixEvaluator postfix_evaluator = - PostfixEvaluator(NULL, &fake_memory); + PostfixEvaluator(nullptr, &fake_memory); for (unsigned int evaluate_test_set_index = 0; evaluate_test_set_index < evaluate_test_set_count; diff --git a/src/processor/proc_maps_linux.cc b/src/processor/proc_maps_linux.cc index 3c0dea25d..2ab6da225 100644 --- a/src/processor/proc_maps_linux.cc +++ b/src/processor/proc_maps_linux.cc @@ -1,9 +1,14 @@ -// 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. +// For PRI* macros, before anything else might #include it. #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS +#endif /* __STDC_FORMAT_MACROS */ + +#ifdef HAVE_CONFIG_H +#include // Must come first #endif #include "google_breakpad/processor/proc_maps_linux.h" @@ -12,6 +17,8 @@ #include #include +#include + #include "common/using_std_string.h" #include "processor/logging.h" @@ -94,7 +101,7 @@ bool ParseProcMaps(const string& input, return false; // Pushing then assigning saves us a string copy. - regions.push_back(region); + regions.push_back(std::move(region)); regions.back().path.assign(line + path_index); regions.back().line.assign(line); } diff --git a/src/processor/proc_maps_linux_unittest.cc b/src/processor/proc_maps_linux_unittest.cc index 466f23455..3d683cad7 100644 --- a/src/processor/proc_maps_linux_unittest.cc +++ b/src/processor/proc_maps_linux_unittest.cc @@ -1,7 +1,11 @@ -// 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. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "common/using_std_string.h" #include "google_breakpad/processor/proc_maps_linux.h" diff --git a/src/processor/process_state.cc b/src/processor/process_state.cc index c9269e418..03121cb67 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. // @@ -33,6 +32,10 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/process_state.h" #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/code_modules.h" @@ -51,6 +54,7 @@ void ProcessState::Clear() { crash_address_ = 0; assertion_.clear(); requesting_thread_ = -1; + original_thread_count_ = 0; for (vector::const_iterator iterator = threads_.begin(); iterator != threads_.end(); ++iterator) { @@ -58,14 +62,15 @@ void ProcessState::Clear() { } 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(); modules_with_corrupt_symbols_.clear(); delete modules_; - modules_ = NULL; + modules_ = nullptr; delete unloaded_modules_; - unloaded_modules_ = NULL; + unloaded_modules_ = nullptr; } } // namespace google_breakpad diff --git a/src/processor/processor.gyp b/src/processor/processor.gyp deleted file mode 100644 index 93896c0e9..000000000 --- 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 ecb450d60..000000000 --- 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 d3e02dc3f..f6b5fb4fe 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 6bfc72554..e38fe50a7 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 +#include "common/safe_math.h" #include "processor/range_map.h" #include "processor/linked_ptr.h" #include "processor/logging.h" @@ -57,10 +57,15 @@ template bool RangeMap::StoreRangeInternal( const AddressType& base, const AddressType& delta, const AddressType& size, const EntryType& entry) { - AddressType high = base + (size - 1); - + AddressType high = AddressType(); + bool high_ok = false; + if (size > 0) { + std::pair 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. @@ -245,7 +250,7 @@ bool RangeMap::RetrieveNearestRange( template bool RangeMap::RetrieveRangeAtIndex( - int index, EntryType* entry, AddressType* entry_base, + int64_t index, EntryType* entry, AddressType* entry_base, AddressType* entry_delta, AddressType* entry_size) const { BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveRangeAtIndex requires |entry|"; assert(entry); @@ -258,7 +263,7 @@ bool RangeMap::RetrieveRangeAtIndex( // Walk through the map. Although it's ordered, it's not a vector, so it // can't be addressed directly by index. MapConstIterator iterator = map_.begin(); - for (int this_index = 0; this_index < index; ++this_index) + for (int64_t this_index = 0; this_index < index; ++this_index) ++iterator; *entry = iterator->second.entry(); @@ -274,8 +279,8 @@ bool RangeMap::RetrieveRangeAtIndex( template -int RangeMap::GetCount() const { - return static_cast(map_.size()); +int64_t RangeMap::GetCount() const { + return static_cast(map_.size()); } diff --git a/src/processor/range_map.h b/src/processor/range_map.h index baea91cf4..05c659758 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. // @@ -41,6 +40,7 @@ #define PROCESSOR_RANGE_MAP_H__ +#include #include @@ -110,12 +110,12 @@ 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, + bool RetrieveRangeAtIndex(int64_t 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; + int64_t GetCount() const; // Empties the range map, restoring it to the state it was when it was // initially created. diff --git a/src/processor/range_map_truncate_lower_unittest.cc b/src/processor/range_map_truncate_lower_unittest.cc index a933c956f..b3599fc50 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,11 @@ // 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif #include #include diff --git a/src/processor/range_map_truncate_upper_unittest.cc b/src/processor/range_map_truncate_upper_unittest.cc index 7e3034f2f..aa058ad46 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,13 +24,17 @@ // 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. // // Author: Ivan Penkov +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include diff --git a/src/processor/range_map_unittest.cc b/src/processor/range_map_unittest.cc index 0f1c71319..a4634cc0e 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. // @@ -31,24 +30,32 @@ // // Author: Mark Mentovai +// For PRI* macros, before anything else might #include it. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif /* __STDC_FORMAT_MACROS */ +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include #include #include +#include + #include "processor/range_map-inl.h" -#include "common/scoped_ptr.h" #include "processor/linked_ptr.h" #include "processor/logging.h" namespace { - +using google_breakpad::AddIgnoringOverflow; using google_breakpad::linked_ptr; -using google_breakpad::scoped_ptr; using google_breakpad::RangeMap; - // A CountedObject holds an int. A global (not thread safe!) count of // allocated CountedObjects is maintained to help test memory management. class CountedObject { @@ -148,10 +155,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) { @@ -272,14 +279,15 @@ static bool RetrieveTest(TestMap* range_map, const RangeTest* range_test) { // false if the test fails. static bool RetrieveIndexTest(TestMap* range_map, int set) { linked_ptr object; - CountedObject* last_object = NULL; + CountedObject* last_object = nullptr; AddressType last_base = 0; int object_count = range_map->GetCount(); for (int object_index = 0; object_index < object_count; ++object_index) { AddressType base; if (!range_map->RetrieveRangeAtIndex(object_index, &object, &base, - NULL /* delta */, NULL /* size */)) { + nullptr /* delta */, + nullptr /* size */)) { fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d, " "expected success, observed failure\n", set, object_index); @@ -288,7 +296,7 @@ static bool RetrieveIndexTest(TestMap* range_map, int set) { if (!object.get()) { fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d, " - "expected object, observed NULL\n", + "expected object, observed nullptr\n", set, object_index); return false; } @@ -319,8 +327,9 @@ static bool RetrieveIndexTest(TestMap* range_map, int set) { // Make sure that RetrieveRangeAtIndex doesn't allow lookups at indices that // are too high. - if (range_map->RetrieveRangeAtIndex(object_count, &object, NULL /* base */, - NULL /* delta */, NULL /* size */)) { + if (range_map->RetrieveRangeAtIndex(object_count, &object, nullptr /* base */, + nullptr /* delta */, + nullptr /* size */)) { fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d (too large), " "expected failure, observed success\n", set, object_count); @@ -330,12 +339,12 @@ static bool RetrieveIndexTest(TestMap* range_map, int set) { return true; } -// Additional RetriveAtIndex test to expose the bug in RetrieveRangeAtIndex(). +// Additional RetrieveAtIndex test to expose the bug in RetrieveRangeAtIndex(). // Bug info: RetrieveRangeAtIndex() previously retrieves the high address of // entry, however, it is supposed to retrieve the base address of entry as // stated in the comment in range_map.h. -static bool RetriveAtIndexTest2() { - scoped_ptr range_map(new TestMap()); +static bool RetrieveAtIndexTest2() { + std::unique_ptr range_map(new TestMap()); // Store ranges with base address = 2 * object_id: const int range_size = 2; @@ -350,7 +359,8 @@ static bool RetriveAtIndexTest2() { for (int object_index = 0; object_index < object_count; ++object_index) { AddressType base; if (!range_map->RetrieveRangeAtIndex(object_index, &object, &base, - NULL /* delta */, NULL /* size */)) { + nullptr /* delta */, + nullptr /* size */)) { fprintf(stderr, "FAILED: RetrieveAtIndexTest2 index %d, " "expected success, observed failure\n", object_index); return false; @@ -358,7 +368,7 @@ static bool RetriveAtIndexTest2() { int expected_base = 2 * object->id(); if (base != expected_base) { - fprintf(stderr, "FAILED: RetriveAtIndexTest2 index %d, " + fprintf(stderr, "FAILED: RetrieveAtIndexTest2 index %d, " "expected base %d, observed base %d", object_index, expected_base, base); return false; @@ -461,7 +471,7 @@ static bool RunTests() { // Maintain the range map in a pointer so that deletion can be meaningfully // tested. - scoped_ptr range_map(new TestMap()); + std::unique_ptr range_map(new TestMap()); // Run all of the test sets in sequence. unsigned int range_test_set_count = sizeof(range_test_sets) / @@ -502,7 +512,7 @@ static bool RunTests() { // The RangeMap's own count of objects should also match. if (range_map->GetCount() != stored_count) { fprintf(stderr, "FAILED: stored object count doesn't match GetCount, " - "expected %d, observed %d\n", + "expected %d, observed %" PRId64 "\n", stored_count, range_map->GetCount()); return false; @@ -540,7 +550,7 @@ static bool RunTests() { } } - if (!RetriveAtIndexTest2()) { + if (!RetrieveAtIndexTest2()) { fprintf(stderr, "FAILED: did not pass RetrieveAtIndexTest2()\n"); return false; } diff --git a/src/processor/simple_serializer-inl.h b/src/processor/simple_serializer-inl.h index cb1a04081..d3c89b368 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,16 @@ #ifndef PROCESSOR_SIMPLE_SERIALIZER_INL_H__ #define PROCESSOR_SIMPLE_SERIALIZER_INL_H__ -#include - #include "processor/simple_serializer.h" -#include "map_serializers-inl.h" + +#include + +#include #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 { @@ -113,6 +114,25 @@ class SimpleSerializer { } }; +// Specializations of SimpleSerializer: InlineOrigin +template <> +class SimpleSerializer { + typedef BasicSourceLineResolver::InlineOrigin InlineOrigin; + + public: + static size_t SizeOf(const InlineOrigin& origin) { + return SimpleSerializer::SizeOf(origin.has_file_id) + + SimpleSerializer::SizeOf(origin.source_file_id) + + SimpleSerializer::SizeOf(origin.name); + } + static char* Write(const InlineOrigin& origin, char* dest) { + dest = SimpleSerializer::Write(origin.has_file_id, dest); + dest = SimpleSerializer::Write(origin.source_file_id, dest); + dest = SimpleSerializer::Write(origin.name, dest); + return dest; + } +}; + // Specializations of SimpleSerializer: PublicSymbol template<> class SimpleSerializer { @@ -121,12 +141,14 @@ class SimpleSerializer { static size_t SizeOf(const PublicSymbol& pubsymbol) { return SimpleSerializer::SizeOf(pubsymbol.name) + SimpleSerializer::SizeOf(pubsymbol.address) - + SimpleSerializer::SizeOf(pubsymbol.parameter_size); + + SimpleSerializer::SizeOf(pubsymbol.parameter_size) + + SimpleSerializer::SizeOf(pubsymbol.is_multiple); } static char* Write(const PublicSymbol& pubsymbol, char* dest) { dest = SimpleSerializer::Write(pubsymbol.name, dest); dest = SimpleSerializer::Write(pubsymbol.address, dest); dest = SimpleSerializer::Write(pubsymbol.parameter_size, dest); + dest = SimpleSerializer::Write(pubsymbol.is_multiple, dest); return dest; } }; @@ -165,13 +187,13 @@ class SimpleSerializer { }; // Specializations of SimpleSerializer: Linked_ptr version of -// Line, Function, PublicSymbol, WindowsFrameInfo. +// Line, InlineOrigin, Inline, Function, PublicSymbol, WindowsFrameInfo. template<> class SimpleSerializer< linked_ptr > { typedef BasicSourceLineResolver::Line Line; public: static size_t SizeOf(const linked_ptr& lineptr) { - if (lineptr.get() == NULL) return 0; + if (lineptr.get() == nullptr) return 0; return SimpleSerializer::SizeOf(*(lineptr.get())); } static char* Write(const linked_ptr& lineptr, char* dest) { @@ -181,11 +203,86 @@ class SimpleSerializer< linked_ptr > { } }; +template <> +class SimpleSerializer> { + typedef BasicSourceLineResolver::InlineOrigin InlineOrigin; + + public: + static size_t SizeOf(const linked_ptr& origin_ptr) { + if (origin_ptr.get() == nullptr) + return 0; + return SimpleSerializer::SizeOf(*(origin_ptr.get())); + } + static char* Write(const linked_ptr& origin_ptr, char* dest) { + if (origin_ptr.get()) + dest = SimpleSerializer::Write(*(origin_ptr.get()), dest); + return dest; + } +}; + +// Specializations of SimpleSerializer: Inline +template <> +class SimpleSerializer>; +template <> +class SimpleSerializer { + 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> { + typedef BasicSourceLineResolver::Inline Inline; + + public: + static size_t SizeOf(const linked_ptr& inline_ptr) { + if (inline_ptr.get() == nullptr) + return 0; + return SimpleSerializer::SizeOf(*(inline_ptr.get())); + } + static char* Write(const linked_ptr& inline_ptr, char* dest) { + if (inline_ptr.get()) + dest = SimpleSerializer::Write(*(inline_ptr.get()), dest); + return dest; + } +}; + +size_t SimpleSerializer::SizeOf( + const Inline& in) { + return SimpleSerializer::SizeOf(in.has_call_site_file_id) + + SimpleSerializer::SizeOf(in.inline_nest_level) + + SimpleSerializer::SizeOf(in.call_site_line) + + SimpleSerializer::SizeOf(in.call_site_file_id) + + SimpleSerializer::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::Write(const Inline& in, + char* dest) { + dest = SimpleSerializer::Write(in.has_call_site_file_id, dest); + dest = SimpleSerializer::Write(in.inline_nest_level, dest); + dest = SimpleSerializer::Write(in.call_site_line, dest); + dest = SimpleSerializer::Write(in.call_site_file_id, dest); + dest = SimpleSerializer::Write(in.origin_id, dest); + // Write the size of inline_ranges. + dest = SimpleSerializer::Write(in.inline_ranges.size(), dest); + for (const std::pair& range : in.inline_ranges) { + dest = SimpleSerializer::Write(range.first, dest); + dest = SimpleSerializer::Write(range.second, dest); + } + return dest; +} + template<> class SimpleSerializer { // Convenient type names. typedef BasicSourceLineResolver::Function Function; typedef BasicSourceLineResolver::Line Line; + typedef BasicSourceLineResolver::Inline Inline; + public: static size_t SizeOf(const Function& func) { unsigned int size = 0; @@ -193,6 +290,11 @@ class SimpleSerializer { size += SimpleSerializer::SizeOf(func.address); size += SimpleSerializer::SizeOf(func.size); size += SimpleSerializer::SizeOf(func.parameter_size); + size += SimpleSerializer::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; } @@ -202,12 +304,22 @@ class SimpleSerializer { dest = SimpleSerializer::Write(func.address, dest); dest = SimpleSerializer::Write(func.size, dest); dest = SimpleSerializer::Write(func.parameter_size, dest); + dest = SimpleSerializer::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::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 > range_map_serializer_; + static RangeMapSerializer> range_map_serializer_; + static ContainedRangeMapSerializer> + inline_range_map_serializer_; }; template<> @@ -231,7 +343,7 @@ class SimpleSerializer< linked_ptr > { typedef BasicSourceLineResolver::PublicSymbol PublicSymbol; public: static size_t SizeOf(const linked_ptr& pubsymbol) { - if (pubsymbol.get() == NULL) return 0; + if (pubsymbol.get() == nullptr) return 0; return SimpleSerializer::SizeOf(*(pubsymbol.get())); } static char* Write(const linked_ptr& pubsymbol, char* dest) { @@ -245,7 +357,7 @@ template<> class SimpleSerializer< linked_ptr > { public: static size_t SizeOf(const linked_ptr& wfi) { - if (wfi.get() == NULL) return 0; + if (wfi.get() == nullptr) return 0; return SimpleSerializer::SizeOf(*(wfi.get())); } static char* Write(const linked_ptr& wfi, char* dest) { diff --git a/src/processor/simple_serializer.h b/src/processor/simple_serializer.h index 9e51d8067..bd6cc84ce 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 + #include "google_breakpad/common/breakpad_types.h" namespace google_breakpad { diff --git a/src/processor/simple_symbol_supplier.cc b/src/processor/simple_symbol_supplier.cc index cdc3efbf9..f134d10f0 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. // @@ -33,6 +32,10 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "processor/simple_symbol_supplier.h" #include @@ -111,7 +114,7 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetCStringSymbolData( if (s == FOUND) { *symbol_data_size = symbol_data_string.size() + 1; *symbol_data = new char[*symbol_data_size]; - if (*symbol_data == NULL) { + if (*symbol_data == nullptr) { BPLOG(ERROR) << "Memory allocation for size " << *symbol_data_size << " failed"; return INTERRUPT; diff --git a/src/processor/simple_symbol_supplier.h b/src/processor/simple_symbol_supplier.h index 3a65c7e60..3302bab63 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. // diff --git a/src/processor/source_line_resolver_base.cc b/src/processor/source_line_resolver_base.cc index 45a06cf3c..817ac8a01 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. // @@ -34,6 +33,10 @@ // // Author: Siyang Xie (lambxsy@google.com) +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -42,10 +45,10 @@ #include #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 { @@ -67,11 +70,11 @@ SourceLineResolverBase::~SourceLineResolverBase() { } // Delete the map of modules. delete modules_; - modules_ = NULL; + modules_ = nullptr; // Delete the set of corrupt modules. delete corrupt_modules_; - corrupt_modules_ = NULL; + corrupt_modules_ = nullptr; MemoryMap::iterator iter = memory_buffers_->begin(); for (; iter != memory_buffers_->end(); ++iter) { @@ -79,16 +82,16 @@ SourceLineResolverBase::~SourceLineResolverBase() { } // Delete the map of memory buffers. delete memory_buffers_; - memory_buffers_ = NULL; + memory_buffers_ = nullptr; delete module_factory_; - module_factory_ = NULL; + module_factory_ = nullptr; } bool SourceLineResolverBase::ReadSymbolFile(const string& map_file, char** symbol_data, size_t* symbol_data_size) { - if (symbol_data == NULL || symbol_data_size == NULL) { + if (symbol_data == nullptr || symbol_data_size == nullptr) { BPLOG(ERROR) << "Could not Read file into Null memory pointer"; return false; } @@ -110,7 +113,7 @@ bool SourceLineResolverBase::ReadSymbolFile(const string& map_file, *symbol_data_size = file_size + 1; *symbol_data = new char[file_size + 1]; - if (*symbol_data == NULL) { + if (*symbol_data == nullptr) { BPLOG(ERROR) << "Could not allocate memory for " << map_file; return false; } @@ -124,7 +127,7 @@ bool SourceLineResolverBase::ReadSymbolFile(const string& map_file, BPLOG(ERROR) << "Could not open " << map_file << ", error " << error_code << ": " << error_string; delete [] (*symbol_data); - *symbol_data = NULL; + *symbol_data = nullptr; return false; } @@ -140,7 +143,7 @@ bool SourceLineResolverBase::ReadSymbolFile(const string& map_file, BPLOG(ERROR) << "Could not slurp " << map_file << ", error " << error_code << ": " << error_string; delete [] (*symbol_data); - *symbol_data = NULL; + *symbol_data = nullptr; return false; } @@ -150,7 +153,7 @@ bool SourceLineResolverBase::ReadSymbolFile(const string& map_file, bool SourceLineResolverBase::LoadModule(const CodeModule* module, const string& map_file) { - if (module == NULL) + if (module == nullptr) return false; // Make sure we don't already have a module with the given name. @@ -168,7 +171,9 @@ bool SourceLineResolverBase::LoadModule(const CodeModule* module, 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); @@ -185,7 +190,10 @@ bool SourceLineResolverBase::LoadModule(const CodeModule* module, bool SourceLineResolverBase::LoadModuleUsingMapBuffer( const CodeModule* module, const string& map_buffer) { - if (module == NULL) + BPLOG(INFO) << "SourceLineResolverBase::LoadModuleUsingMapBuffer(module = " + << module->code_file() + << ", map_buffer.size() = " << map_buffer.size() << ")"; + if (module == nullptr) return false; // Make sure we don't already have a module with the given name. @@ -197,7 +205,7 @@ bool SourceLineResolverBase::LoadModuleUsingMapBuffer( size_t memory_buffer_size = map_buffer.size() + 1; char* memory_buffer = new char[memory_buffer_size]; - if (memory_buffer == NULL) { + if (memory_buffer == nullptr) { BPLOG(ERROR) << "Could not allocate memory for " << module->code_file(); return false; } @@ -234,7 +242,7 @@ 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()); @@ -245,7 +253,6 @@ bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer( // Returning false from here would be an indication that the symbols for // this module are missing which would be wrong. Intentionally fall through // and add the module to both the modules_ and the corrupt_modules_ lists. - assert(basic_module->IsCorrupt()); } modules_->insert(make_pair(module->code_file(), basic_module)); @@ -295,11 +302,13 @@ bool SourceLineResolverBase::IsModuleCorrupt(const CodeModule* module) { return corrupt_modules_->find(module->code_file()) != corrupt_modules_->end(); } -void SourceLineResolverBase::FillSourceLineInfo(StackFrame* frame) { +void SourceLineResolverBase::FillSourceLineInfo( + StackFrame* frame, + std::deque>* 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); } } } @@ -312,7 +321,7 @@ WindowsFrameInfo* SourceLineResolverBase::FindWindowsFrameInfo( return it->second->FindWindowsFrameInfo(frame); } } - return NULL; + return nullptr; } CFIFrameInfo* SourceLineResolverBase::FindCFIFrameInfo( @@ -323,7 +332,7 @@ CFIFrameInfo* SourceLineResolverBase::FindCFIFrameInfo( return it->second->FindCFIFrameInfo(frame); } } - return NULL; + return nullptr; } bool SourceLineResolverBase::CompareString::operator()( diff --git a/src/processor/source_line_resolver_base_types.h b/src/processor/source_line_resolver_base_types.h index db9f7b8e2..4b3b366cb 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 +#include #include +#include #include #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__ @@ -66,6 +69,43 @@ class SourceLineResolverBase::AutoFileCloser { 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>; + 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 { Line() { } Line(MemAddr addr, MemAddr code_size, int file_id, int source_line) @@ -142,7 +182,9 @@ 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>* inlined_frames) const = 0; // If Windows stack walking information is available covering ADDRESS, // return a WindowsFrameInfo structure describing it. If the information diff --git a/src/processor/stack_frame_cpu.cc b/src/processor/stack_frame_cpu.cc index 6175dc7f2..4a4a052cc 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. // @@ -33,6 +32,10 @@ // // Author: Colin Blundell +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/stack_frame_cpu.h" namespace google_breakpad { diff --git a/src/processor/stack_frame_symbolizer.cc b/src/processor/stack_frame_symbolizer.cc index 7a44f243c..f54653c26 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. // @@ -32,11 +31,14 @@ // line information in a stack frame, and also looks up WindowsFrameInfo or // CFIFrameInfo for a stack frame. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/stack_frame_symbolizer.h" #include -#include "common/scoped_ptr.h" #include "google_breakpad/processor/code_module.h" #include "google_breakpad/processor/code_modules.h" #include "google_breakpad/processor/source_line_resolver_interface.h" @@ -57,10 +59,11 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo( const CodeModules* modules, const CodeModules* unloaded_modules, const SystemInfo* system_info, - StackFrame* frame) { + StackFrame* frame, + std::deque>* inlined_frames) { assert(frame); - const CodeModule* module = NULL; + const CodeModule* module = nullptr; if (modules) { module = modules->GetModuleForAddress(frame->instruction); } @@ -80,7 +83,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; } @@ -92,7 +95,7 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo( // Start fetching symbol from supplier. string symbol_file; - char* symbol_data = NULL; + char* symbol_data = nullptr; size_t symbol_data_size; SymbolSupplier::SymbolResult symbol_result = supplier_->GetCStringSymbolData( module, system_info, &symbol_file, &symbol_data, &symbol_data_size); @@ -108,7 +111,7 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo( } if (load_success) { - resolver_->FillSourceLineInfo(frame); + resolver_->FillSourceLineInfo(frame, inlined_frames); return resolver_->IsModuleCorrupt(frame->module) ? kWarningCorruptSymbols : kNoError; } else { @@ -134,12 +137,12 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo( WindowsFrameInfo* StackFrameSymbolizer::FindWindowsFrameInfo( const StackFrame* frame) { - return resolver_ ? resolver_->FindWindowsFrameInfo(frame) : NULL; + return resolver_ ? resolver_->FindWindowsFrameInfo(frame) : nullptr; } CFIFrameInfo* StackFrameSymbolizer::FindCFIFrameInfo( const StackFrame* frame) { - return resolver_ ? resolver_->FindCFIFrameInfo(frame) : NULL; + return resolver_ ? resolver_->FindCFIFrameInfo(frame) : nullptr; } } // namespace google_breakpad diff --git a/src/processor/stackwalk_common.cc b/src/processor/stackwalk_common.cc index 904757205..809836151 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. // @@ -32,6 +31,10 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "processor/stackwalk_common.h" #include @@ -57,6 +60,7 @@ namespace google_breakpad { namespace { using std::vector; +using std::unique_ptr; // Separator character for machine readable output. static const char kOutputSeparator = '|'; @@ -149,7 +153,8 @@ static void PrintStackContents(const string& indent, const StackFrameARM* frame_arm = static_cast(frame); const StackFrameARM* prev_frame_arm = static_cast(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]; @@ -160,12 +165,39 @@ static void PrintStackContents(const string& indent, static_cast(frame); const StackFrameARM64* prev_frame_arm64 = static_cast(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(frame); + const StackFrameRISCV* prev_frame_riscv = + static_cast(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(frame); + const StackFrameRISCV64* prev_frame_riscv64 = + static_cast(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,27 +249,58 @@ static void PrintStackContents(const string& indent, modules->GetModuleForAddress(pointee_frame.instruction); // Try to look up the function name. + std::deque> 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(address), - static_cast(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(address), + static_cast(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); + } + }; + print_function_name(&pointee_frame); + for (unique_ptr &frame : inlined_frames) + print_function_name(frame.get()); + } + printf("\n"); +} + +static void PrintFrameHeader(const StackFrame* frame, int frame_index) { + printf("%2d ", frame_index); + + uint64_t instruction_address = frame->ReturnAddress(); + + if (frame->module) { + printf("%s", PathnameStripper::File(frame->module->code_file()).c_str()); + 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(" [%s : %d + 0x%" PRIx64 "]", source_file.c_str(), + frame->source_line, + instruction_address - frame->source_line_base); } else { - printf("%s *(0x%016" PRIx64 ") = 0x%016" PRIx64, - indent.c_str(), address, pointee_frame.instruction); + printf(" + 0x%" PRIx64, instruction_address - frame->function_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); + } else { + printf(" + 0x%" PRIx64, + instruction_address - frame->module->base_address()); } + } else { + printf("0x%" PRIx64, instruction_address); } - printf("\n"); } // PrintStack prints the call stack in |stack| to stdout, in a reasonably @@ -261,347 +324,618 @@ static void PrintStack(const CallStack* stack, } for (int frame_index = 0; frame_index < frame_count; ++frame_index) { const StackFrame* frame = stack->frames()->at(frame_index); - printf("%2d ", frame_index); - - uint64_t instruction_address = frame->ReturnAddress(); - - if (frame->module) { - printf("%s", PathnameStripper::File(frame->module->code_file()).c_str()); - 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(" [%s : %d + 0x%" PRIx64 "]", - source_file.c_str(), - frame->source_line, - instruction_address - frame->source_line_base); - } else { - printf(" + 0x%" PRIx64, instruction_address - frame->function_base); - } - } else { - printf(" + 0x%" PRIx64, - instruction_address - frame->module->base_address()); - } - } else { - printf("0x%" PRIx64, instruction_address); - } + PrintFrameHeader(frame, frame_index); printf("\n "); - int sequence = 0; - if (cpu == "x86") { - const StackFrameX86* frame_x86 = - reinterpret_cast(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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()); @@ -778,7 +1112,7 @@ static void PrintModulesMachineReadable(const CodeModules* modules) { kOutputSeparator, base_address, kOutputSeparator, base_address + module->size() - 1, kOutputSeparator, - main_module != NULL && base_address == main_address ? 1 : 0); + main_module != nullptr && base_address == main_address ? 1 : 0); } } @@ -786,6 +1120,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 +1191,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); + } } } @@ -947,4 +1284,21 @@ void PrintProcessStateMachineReadable(const ProcessState& process_state) { } } +void PrintRequestingThreadBrief(const ProcessState& process_state) { + int requesting_thread = process_state.requesting_thread(); + if (requesting_thread == -1) { + printf(" \n"); + return; + } + + printf("Thread %d (%s)\n", requesting_thread, + process_state.crashed() ? "crashed" : "requested dump, did not crash"); + const CallStack* stack = process_state.threads()->at(requesting_thread); + int frame_count = stack->frames()->size(); + for (int frame_index = 0; frame_index < frame_count; ++frame_index) { + PrintFrameHeader(stack->frames()->at(frame_index), frame_index); + printf("\n"); + } +} + } // namespace google_breakpad diff --git a/src/processor/stackwalk_common.h b/src/processor/stackwalk_common.h index a74f7b6da..3782f987b 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,7 +41,9 @@ 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); +void PrintRequestingThreadBrief(const ProcessState& process_state); } // namespace google_breakpad diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc index 4988ef1eb..e84845ec0 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. // @@ -33,11 +32,16 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/stackwalker.h" #include -#include "common/scoped_ptr.h" +#include + #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/code_module.h" #include "google_breakpad/processor/code_modules.h" @@ -55,6 +59,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 { @@ -77,7 +83,7 @@ Stackwalker::Stackwalker(const SystemInfo* system_info, : system_info_(system_info), memory_(memory), modules_(modules), - unloaded_modules_(NULL), + unloaded_modules_(nullptr), frame_symbolizer_(frame_symbolizer) { assert(frame_symbolizer_); } @@ -131,18 +137,19 @@ bool Stackwalker::Walk( uint32_t scanned_frames = 0; // Take ownership of the pointer returned by GetContextFrame. - scoped_ptr frame(GetContextFrame()); + std::unique_ptr frame(GetContextFrame()); while (frame.get()) { // frame already contains a good frame with properly set instruction and // frame_pointer fields. The frame structure comes from either the // context frame (above) or a caller frame (below). + std::deque> 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 +180,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()); @@ -203,10 +215,10 @@ Stackwalker* Stackwalker::StackwalkerForCPU( StackFrameSymbolizer* frame_symbolizer) { if (!context) { BPLOG(ERROR) << "Can't choose a stackwalker implementation without context"; - return NULL; + return nullptr; } - Stackwalker* cpu_stackwalker = NULL; + Stackwalker* cpu_stackwalker = nullptr; uint32_t cpu = context->GetContextCPU(); switch (cpu) { @@ -265,6 +277,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 +333,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 e81fec282..a4951ebc1 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. // @@ -33,6 +32,10 @@ // // Author: Chris Hamilton +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -51,40 +54,37 @@ StackwalkerAddressList::StackwalkerAddressList( size_t frame_count, const CodeModules* modules, StackFrameSymbolizer* frame_symbolizer) - : Stackwalker(NULL, NULL, modules, frame_symbolizer), + : Stackwalker(nullptr, nullptr, modules, frame_symbolizer), frames_(frames), - frame_count_(frame_count) { + frame_count_(frame_count), + next_frame_index_(0) { assert(frames); assert(frame_symbolizer); } StackFrame* StackwalkerAddressList::GetContextFrame() { if (frame_count_ == 0) - return NULL; + return nullptr; StackFrame* frame = new StackFrame(); frame->instruction = frames_[0]; frame->trust = StackFrame::FRAME_TRUST_PREWALKED; + + next_frame_index_ = 1; + return frame; } -StackFrame* StackwalkerAddressList::GetCallerFrame(const CallStack* stack, +StackFrame* StackwalkerAddressList::GetCallerFrame(const CallStack*, bool stack_scan_allowed) { - if (!stack) { - BPLOG(ERROR) << "Can't get caller frame without stack"; - return NULL; - } - - size_t frame_index = stack->frames()->size(); - // There are no more frames to fetch. - if (frame_index >= frame_count_) - return NULL; + if (next_frame_index_ >= frame_count_) + return nullptr; // All frames have the highest level of trust because they were // explicitly provided. StackFrame* frame = new StackFrame(); - frame->instruction = frames_[frame_index]; + frame->instruction = frames_[next_frame_index_++]; frame->trust = StackFrame::FRAME_TRUST_PREWALKED; return frame; } diff --git a/src/processor/stackwalker_address_list.h b/src/processor/stackwalker_address_list.h index 0f8c989ef..b024d2ca6 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. // @@ -37,7 +36,6 @@ #ifndef PROCESSOR_STACKWALKER_ADDRESS_LIST_H_ #define PROCESSOR_STACKWALKER_ADDRESS_LIST_H_ -#include "common/basictypes.h" #include "google_breakpad/common/breakpad_types.h" #include "google_breakpad/processor/stackwalker.h" @@ -54,6 +52,8 @@ class StackwalkerAddressList : public Stackwalker { size_t frame_count, const CodeModules* modules, StackFrameSymbolizer* frame_symbolizer); + StackwalkerAddressList(const StackwalkerAddressList&) = delete; + void operator=(const StackwalkerAddressList&) = delete; private: // Implementation of Stackwalker. @@ -63,8 +63,7 @@ class StackwalkerAddressList : public Stackwalker { const uint64_t* frames_; size_t frame_count_; - - DISALLOW_COPY_AND_ASSIGN(StackwalkerAddressList); + size_t next_frame_index_; }; } // namespace google_breakpad diff --git a/src/processor/stackwalker_address_list_unittest.cc b/src/processor/stackwalker_address_list_unittest.cc index 2828dff21..1da0b17b2 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. // @@ -32,6 +31,10 @@ // // Author: Chris Hamilton +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -98,24 +101,38 @@ class StackwalkerAddressListTest : public testing::Test { void SetModuleSymbols(MockCodeModule* module, const string& info) { size_t buffer_size; char* buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); - EXPECT_CALL(supplier, GetCStringSymbolData(module, NULL, _, _, _)) + EXPECT_CALL(supplier, GetCStringSymbolData(module, nullptr, _, _, _)) .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), SetArgumentPointee<4>(buffer_size), Return(MockSymbolSupplier::FOUND))); } - void CheckCallStack(const CallStack& call_stack) { + void CheckCallStack(const CallStack& call_stack, bool allow_inline=false) { const std::vector* frames = call_stack.frames(); - ASSERT_EQ(arraysize(kDummyFrames), frames->size()); - for (size_t i = 0; i < arraysize(kDummyFrames); ++i) { - ASSERT_EQ(kDummyFrames[i], frames->at(i)->instruction); - ASSERT_EQ(StackFrame::FRAME_TRUST_PREWALKED, frames->at(i)->trust); + ASSERT_LE(arraysize(kDummyFrames), frames->size()); + + // Iterate through the produced stack frames, validating that all of the + // prewalked frames match the expected input frames. Inlined frames are only + // allowed if `allow_inline` is set to true. + + size_t j = 0; + for (size_t i = 0; i < frames->size(); ++i) { + if (j <= 2) { + ASSERT_EQ(static_cast(&module2), frames->at(i)->module); + } else { + ASSERT_EQ(static_cast(&module1), frames->at(i)->module); + } + + ASSERT_EQ(kDummyFrames[j], frames->at(i)->instruction); + if (frames->at(i)->trust == StackFrame::FRAME_TRUST_PREWALKED) { + // Only move on to the next "real" stack frame if this isn't an + // inlined stack frame. + ++j; + } else { + ASSERT_TRUE(allow_inline); + ASSERT_EQ(StackFrame::FRAME_TRUST_INLINE, frames->at(i)->trust); + } } - ASSERT_EQ(static_cast(&module2), frames->at(0)->module); - ASSERT_EQ(static_cast(&module2), frames->at(1)->module); - ASSERT_EQ(static_cast(&module2), frames->at(2)->module); - ASSERT_EQ(static_cast(&module1), frames->at(3)->module); - ASSERT_EQ(static_cast(&module1), frames->at(4)->module); } MockCodeModule module1; @@ -196,3 +213,80 @@ TEST_F(StackwalkerAddressListTest, ScanWithSymbols) { ASSERT_EQ("mod1func1", frames->at(4)->function_name); ASSERT_EQ(0x40001000u, frames->at(4)->function_base); } + +TEST_F(StackwalkerAddressListTest, ScanWithInlining) { + // File : FILE number(dex) name + // Function: FUNC address(hex) size(hex) parameter_size(hex) name + // Inline: : INLINE_ORIGIN number(dec) name + // : INLINE depth(dec) line(dec) filenum(dec) inlinenum(dec) + // address(hex) size(hex) + // Line : address(hex) size(hex) line(dec) filenum(dec) + SetModuleSymbols(&module2, + "FILE 1 module2.cc\n" + "INLINE_ORIGIN 0 mod2inlinefunc1\n" + "INLINE_ORIGIN 1 mod2inlinefunc2\n" + "INLINE_ORIGIN 2 mod2inlinefunc3\n" + "FUNC 3000 100 10 mod2func3\n" + "INLINE 0 1 1 1 3000 10\n" + "INLINE 1 1 1 2 3000 10\n" + "3000 10 1 1\n" + "FUNC 2000 200 10 mod2func2\n" + "INLINE 0 1 1 0 2000 10\n" + "FUNC 1000 300 10 mod2func1\n"); + SetModuleSymbols(&module1, + "FUNC 2000 200 10 mod1func2\n" + "FUNC 1000 300 10 mod1func1\n"); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAddressList walker(kDummyFrames, arraysize(kDummyFrames), + &modules, &frame_symbolizer); + + CallStack call_stack; + vector modules_without_symbols; + vector 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()); + + ASSERT_NO_FATAL_FAILURE(CheckCallStack(call_stack, /*allow_inline=*/true)); + + const std::vector* frames = call_stack.frames(); + + // We have full file/line information for the first function call, including + // inline functions + ASSERT_EQ("mod2inlinefunc3", frames->at(0)->function_name); + ASSERT_EQ(0x50003000u, frames->at(0)->function_base); + ASSERT_EQ("module2.cc", frames->at(0)->source_file_name); + ASSERT_EQ(1, frames->at(0)->source_line); + ASSERT_EQ(0x50003000u, frames->at(0)->source_line_base); + + ASSERT_EQ("mod2inlinefunc2", frames->at(1)->function_name); + ASSERT_EQ(0x50003000u, frames->at(1)->function_base); + ASSERT_EQ("module2.cc", frames->at(1)->source_file_name); + ASSERT_EQ(1, frames->at(1)->source_line); + ASSERT_EQ(0x50003000u, frames->at(1)->source_line_base); + + ASSERT_EQ("mod2func3", frames->at(2)->function_name); + ASSERT_EQ(0x50003000u, frames->at(2)->function_base); + ASSERT_EQ("module2.cc", frames->at(2)->source_file_name); + ASSERT_EQ(1, frames->at(2)->source_line); + ASSERT_EQ(0x50003000u, frames->at(2)->source_line_base); + + // Here we have inlining information, but no file/line information. + ASSERT_EQ("mod2inlinefunc1", frames->at(3)->function_name); + ASSERT_EQ(0x50002000u, frames->at(3)->function_base); + + ASSERT_EQ("mod2func2", frames->at(4)->function_name); + ASSERT_EQ(0x50002000u, frames->at(4)->function_base); + + ASSERT_EQ("mod2func1", frames->at(5)->function_name); + ASSERT_EQ(0x50001000u, frames->at(5)->function_base); + + ASSERT_EQ("mod1func2", frames->at(6)->function_name); + ASSERT_EQ(0x40002000u, frames->at(6)->function_base); + + ASSERT_EQ("mod1func1", frames->at(7)->function_name); + ASSERT_EQ(0x40001000u, frames->at(7)->function_base); +} diff --git a/src/processor/stackwalker_amd64.cc b/src/processor/stackwalker_amd64.cc index f346a4eee..5a397fce5 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. // @@ -33,9 +32,14 @@ // // Author: Mark Mentovai, Ted Mielczarek +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include -#include "common/scoped_ptr.h" +#include + #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/memory_region.h" #include "google_breakpad/processor/source_line_resolver_interface.h" @@ -55,37 +59,37 @@ StackwalkerAMD64::cfi_register_map_[] = { // flags here really means that the walker should assume they're // unchanged if the CFI doesn't mention them --- clearly wrong for $rip // and $rsp. - { "$rax", NULL, false, + { "$rax", nullptr, false, StackFrameAMD64::CONTEXT_VALID_RAX, &MDRawContextAMD64::rax }, - { "$rdx", NULL, false, + { "$rdx", nullptr, false, StackFrameAMD64::CONTEXT_VALID_RDX, &MDRawContextAMD64::rdx }, - { "$rcx", NULL, false, + { "$rcx", nullptr, false, StackFrameAMD64::CONTEXT_VALID_RCX, &MDRawContextAMD64::rcx }, - { "$rbx", NULL, true, + { "$rbx", nullptr, true, StackFrameAMD64::CONTEXT_VALID_RBX, &MDRawContextAMD64::rbx }, - { "$rsi", NULL, false, + { "$rsi", nullptr, false, StackFrameAMD64::CONTEXT_VALID_RSI, &MDRawContextAMD64::rsi }, - { "$rdi", NULL, false, + { "$rdi", nullptr, false, StackFrameAMD64::CONTEXT_VALID_RDI, &MDRawContextAMD64::rdi }, - { "$rbp", NULL, true, + { "$rbp", nullptr, true, StackFrameAMD64::CONTEXT_VALID_RBP, &MDRawContextAMD64::rbp }, { "$rsp", ".cfa", false, StackFrameAMD64::CONTEXT_VALID_RSP, &MDRawContextAMD64::rsp }, - { "$r8", NULL, false, + { "$r8", nullptr, false, StackFrameAMD64::CONTEXT_VALID_R8, &MDRawContextAMD64::r8 }, - { "$r9", NULL, false, + { "$r9", nullptr, false, StackFrameAMD64::CONTEXT_VALID_R9, &MDRawContextAMD64::r9 }, - { "$r10", NULL, false, + { "$r10", nullptr, false, StackFrameAMD64::CONTEXT_VALID_R10, &MDRawContextAMD64::r10 }, - { "$r11", NULL, false, + { "$r11", nullptr, false, StackFrameAMD64::CONTEXT_VALID_R11, &MDRawContextAMD64::r11 }, - { "$r12", NULL, true, + { "$r12", nullptr, true, StackFrameAMD64::CONTEXT_VALID_R12, &MDRawContextAMD64::r12 }, - { "$r13", NULL, true, + { "$r13", nullptr, true, StackFrameAMD64::CONTEXT_VALID_R13, &MDRawContextAMD64::r13 }, - { "$r14", NULL, true, + { "$r14", nullptr, true, StackFrameAMD64::CONTEXT_VALID_R14, &MDRawContextAMD64::r14 }, - { "$r15", NULL, true, + { "$r15", nullptr, true, StackFrameAMD64::CONTEXT_VALID_R15, &MDRawContextAMD64::r15 }, { "$rip", ".ra", false, StackFrameAMD64::CONTEXT_VALID_RIP, &MDRawContextAMD64::rip }, @@ -110,7 +114,7 @@ uint64_t StackFrameAMD64::ReturnAddress() const { StackFrame* StackwalkerAMD64::GetContextFrame() { if (!context_) { BPLOG(ERROR) << "Can't get context frame without context"; - return NULL; + return nullptr; } StackFrameAMD64* frame = new StackFrameAMD64(); @@ -130,22 +134,21 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByCFIFrameInfo( CFIFrameInfo* cfi_frame_info) { StackFrameAMD64* last_frame = static_cast(frames.back()); - scoped_ptr frame(new StackFrameAMD64()); + std::unique_ptr frame(new StackFrameAMD64()); if (!cfi_walker_ .FindCallerRegisters(*memory_, *cfi_frame_info, last_frame->context, last_frame->context_validity, &frame->context, &frame->context_validity)) - return NULL; + return nullptr; // Make sure we recovered all the essentials. static const int essentials = (StackFrameAMD64::CONTEXT_VALID_RIP | StackFrameAMD64::CONTEXT_VALID_RSP); if ((frame->context_validity & essentials) != essentials) - return NULL; + return nullptr; if (!frame->context.rip || !frame->context.rsp) { - BPLOG(ERROR) << "invalid rip/rsp"; - return NULL; + return nullptr; } frame->trust = StackFrame::FRAME_TRUST_CFI; @@ -181,7 +184,7 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByFramePointerRecovery( // If rbp is not 8-byte aligned it can't be a frame pointer. if (last_rbp % 8 != 0) { - return NULL; + return nullptr; } uint64_t caller_rip, caller_rbp; @@ -192,18 +195,18 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByFramePointerRecovery( // If the recovered rip is not a canonical address it can't be // the return address, so rbp must not have been a frame pointer. if (is_non_canonical(caller_rip)) { - return NULL; + return nullptr; } // Check that rbp is within the right frame if (caller_rsp <= last_rbp || caller_rbp < caller_rsp) { - return NULL; + return nullptr; } // Sanity check that resulting rbp is still inside stack memory. uint64_t unused; if (!memory_->GetMemoryAtAddress(caller_rbp, &unused)) { - return NULL; + return nullptr; } StackFrameAMD64* frame = new StackFrameAMD64(); @@ -218,7 +221,36 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByFramePointerRecovery( return frame; } - return NULL; + return nullptr; +} + +StackFrameAMD64* StackwalkerAMD64::GetCallerBySimulatingReturn( + const vector& frames) { + assert(frames.back()->trust == StackFrame::FRAME_TRUST_CONTEXT); + StackFrameAMD64* last_frame = static_cast(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 nullptr; + } + + // 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( @@ -228,9 +260,10 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByStackScan( 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; + return nullptr; } // Create a new stack frame (ownership will be transferred to the caller) @@ -275,21 +308,35 @@ StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack* stack, bool stack_scan_allowed) { if (!memory_ || !stack) { BPLOG(ERROR) << "Can't get caller frame without memory or stack"; - return NULL; + return nullptr; } const vector& frames = *stack->frames(); StackFrameAMD64* last_frame = static_cast(frames.back()); - scoped_ptr new_frame; + std::unique_ptr new_frame; - // If we have DWARF CFI information, use it. - scoped_ptr cfi_frame_info( + // If we have CFI information, use it. + std::unique_ptr 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)); } @@ -300,7 +347,7 @@ StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack* stack, // If nothing worked, tell the caller. if (!new_frame.get()) - return NULL; + return nullptr; if (system_info_->os_short == "nacl") { // Apply constraints from Native Client's x86-64 sandbox. These @@ -314,8 +361,10 @@ 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)) { - return NULL; + last_frame->context.rsp, + /*first_unwind=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { + return nullptr; } // new_frame->context.rip is the return address, which is the instruction diff --git a/src/processor/stackwalker_amd64.h b/src/processor/stackwalker_amd64.h index 5e1af6f13..307f2444a 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. // @@ -90,6 +89,11 @@ class StackwalkerAMD64 : public Stackwalker { // of the returned frame. Return NULL on failure. StackFrameAMD64* GetCallerByStackScan(const vector& frames); + // Trying to simulate a return. The caller takes ownership of the returned + // frame. Return NULL on failure. + StackFrameAMD64* GetCallerBySimulatingReturn( + const vector& frames); + // Stores the CPU context corresponding to the innermost stack frame to // be returned by GetContextFrame. const MDRawContextAMD64* context_; diff --git a/src/processor/stackwalker_amd64_unittest.cc b/src/processor/stackwalker_amd64_unittest.cc index a77015a6c..824e9a8f8 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. // @@ -31,6 +30,10 @@ // stackwalker_amd64_unittest.cc: Unit tests for StackwalkerAMD64 class. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -153,7 +156,7 @@ TEST_F(SanityCheck, NoResolver) { raw_context.rip = 0x00007400c0000200ULL; raw_context.rbp = 0x8000000080000000ULL; - StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackFrameSymbolizer frame_symbolizer(nullptr, nullptr); StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, &frame_symbolizer); // This should succeed even without a resolver or supplier. @@ -205,7 +208,7 @@ TEST_F(GetContextFrame, NoStackMemory) { raw_context.rbp = 0x8000000080000000ULL; StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); - StackwalkerAMD64 walker(&system_info, &raw_context, NULL, &modules, + StackwalkerAMD64 walker(&system_info, &raw_context, nullptr, &modules, &frame_symbolizer); vector modules_without_symbols; vector modules_with_corrupt_symbols; diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc index f932ded92..87c928144 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. // @@ -33,9 +32,13 @@ // // Author: Mark Mentovai, Ted Mielczarek, Jim Blandy +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include #include -#include "common/scoped_ptr.h" #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/memory_region.h" #include "google_breakpad/processor/source_line_resolver_interface.h" @@ -62,7 +65,7 @@ StackwalkerARM::StackwalkerARM(const SystemInfo* system_info, StackFrame* StackwalkerARM::GetContextFrame() { if (!context_) { BPLOG(ERROR) << "Can't get context frame without context"; - return NULL; + return nullptr; } StackFrameARM* frame = new StackFrameARM(); @@ -87,7 +90,7 @@ StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo( "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "fps", "cpsr", - NULL + nullptr }; // Populate a dictionary with the valid register values in last_frame. @@ -100,10 +103,10 @@ StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo( CFIFrameInfo::RegisterValueMap caller_registers; if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, &caller_registers)) - return NULL; + return nullptr; // Construct a new stack frame given the values the CFI recovered. - scoped_ptr frame(new StackFrameARM()); + std::unique_ptr frame(new StackFrameARM()); for (int i = 0; register_names[i]; i++) { CFIFrameInfo::RegisterValueMap::iterator entry = caller_registers.find(register_names[i]); @@ -155,7 +158,7 @@ StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo( static const int essentials = (StackFrameARM::CONTEXT_VALID_SP | StackFrameARM::CONTEXT_VALID_PC); if ((frame->context_validity & essentials) != essentials) - return NULL; + return nullptr; frame->trust = StackFrame::FRAME_TRUST_CFI; return frame.release(); @@ -168,9 +171,10 @@ StackFrameARM* StackwalkerARM::GetCallerByStackScan( 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; + return nullptr; } // ScanForReturnAddress found a reasonable return address. Advance @@ -198,7 +202,7 @@ StackFrameARM* StackwalkerARM::GetCallerByFramePointer( if (!(last_frame->context_validity & StackFrameARM::RegisterValidFlag(fp_register_))) { - return NULL; + return nullptr; } uint32_t last_fp = last_frame->context.iregs[fp_register_]; @@ -207,14 +211,14 @@ StackFrameARM* StackwalkerARM::GetCallerByFramePointer( 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; + return nullptr; } uint32_t caller_lr = 0; if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 4, &caller_lr)) { BPLOG(ERROR) << "Unable to read caller_lr from last_fp + 4: 0x" << std::hex << (last_fp + 4); - return NULL; + return nullptr; } uint32_t caller_sp = last_fp ? last_fp + 8 : @@ -238,43 +242,22 @@ StackFrameARM* StackwalkerARM::GetCallerByFramePointer( return frame; } -StackFrameARM* StackwalkerARM::GetCallerByLinkRegister( - const vector& frames) { - StackFrameARM* last_frame = static_cast(frames.back()); - uint32_t last_lr = last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; - - if (!(last_frame->context_validity & StackFrameARM::CONTEXT_VALID_LR) || - !InstructionAddressSeemsValid(last_lr)) { - return NULL; - } - - StackFrameARM* frame = new StackFrameARM(); - - frame->trust = StackFrame::FRAME_TRUST_SCAN; - frame->context = last_frame->context; - frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = last_lr; - frame->context_validity = - context_frame_validity_ & (~StackFrameARM::CONTEXT_VALID_LR); - - return frame; -} - StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack, bool stack_scan_allowed) { if (!memory_ || !stack) { BPLOG(ERROR) << "Can't get caller frame without memory or stack"; - return NULL; + return nullptr; } const vector& frames = *stack->frames(); StackFrameARM* last_frame = static_cast(frames.back()); - scoped_ptr frame; + std::unique_ptr frame; // See if there is DWARF call frame information covering this address. // TODO(jperaza): Ignore iOS CFI info until it is properly collected. // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=764 if (!system_info_ || system_info_->os != "iOS") { - scoped_ptr cfi_frame_info( + std::unique_ptr cfi_frame_info( frame_symbolizer_->FindCFIFrameInfo(last_frame)); if (cfi_frame_info.get()) frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); @@ -285,26 +268,21 @@ StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack, if (fp_register_ >= 0 && !frame.get()) frame.reset(GetCallerByFramePointer(frames)); - // For the first frame, return address may still be in the LR register at - // entry. Prefer to use LR register than scanning stack if LR register value - // points to a function range. - if (frames.size() == 1 && !frame.get()) - frame.reset(GetCallerByLinkRegister(frames)); - // If everuthing 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; + return nullptr; // Should we terminate the stack walk? (end-of-stack or broken invariant) 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)) { - return NULL; + /*first_unwind=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { + return nullptr; } // The new frame's context's PC is the return address, which is one diff --git a/src/processor/stackwalker_arm.h b/src/processor/stackwalker_arm.h index 9c386070b..d95b4e32d 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. // @@ -82,11 +81,6 @@ class StackwalkerARM : public Stackwalker { // Return NULL on failure. StackFrameARM* GetCallerByFramePointer(const vector& frames); - // Use the link register if it seems to be a valid function adderss. - // The caller takes ownership of the returned frame. Return NULL on failure. - // This is useful when PC register is corrupted. - StackFrameARM* GetCallerByLinkRegister(const vector& frames); - // Scan the stack for plausible return addresses. The caller takes ownership // of the returned frame. Return NULL on failure. StackFrameARM* GetCallerByStackScan(const vector& frames); diff --git a/src/processor/stackwalker_arm64.cc b/src/processor/stackwalker_arm64.cc index 9acf8188e..a174fb5b2 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. // @@ -33,16 +32,23 @@ // // Author: Mark Mentovai, Ted Mielczarek, Jim Blandy, Colin Blundell +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "processor/stackwalker_arm64.h" + +#include + +#include #include -#include "common/scoped_ptr.h" #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/memory_region.h" #include "google_breakpad/processor/source_line_resolver_interface.h" #include "google_breakpad/processor/stack_frame_cpu.h" #include "processor/cfi_frame_info.h" #include "processor/logging.h" -#include "processor/stackwalker_arm64.h" namespace google_breakpad { @@ -81,7 +87,7 @@ uint64_t StackwalkerARM64::PtrauthStrip(uint64_t ptr) { StackFrame* StackwalkerARM64::GetContextFrame() { if (!context_) { BPLOG(ERROR) << "Can't get context frame without context"; - return NULL; + return nullptr; } StackFrameARM64* frame = new StackFrameARM64(); @@ -108,7 +114,7 @@ StackFrameARM64* StackwalkerARM64::GetCallerByCFIFrameInfo( "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", - "pc", NULL + "pc", nullptr }; // Populate a dictionary with the valid register values in last_frame. @@ -122,10 +128,10 @@ StackFrameARM64* StackwalkerARM64::GetCallerByCFIFrameInfo( CFIFrameInfo::RegisterValueMap caller_registers; if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, &caller_registers)) { - return NULL; + return nullptr; } // Construct a new stack frame given the values the CFI recovered. - scoped_ptr frame(new StackFrameARM64()); + std::unique_ptr frame(new StackFrameARM64()); for (int i = 0; register_names[i]; i++) { CFIFrameInfo::RegisterValueMap::iterator entry = caller_registers.find(register_names[i]); @@ -168,8 +174,10 @@ StackFrameARM64* StackwalkerARM64::GetCallerByCFIFrameInfo( static const uint64_t essentials = (StackFrameARM64::CONTEXT_VALID_SP | StackFrameARM64::CONTEXT_VALID_PC); if ((frame->context_validity & essentials) != essentials) - return NULL; + return nullptr; + 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(); } @@ -181,9 +189,10 @@ StackFrameARM64* StackwalkerARM64::GetCallerByStackScan( 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; + return nullptr; } // ScanForReturnAddress found a reasonable return address. Advance @@ -218,14 +227,14 @@ StackFrameARM64* StackwalkerARM64::GetCallerByFramePointer( 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; + return nullptr; } uint64_t caller_lr = 0; if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 8, &caller_lr)) { BPLOG(ERROR) << "Unable to read caller_lr from last_fp + 8: 0x" << std::hex << (last_fp + 8); - return NULL; + return nullptr; } caller_lr = PtrauthStrip(caller_lr); @@ -261,15 +270,27 @@ void StackwalkerARM64::CorrectRegLRByFramePointer( last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP]) return; - StackFrameARM64* last_last_frame = - static_cast(*(frames.end() - 2)); - uint64_t last_last_fp = - last_last_frame->context.iregs[MD_CONTEXT_ARM64_REG_FP]; + // Searching for a real callee frame. Skipping inline frames since they + // don't contain context (and cannot be downcasted to StackFrameARM64). + int64_t last_frame_callee_id = frames.size() - 2; + while (last_frame_callee_id >= 0 && frames[last_frame_callee_id]->trust == + StackFrame::FRAME_TRUST_INLINE) { + last_frame_callee_id--; + } + // last_frame_callee_id should not become negative because at the top of the + // stack trace we always have a context frame (FRAME_TRUST_CONTEXT) so the + // above loop should end before last_frame_callee_id gets negative. But we are + // being extra defensive here and bail if it ever becomes negative. + if (last_frame_callee_id < 0) return; + StackFrameARM64* last_frame_callee = + static_cast(frames[last_frame_callee_id]); + + uint64_t last_frame_callee_fp = + last_frame_callee->context.iregs[MD_CONTEXT_ARM64_REG_FP]; uint64_t last_fp = 0; - if (last_last_fp && !memory_->GetMemoryAtAddress(last_last_fp, &last_fp)) { - BPLOG(ERROR) << "Unable to read last_fp from last_last_fp: 0x" - << std::hex << last_last_fp; + if (last_frame_callee_fp && + !memory_->GetMemoryAtAddress(last_frame_callee_fp, &last_fp)) { return; } // Give up if STACK CFI doesn't agree with frame pointer. @@ -277,9 +298,10 @@ void StackwalkerARM64::CorrectRegLRByFramePointer( return; uint64_t last_lr = 0; - if (last_last_fp && !memory_->GetMemoryAtAddress(last_last_fp + 8, &last_lr)) { + if (last_frame_callee_fp && + !memory_->GetMemoryAtAddress(last_frame_callee_fp + 8, &last_lr)) { BPLOG(ERROR) << "Unable to read last_lr from (last_last_fp + 8): 0x" - << std::hex << (last_last_fp + 8); + << std::hex << (last_frame_callee_fp + 8); return; } last_lr = PtrauthStrip(last_lr); @@ -291,15 +313,15 @@ StackFrame* StackwalkerARM64::GetCallerFrame(const CallStack* stack, bool stack_scan_allowed) { if (!memory_ || !stack) { BPLOG(ERROR) << "Can't get caller frame without memory or stack"; - return NULL; + return nullptr; } const vector& frames = *stack->frames(); StackFrameARM64* last_frame = static_cast(frames.back()); - scoped_ptr frame; + std::unique_ptr frame; // See if there is DWARF call frame information covering this address. - scoped_ptr cfi_frame_info( + std::unique_ptr cfi_frame_info( frame_symbolizer_->FindCFIFrameInfo(last_frame)); if (cfi_frame_info.get()) frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); @@ -314,14 +336,15 @@ StackFrame* StackwalkerARM64::GetCallerFrame(const CallStack* stack, // If nothing worked, tell the caller. if (!frame.get()) - return NULL; + return nullptr; // Should we terminate the stack walk? (end-of-stack or broken invariant) 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)) { - return NULL; + /*first_unwind=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { + return nullptr; } // The new frame's context's PC is the return address, which is one diff --git a/src/processor/stackwalker_arm64.h b/src/processor/stackwalker_arm64.h index 4c7da3fbd..933b557ff 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. // @@ -42,6 +41,7 @@ #include "google_breakpad/common/breakpad_types.h" #include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/stack_frame_cpu.h" #include "google_breakpad/processor/stackwalker.h" namespace google_breakpad { diff --git a/src/processor/stackwalker_arm64_unittest.cc b/src/processor/stackwalker_arm64_unittest.cc index 6553e0cd9..24c3527db 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. // @@ -31,6 +30,10 @@ // stackwalker_arm64_unittest.cc: Unit tests for StackwalkerARM64 class. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -147,7 +150,7 @@ class SanityCheck: public StackwalkerARM64Fixture, 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); + StackFrameSymbolizer frame_symbolizer(nullptr, nullptr); StackwalkerARM64 walker(&system_info, &raw_context, &stack_region, &modules, &frame_symbolizer); // This should succeed even without a resolver or supplier. @@ -171,7 +174,7 @@ class GetContextFrame: public StackwalkerARM64Fixture, public Test { }; // without stack memory present. TEST_F(GetContextFrame, NoStackMemory) { StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); - StackwalkerARM64 walker(&system_info, &raw_context, NULL, &modules, + StackwalkerARM64 walker(&system_info, &raw_context, nullptr, &modules, &frame_symbolizer); vector modules_without_symbols; vector modules_with_corrupt_symbols; diff --git a/src/processor/stackwalker_arm_unittest.cc b/src/processor/stackwalker_arm_unittest.cc index 046081fa2..eab51c379 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. // @@ -31,6 +30,10 @@ // stackwalker_arm_unittest.cc: Unit tests for StackwalkerARM class. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -149,7 +152,7 @@ TEST_F(SanityCheck, NoResolver) { // Since we have no call frame information, and all unwinding // requires call frame information, the stack walk will end after // the first frame. - StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackFrameSymbolizer frame_symbolizer(nullptr, nullptr); StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules, &frame_symbolizer); // This should succeed even without a resolver or supplier. @@ -194,7 +197,7 @@ TEST_F(GetContextFrame, Simple) { // without stack memory present. TEST_F(GetContextFrame, NoStackMemory) { StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); - StackwalkerARM walker(&system_info, &raw_context, -1, NULL, &modules, + StackwalkerARM walker(&system_info, &raw_context, -1, nullptr, &modules, &frame_symbolizer); vector modules_without_symbols; vector modules_with_corrupt_symbols; diff --git a/src/processor/stackwalker_mips.cc b/src/processor/stackwalker_mips.cc index c33ecdbe9..4a7c0e107 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. // @@ -33,7 +32,12 @@ // // Author: Tata Elxsi -#include "common/scoped_ptr.h" +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/code_modules.h" #include "google_breakpad/processor/memory_region.h" @@ -62,7 +66,7 @@ StackwalkerMIPS::StackwalkerMIPS(const SystemInfo* system_info, << HexString(memory_->GetBase()) << "+" << HexString(memory_->GetSize()); - memory_ = NULL; + memory_ = nullptr; } } else { if (0xffffffff - memory_->GetBase() < memory_->GetSize() - 1) { @@ -70,7 +74,7 @@ StackwalkerMIPS::StackwalkerMIPS(const SystemInfo* system_info, << HexString(memory_->GetBase()) << "+" << HexString(memory_->GetSize()); - memory_ = NULL; + memory_ = nullptr; } } } @@ -79,7 +83,7 @@ StackwalkerMIPS::StackwalkerMIPS(const SystemInfo* system_info, StackFrame* StackwalkerMIPS::GetContextFrame() { if (!context_) { BPLOG(ERROR) << "Can't get context frame without context."; - return NULL; + return nullptr; } StackFrameMIPS* frame = new StackFrameMIPS(); @@ -99,7 +103,7 @@ static const char* const kRegisterNames[] = { "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", "$to", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", - "$fp", "$ra", NULL + "$fp", "$ra", nullptr // TODO(gordanac): add float point save registers }; @@ -123,7 +127,7 @@ StackFrameMIPS* StackwalkerMIPS::GetCallerByCFIFrameInfo( if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, &caller_registers)) { - return NULL; + return nullptr; } CFIFrameInfo::RegisterValueMap::const_iterator entry = @@ -140,7 +144,7 @@ StackFrameMIPS* StackwalkerMIPS::GetCallerByCFIFrameInfo( } caller_registers["$pc"] = pc; // Construct a new stack frame given the values the CFI recovered. - scoped_ptr frame(new StackFrameMIPS()); + std::unique_ptr frame(new StackFrameMIPS()); for (int i = 0; kRegisterNames[i]; ++i) { CFIFrameInfo::RegisterValueMap::const_iterator caller_entry = @@ -190,7 +194,7 @@ StackFrameMIPS* StackwalkerMIPS::GetCallerByCFIFrameInfo( if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, &caller_registers)) { - return NULL; + return nullptr; } CFIFrameInfo::RegisterValueMap::const_iterator entry = @@ -207,7 +211,7 @@ StackFrameMIPS* StackwalkerMIPS::GetCallerByCFIFrameInfo( } caller_registers["$pc"] = pc; // Construct a new stack frame given the values the CFI recovered. - scoped_ptr frame(new StackFrameMIPS()); + std::unique_ptr frame(new StackFrameMIPS()); for (int i = 0; kRegisterNames[i]; ++i) { CFIFrameInfo::RegisterValueMap::const_iterator caller_entry = @@ -249,15 +253,15 @@ StackFrame* StackwalkerMIPS::GetCallerFrame(const CallStack* stack, bool stack_scan_allowed) { if (!memory_ || !stack) { BPLOG(ERROR) << "Can't get caller frame without memory or stack"; - return NULL; + return nullptr; } const vector& frames = *stack->frames(); StackFrameMIPS* last_frame = static_cast(frames.back()); - scoped_ptr new_frame; + std::unique_ptr new_frame; // See if there is DWARF call frame information covering this address. - scoped_ptr cfi_frame_info( + std::unique_ptr cfi_frame_info( frame_symbolizer_->FindCFIFrameInfo(last_frame)); if (cfi_frame_info.get()) new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); @@ -269,15 +273,16 @@ StackFrame* StackwalkerMIPS::GetCallerFrame(const CallStack* stack, // If nothing worked, tell the caller. if (!new_frame.get()) { - return NULL; + return nullptr; } // Should we terminate the stack walk? (end-of-stack or broken invariant) 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)) { - return NULL; + /*first_unwind=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { + return nullptr; } return new_frame.release(); @@ -322,13 +327,13 @@ StackFrameMIPS* StackwalkerMIPS::GetCallerByStackScan( // If we can't find an instruction pointer even with stack scanning, // give up. BPLOG(ERROR) << " ScanForReturnAddress failed "; - return NULL; + return nullptr; } // Get $fp stored in the stack frame. if (!memory_->GetMemoryAtAddress(caller_sp - sizeof(caller_pc), &caller_fp)) { BPLOG(INFO) << " GetMemoryAtAddress for fp failed " ; - return NULL; + return nullptr; } count = count - (caller_sp - last_sp) / sizeof(caller_pc); @@ -338,7 +343,7 @@ StackFrameMIPS* StackwalkerMIPS::GetCallerByStackScan( if (!count) { BPLOG(INFO) << " No frame found " ; - return NULL; + return nullptr; } // ScanForReturnAddress found a reasonable return address. Advance @@ -388,13 +393,13 @@ StackFrameMIPS* StackwalkerMIPS::GetCallerByStackScan( // If we can't find an instruction pointer even with stack scanning, // give up. BPLOG(ERROR) << " ScanForReturnAddress failed "; - return NULL; + return nullptr; } // Get $fp stored in the stack frame. if (!memory_->GetMemoryAtAddress(caller_sp - sizeof(caller_pc), &caller_fp)) { BPLOG(INFO) << " GetMemoryAtAddress for fp failed " ; - return NULL; + return nullptr; } count = count - (caller_sp - last_sp) / sizeof(caller_pc); @@ -404,7 +409,7 @@ StackFrameMIPS* StackwalkerMIPS::GetCallerByStackScan( if (!count) { BPLOG(INFO) << " No frame found " ; - return NULL; + return nullptr; } // ScanForReturnAddress found a reasonable return address. Advance diff --git a/src/processor/stackwalker_mips.h b/src/processor/stackwalker_mips.h index 5f97791fb..e9776074e 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 c3c3011a9..f8791e3c4 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. // @@ -32,6 +31,10 @@ // stackwalker_mips64_unittest.cc: Unit tests for StackwalkerMIPS class for // mips64 platforms. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -155,7 +158,7 @@ TEST_F(SanityCheck, NoResolver) { raw_context.epc = 0x00400020; raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; - StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackFrameSymbolizer frame_symbolizer(nullptr, nullptr); StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, &frame_symbolizer); // This should succeed, even without a resolver or supplier. @@ -211,7 +214,7 @@ TEST_F(GetContextFrame, NoStackMemory) { raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); - StackwalkerMIPS walker(&system_info, &raw_context, NULL, &modules, + StackwalkerMIPS walker(&system_info, &raw_context, nullptr, &modules, &frame_symbolizer); vector modules_without_symbols; vector modules_with_corrupt_symbols; @@ -645,8 +648,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 21267aebc..c92d1f0a7 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. // @@ -31,6 +30,10 @@ // stackwalker_mips_unittest.cc: Unit tests for StackwalkerMIPS class. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -153,7 +156,7 @@ TEST_F(SanityCheck, NoResolver) { raw_context.epc = 0x00400020; raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; - StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackFrameSymbolizer frame_symbolizer(nullptr, nullptr); StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, &frame_symbolizer); // This should succeed, even without a resolver or supplier. @@ -207,7 +210,7 @@ TEST_F(GetContextFrame, NoStackMemory) { raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); - StackwalkerMIPS walker(&system_info, &raw_context, NULL, &modules, + StackwalkerMIPS walker(&system_info, &raw_context, nullptr, &modules, &frame_symbolizer); vector modules_without_symbols; vector modules_with_corrupt_symbols; diff --git a/src/processor/stackwalker_ppc.cc b/src/processor/stackwalker_ppc.cc index 1e34c3833..4afeec83d 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. // @@ -34,7 +33,12 @@ // Author: Mark Mentovai -#include "common/scoped_ptr.h" +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + #include "processor/stackwalker_ppc.h" #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/memory_region.h" @@ -58,7 +62,7 @@ StackwalkerPPC::StackwalkerPPC(const SystemInfo* system_info, BPLOG(ERROR) << "Memory out of range for stackwalking: " << HexString(memory_->GetBase()) << "+" << HexString(memory_->GetSize()); - memory_ = NULL; + memory_ = nullptr; } } @@ -66,7 +70,7 @@ StackwalkerPPC::StackwalkerPPC(const SystemInfo* system_info, StackFrame* StackwalkerPPC::GetContextFrame() { if (!context_) { BPLOG(ERROR) << "Can't get context frame without context"; - return NULL; + return nullptr; } StackFramePPC* frame = new StackFramePPC(); @@ -86,7 +90,7 @@ StackFrame* StackwalkerPPC::GetCallerFrame(const CallStack* stack, bool stack_scan_allowed) { if (!memory_ || !stack) { BPLOG(ERROR) << "Can't get caller frame without memory or stack"; - return NULL; + return nullptr; } // The instruction pointers for previous frames are saved on the stack. @@ -108,7 +112,7 @@ StackFrame* StackwalkerPPC::GetCallerFrame(const CallStack* stack, if (!memory_->GetMemoryAtAddress(last_frame->context.gpr[1], &stack_pointer) || stack_pointer <= last_frame->context.gpr[1]) { - return NULL; + return nullptr; } // Mac OS X/Darwin gives 1 as the return address from the bottom-most @@ -119,10 +123,10 @@ StackFrame* StackwalkerPPC::GetCallerFrame(const CallStack* stack, uint32_t instruction; if (!memory_->GetMemoryAtAddress(stack_pointer + 8, &instruction) || instruction <= 1) { - return NULL; + return nullptr; } - scoped_ptr frame(new StackFramePPC()); + std::unique_ptr frame(new StackFramePPC()); frame->context = last_frame->context; frame->context.srr0 = instruction; @@ -132,11 +136,10 @@ 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)) { - return NULL; + if (TerminateWalk(instruction, stack_pointer, last_frame->context.gpr[1], + /*first_unwind=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { + return nullptr; } // frame->context.srr0 is the return address, which is one instruction diff --git a/src/processor/stackwalker_ppc.h b/src/processor/stackwalker_ppc.h index 012e5c32f..182e46d45 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 fb2bac3c4..f0298f2bc 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. // @@ -32,7 +31,12 @@ // See stackwalker_ppc64.h for documentation. -#include "common/scoped_ptr.h" +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + #include "processor/stackwalker_ppc64.h" #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/memory_region.h" @@ -57,7 +61,7 @@ StackwalkerPPC64::StackwalkerPPC64(const SystemInfo* system_info, StackFrame* StackwalkerPPC64::GetContextFrame() { if (!context_) { BPLOG(ERROR) << "Can't get context frame without context"; - return NULL; + return nullptr; } StackFramePPC64* frame = new StackFramePPC64(); @@ -77,7 +81,7 @@ StackFrame* StackwalkerPPC64::GetCallerFrame(const CallStack* stack, bool stack_scan_allowed) { if (!memory_ || !stack) { BPLOG(ERROR) << "Can't get caller frame without memory or stack"; - return NULL; + return nullptr; } // The instruction pointers for previous frames are saved on the stack. @@ -99,7 +103,7 @@ StackFrame* StackwalkerPPC64::GetCallerFrame(const CallStack* stack, if (!memory_->GetMemoryAtAddress(last_frame->context.gpr[1], &stack_pointer) || stack_pointer <= last_frame->context.gpr[1]) { - return NULL; + return nullptr; } // Mac OS X/Darwin gives 1 as the return address from the bottom-most @@ -110,10 +114,10 @@ StackFrame* StackwalkerPPC64::GetCallerFrame(const CallStack* stack, uint64_t instruction; if (!memory_->GetMemoryAtAddress(stack_pointer + 16, &instruction) || instruction <= 1) { - return NULL; + return nullptr; } - scoped_ptr frame(new StackFramePPC64()); + std::unique_ptr frame(new StackFramePPC64()); frame->context = last_frame->context; frame->context.srr0 = instruction; @@ -123,11 +127,10 @@ 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)) { - return NULL; + if (TerminateWalk(instruction, stack_pointer, last_frame->context.gpr[1], + /*is_context_frame=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { + return nullptr; } // frame->context.srr0 is the return address, which is one instruction diff --git a/src/processor/stackwalker_ppc64.h b/src/processor/stackwalker_ppc64.h index a406343af..ede0b51c6 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 000000000..d350fe54f --- /dev/null +++ b/src/processor/stackwalker_riscv.cc @@ -0,0 +1,540 @@ +// 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 + */ + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + +#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 nullptr; + } + + 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& frames, + CFIFrameInfo* cfi_frame_info) { + StackFrameRISCV* last_frame = + static_cast(frames.back()); + + // Populate a dictionary with the valid register values in last_frame. + CFIFrameInfo::RegisterValueMap 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 caller_registers; + if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, + &caller_registers)) { + return nullptr; + } + + // Construct a new stack frame given the values the CFI recovered. + CFIFrameInfo::RegisterValueMap::iterator entry; + std::unique_ptr 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 nullptr; + + frame->trust = StackFrame::FRAME_TRUST_CFI; + return frame.release(); +} + +StackFrameRISCV* StackwalkerRISCV::GetCallerByStackScan( + const vector& frames) { + StackFrameRISCV* last_frame = + static_cast(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 nullptr; + } + + // 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& frames) { + StackFrameRISCV* last_frame = + static_cast(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 nullptr; + } + + 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 nullptr; + } + + 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 nullptr; + } + + const vector& frames = *stack->frames(); + StackFrameRISCV* last_frame = + static_cast(frames.back()); + std::unique_ptr frame; + + // Try to recover caller information from CFI. + std::unique_ptr 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 nullptr; + + // 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 nullptr; + } + + // 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 000000000..863914d88 --- /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& 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& frames); + + // Scan the stack for plausible return addresses. The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameRISCV* GetCallerByStackScan( + const vector& 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 000000000..3da914db9 --- /dev/null +++ b/src/processor/stackwalker_riscv64.cc @@ -0,0 +1,540 @@ +// 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 + */ + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + +#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 nullptr; + } + + 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& frames, + CFIFrameInfo* cfi_frame_info) { + StackFrameRISCV64* last_frame = + static_cast(frames.back()); + + // Populate a dictionary with the valid register values in last_frame. + CFIFrameInfo::RegisterValueMap 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 caller_registers; + if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, + &caller_registers)) { + return nullptr; + } + + // Construct a new stack frame given the values the CFI recovered. + CFIFrameInfo::RegisterValueMap::iterator entry; + std::unique_ptr 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 nullptr; + + frame->trust = StackFrame::FRAME_TRUST_CFI; + return frame.release(); +} + +StackFrameRISCV64* StackwalkerRISCV64::GetCallerByStackScan( + const vector& frames) { + StackFrameRISCV64* last_frame = + static_cast(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 nullptr; + } + + // 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& frames) { + StackFrameRISCV64* last_frame = + static_cast(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 nullptr; + } + + 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 nullptr; + } + + 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 nullptr; + } + + const vector& frames = *stack->frames(); + StackFrameRISCV64* last_frame = + static_cast(frames.back()); + std::unique_ptr frame; + + // Try to recover caller information from CFI. + std::unique_ptr 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 nullptr; + + // 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 nullptr; + } + + // 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 000000000..89ab12ff6 --- /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& 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& frames); + + // Scan the stack for plausible return addresses. The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameRISCV64* GetCallerByStackScan( + const vector& 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 000000000..5f02c0d9f --- /dev/null +++ b/src/processor/stackwalker_riscv64_unittest.cc @@ -0,0 +1,887 @@ +// 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 + */ + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include +#include +#include + +#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(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* 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(nullptr, nullptr); + StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + // This should succeed even without a resolver or supplier. + vector modules_without_symbols; + vector 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(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, nullptr, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector 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(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 modules_without_symbols; + vector 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(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(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(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 modules_without_symbols; + vector 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(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(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 modules_without_symbols; + vector 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(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(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 modules_without_symbols; + vector 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(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 modules_without_symbols; + vector 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(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(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(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 modules_without_symbols; + vector 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(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(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 modules_without_symbols; + vector 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 modules_without_symbols; + vector 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 000000000..555b55d01 --- /dev/null +++ b/src/processor/stackwalker_riscv_unittest.cc @@ -0,0 +1,887 @@ +// 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 + */ + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include +#include +#include + +#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(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* 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(nullptr, nullptr); + StackwalkerRISCV walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + // This should succeed even without a resolver or supplier. + vector modules_without_symbols; + vector 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(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, nullptr, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector 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(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 modules_without_symbols; + vector 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(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(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(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 modules_without_symbols; + vector 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(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(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 modules_without_symbols; + vector 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(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(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 modules_without_symbols; + vector 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(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 modules_without_symbols; + vector 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(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(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(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 modules_without_symbols; + vector 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(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(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 modules_without_symbols; + vector 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 modules_without_symbols; + vector 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 dcb2df007..977567cce 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. // @@ -49,6 +48,10 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "processor/logging.h" @@ -66,7 +69,6 @@ #include -#include "common/scoped_ptr.h" #include "google_breakpad/common/breakpad_types.h" #include "google_breakpad/common/minidump_format.h" #include "google_breakpad/processor/basic_source_line_resolver.h" @@ -80,7 +82,6 @@ using google_breakpad::BasicSourceLineResolver; using google_breakpad::CallStack; using google_breakpad::CodeModule; using google_breakpad::MemoryRegion; -using google_breakpad::scoped_ptr; using google_breakpad::StackFrame; using google_breakpad::StackFramePPC; using google_breakpad::StackFrameX86; @@ -324,23 +325,23 @@ static unsigned int CountCallerFrames() { context.ebp = GetEBP(); context.esp = GetESP(); - StackwalkerX86 stackwalker = StackwalkerX86(NULL, &context, &memory, NULL, - NULL, &resolver); + StackwalkerX86 stackwalker = StackwalkerX86(nullptr, &context, &memory, + nullptr, nullptr, &resolver); #elif defined(__ppc__) MDRawContextPPC context = MDRawContextPPC(); context.srr0 = GetPC(); context.gpr[1] = GetSP(); - StackwalkerPPC stackwalker = StackwalkerPPC(NULL, &context, &memory, NULL, - NULL, &resolver); + StackwalkerPPC stackwalker = StackwalkerPPC(nullptr, &context, &memory, + nullptr, nullptr, &resolver); #elif defined(__sparc__) MDRawContextSPARC context = MDRawContextSPARC(); context.pc = GetPC(); context.g_r[14] = GetSP(); context.g_r[30] = GetFP(); - StackwalkerSPARC stackwalker = StackwalkerSPARC(NULL, &context, &memory, - NULL, NULL, &resolver); + StackwalkerSPARC stackwalker = StackwalkerSPARC(nullptr, &context, &memory, + nullptr, nullptr, &resolver); #endif // __i386__ || __ppc__ || __sparc__ CallStack stack; diff --git a/src/processor/stackwalker_selftest_sol.s b/src/processor/stackwalker_selftest_sol.s index 648b0499a..11d1698fb 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 4de838afe..9fc78a2e6 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. // @@ -34,6 +33,10 @@ // Author: Michael Shang +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/memory_region.h" #include "google_breakpad/processor/stack_frame_cpu.h" @@ -56,7 +59,7 @@ StackwalkerSPARC::StackwalkerSPARC(const SystemInfo* system_info, StackFrame* StackwalkerSPARC::GetContextFrame() { if (!context_) { BPLOG(ERROR) << "Can't get context frame without context"; - return NULL; + return nullptr; } StackFrameSPARC* frame = new StackFrameSPARC(); @@ -76,7 +79,7 @@ StackFrame* StackwalkerSPARC::GetCallerFrame(const CallStack* stack, bool stack_scan_allowed) { if (!memory_ || !stack) { BPLOG(ERROR) << "Can't get caller frame without memory or stack"; - return NULL; + return nullptr; } StackFrameSPARC* last_frame = static_cast( @@ -96,27 +99,26 @@ StackFrame* StackwalkerSPARC::GetCallerFrame(const CallStack* stack, // end of the stack. uint64_t stack_pointer = last_frame->context.g_r[30]; if (stack_pointer <= last_frame->context.g_r[14]) { - return NULL; + return nullptr; } uint32_t instruction; if (!memory_->GetMemoryAtAddress(stack_pointer + 60, &instruction) || instruction <= 1) { - return NULL; + return nullptr; } uint32_t stack_base; if (!memory_->GetMemoryAtAddress(stack_pointer + 56, &stack_base) || stack_base <= 1) { - return NULL; + return nullptr; } // 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)) { - return NULL; + if (TerminateWalk(instruction, stack_pointer, last_frame->context.g_r[14], + /*is_context_frame=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { + return nullptr; } StackFrameSPARC* frame = new StackFrameSPARC(); diff --git a/src/processor/stackwalker_sparc.h b/src/processor/stackwalker_sparc.h index e8f2a3888..b7ba507e5 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 2905ea06e..ef09ebbd7 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. // @@ -148,7 +147,7 @@ class MockCodeModules: public google_breakpad::CodeModules { address - module->base_address() < module->size()) return module; } - return NULL; + return nullptr; }; const CodeModule* GetMainModule() const { return modules_[0]; } diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc index b11e061d4..ae8706d1a 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. // @@ -33,10 +32,15 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include + +#include #include -#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" @@ -68,19 +72,19 @@ StackwalkerX86::cfi_register_map_[] = { StackFrameX86::CONTEXT_VALID_EIP, &MDRawContextX86::eip }, { "$esp", ".cfa", false, StackFrameX86::CONTEXT_VALID_ESP, &MDRawContextX86::esp }, - { "$ebp", NULL, true, + { "$ebp", nullptr, true, StackFrameX86::CONTEXT_VALID_EBP, &MDRawContextX86::ebp }, - { "$eax", NULL, false, + { "$eax", nullptr, false, StackFrameX86::CONTEXT_VALID_EAX, &MDRawContextX86::eax }, - { "$ebx", NULL, true, + { "$ebx", nullptr, true, StackFrameX86::CONTEXT_VALID_EBX, &MDRawContextX86::ebx }, - { "$ecx", NULL, false, + { "$ecx", nullptr, false, StackFrameX86::CONTEXT_VALID_ECX, &MDRawContextX86::ecx }, - { "$edx", NULL, false, + { "$edx", nullptr, false, StackFrameX86::CONTEXT_VALID_EDX, &MDRawContextX86::edx }, - { "$esi", NULL, true, + { "$esi", nullptr, true, StackFrameX86::CONTEXT_VALID_ESI, &MDRawContextX86::esi }, - { "$edi", NULL, true, + { "$edi", nullptr, true, StackFrameX86::CONTEXT_VALID_EDI, &MDRawContextX86::edi }, }; @@ -99,17 +103,17 @@ StackwalkerX86::StackwalkerX86(const SystemInfo* system_info, BPLOG(ERROR) << "Memory out of range for stackwalking: " << HexString(memory_->GetBase()) << "+" << HexString(memory_->GetSize()); - memory_ = NULL; + memory_ = nullptr; } } StackFrameX86::~StackFrameX86() { if (windows_frame_info) delete windows_frame_info; - windows_frame_info = NULL; + windows_frame_info = nullptr; if (cfi_frame_info) delete cfi_frame_info; - cfi_frame_info = NULL; + cfi_frame_info = nullptr; } uint64_t StackFrameX86::ReturnAddress() const { @@ -120,7 +124,7 @@ uint64_t StackFrameX86::ReturnAddress() const { StackFrame* StackwalkerX86::GetContextFrame() { if (!context_) { BPLOG(ERROR) << "Can't get context frame without context"; - return NULL; + return nullptr; } StackFrameX86* frame = new StackFrameX86(); @@ -141,6 +145,9 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo( 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(frames.back()); // Save the stack walking info we found, in case we need it later to @@ -151,7 +158,7 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo( // last_frame_info is VALID_PARAMETER_SIZE-only, then we should // assume the traditional frame format or use some other strategy. if (last_frame_info->valid != WindowsFrameInfo::VALID_ALL) - return NULL; + return nullptr; // This stackwalker sets each frame's %esp to its value immediately prior // to the CALL into the callee. This means that %esp points to the last @@ -187,9 +194,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(frames[frames_already_walked - 2]); + = static_cast(frames[last_frame_callee_id]); WindowsFrameInfo* last_frame_callee_info = last_frame_callee->windows_frame_info; if (last_frame_callee_info && @@ -242,7 +255,7 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo( // for calculation of the value of .raSearchStart are available. if (ScanForReturnAddress(raSearchStart, &raSearchStart, &found, 3) && last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT && - last_frame->windows_frame_info != NULL && + last_frame->windows_frame_info != nullptr && last_frame_info->type_ == WindowsFrameInfo::STACK_INFO_FPO && raSearchStartOld == raSearchStart && found == last_frame->context.eip) { @@ -385,12 +398,13 @@ 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; + return nullptr; } // This seems like a reasonable return address. Since program string @@ -429,9 +443,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. @@ -516,22 +531,25 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo( StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo( const vector& 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(frames.back()); last_frame->cfi_frame_info = cfi_frame_info; - scoped_ptr frame(new StackFrameX86()); + std::unique_ptr frame(new StackFrameX86()); if (!cfi_walker_ .FindCallerRegisters(*memory_, *cfi_frame_info, last_frame->context, last_frame->context_validity, &frame->context, &frame->context_validity)) - return NULL; + return nullptr; // Make sure we recovered all the essentials. static const int essentials = (StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP | StackFrameX86::CONTEXT_VALID_EBP); if ((frame->context_validity & essentials) != essentials) - return NULL; + return nullptr; frame->trust = StackFrame::FRAME_TRUST_CFI; @@ -542,6 +560,9 @@ StackFrameX86* StackwalkerX86::GetCallerByEBPAtBase( const vector& 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(frames.back()); uint32_t last_esp = last_frame->context.esp; uint32_t last_ebp = last_frame->context.ebp; @@ -581,12 +602,13 @@ 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; + return nullptr; } // ScanForReturnAddress found a reasonable return address. Advance %esp to @@ -629,12 +651,15 @@ StackFrame* StackwalkerX86::GetCallerFrame(const CallStack* stack, bool stack_scan_allowed) { if (!memory_ || !stack) { BPLOG(ERROR) << "Can't get caller frame without memory or stack"; - return NULL; + return nullptr; } const vector& frames = *stack->frames(); StackFrameX86* last_frame = static_cast(frames.back()); - scoped_ptr new_frame; + // 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); + std::unique_ptr new_frame; // If the resolver has Windows stack walking information, use that. WindowsFrameInfo* windows_frame_info @@ -657,14 +682,14 @@ StackFrame* StackwalkerX86::GetCallerFrame(const CallStack* stack, // If nothing worked, tell the caller. if (!new_frame.get()) - return NULL; + return nullptr; // 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)) { - return NULL; + /*first_unwind=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { + return nullptr; } // new_frame->context.eip is the return address, which is the instruction diff --git a/src/processor/stackwalker_x86.h b/src/processor/stackwalker_x86.h index 1783fda32..1867a689b 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. // diff --git a/src/processor/stackwalker_x86_unittest.cc b/src/processor/stackwalker_x86_unittest.cc index b6f14a145..e5bb63e49 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. // @@ -31,6 +30,10 @@ // stackwalker_x86_unittest.cc: Unit tests for StackwalkerX86 class. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include @@ -163,7 +166,7 @@ TEST_F(SanityCheck, NoResolver) { raw_context.eip = 0x40000200; raw_context.ebp = 0x80000000; - StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackFrameSymbolizer frame_symbolizer(nullptr, nullptr); StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, &frame_symbolizer); // This should succeed, even without a resolver or supplier. @@ -214,7 +217,7 @@ TEST_F(GetContextFrame, NoStackMemory) { raw_context.ebp = 0x80000000; StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); - StackwalkerX86 walker(&system_info, &raw_context, NULL, &modules, + StackwalkerX86 walker(&system_info, &raw_context, nullptr, &modules, &frame_symbolizer); vector modules_without_symbols; vector modules_with_corrupt_symbols; @@ -275,7 +278,7 @@ TEST_F(GetCallerFrame, Traditional) { EXPECT_EQ(0x4000c7a5U, frame0->instruction); EXPECT_EQ(0x4000c7a5U, frame0->context.eip); EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); - EXPECT_EQ(NULL, frame0->windows_frame_info); + EXPECT_EQ(nullptr, frame0->windows_frame_info); } { // To avoid reusing locals by mistake @@ -288,7 +291,7 @@ TEST_F(GetCallerFrame, Traditional) { EXPECT_EQ(0x40008679U, frame1->instruction + 1); EXPECT_EQ(0x40008679U, frame1->context.eip); EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); - EXPECT_EQ(NULL, frame1->windows_frame_info); + EXPECT_EQ(nullptr, frame1->windows_frame_info); } } @@ -340,7 +343,7 @@ TEST_F(GetCallerFrame, TraditionalScan) { EXPECT_EQ(0x4000f49dU, frame0->context.eip); EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); EXPECT_EQ(0xd43eed6eU, frame0->context.ebp); - EXPECT_EQ(NULL, frame0->windows_frame_info); + EXPECT_EQ(nullptr, frame0->windows_frame_info); } { // To avoid reusing locals by mistake @@ -354,7 +357,7 @@ TEST_F(GetCallerFrame, TraditionalScan) { EXPECT_EQ(0x4000129dU, frame1->context.eip); EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); - EXPECT_EQ(NULL, frame1->windows_frame_info); + EXPECT_EQ(nullptr, frame1->windows_frame_info); } } @@ -406,7 +409,7 @@ TEST_F(GetCallerFrame, TraditionalScanLongWay) { EXPECT_EQ(0x4000f49dU, frame0->context.eip); EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); EXPECT_EQ(0xd43eed6eU, frame0->context.ebp); - EXPECT_EQ(NULL, frame0->windows_frame_info); + EXPECT_EQ(nullptr, frame0->windows_frame_info); } { // To avoid reusing locals by mistake @@ -420,7 +423,7 @@ TEST_F(GetCallerFrame, TraditionalScanLongWay) { EXPECT_EQ(0x4000129dU, frame1->context.eip); EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); - EXPECT_EQ(NULL, frame1->windows_frame_info); + EXPECT_EQ(nullptr, frame1->windows_frame_info); } } @@ -472,7 +475,7 @@ TEST_F(GetCallerFrame, ScanningNotAllowed) { EXPECT_EQ(0x4000f49dU, frame0->context.eip); EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); EXPECT_EQ(0xd43eed6eU, frame0->context.ebp); - EXPECT_EQ(NULL, frame0->windows_frame_info); + EXPECT_EQ(nullptr, frame0->windows_frame_info); } } @@ -531,7 +534,7 @@ TEST_F(GetCallerFrame, WindowsFrameData) { EXPECT_EQ(0x4000aa85U, frame0->context.eip); EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); EXPECT_EQ(0xf052c1deU, frame0->context.ebp); - EXPECT_TRUE(frame0->windows_frame_info != NULL); + EXPECT_TRUE(frame0->windows_frame_info != nullptr); } { // To avoid reusing locals by mistake @@ -551,7 +554,7 @@ TEST_F(GetCallerFrame, WindowsFrameData) { EXPECT_EQ(0x9068a878U, frame1->context.ebx); EXPECT_EQ(0xa7120d1aU, frame1->context.esi); EXPECT_EQ(0x630891beU, frame1->context.edi); - EXPECT_EQ(NULL, frame1->windows_frame_info); + EXPECT_EQ(nullptr, frame1->windows_frame_info); } } @@ -612,7 +615,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataAligned) { EXPECT_EQ(0x4000aa85U, frame0->context.eip); EXPECT_EQ(frame0_esp.Value(), frame0->context.esp); EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); - EXPECT_TRUE(frame0->windows_frame_info != NULL); + EXPECT_TRUE(frame0->windows_frame_info != nullptr); } { // To avoid reusing locals by mistake @@ -626,7 +629,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataAligned) { EXPECT_EQ(0x5000129dU, frame1->context.eip); EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); - EXPECT_EQ(NULL, frame1->windows_frame_info); + EXPECT_EQ(nullptr, frame1->windows_frame_info); } } @@ -705,7 +708,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) { EXPECT_EQ(0x40001000U, frame0->function_base); // The FUNC record for module1::wheedle should have produced a // WindowsFrameInfo structure with only the parameter size valid. - ASSERT_TRUE(frame0->windows_frame_info != NULL); + ASSERT_TRUE(frame0->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_PARAMETER_SIZE, frame0->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_UNKNOWN, @@ -727,7 +730,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) { EXPECT_EQ(&module2, frame1->module); EXPECT_EQ("module2::whine", frame1->function_name); EXPECT_EQ(0x5000aa85U, frame1->function_base); - ASSERT_TRUE(frame1->windows_frame_info != NULL); + ASSERT_TRUE(frame1->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, frame1->windows_frame_info->type_); @@ -749,8 +752,8 @@ TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) { EXPECT_EQ(frame2_esp.Value(), frame2->context.esp); EXPECT_EQ(frame2_ebp.Value(), frame2->context.ebp); EXPECT_EQ(0x2558c7f3U, frame2->context.ebx); - EXPECT_EQ(NULL, frame2->module); - EXPECT_EQ(NULL, frame2->windows_frame_info); + EXPECT_EQ(nullptr, frame2->module); + EXPECT_EQ(nullptr, frame2->windows_frame_info); } } @@ -800,7 +803,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataScan) { EXPECT_EQ(0x40000c9cU, frame0->context.eip); EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); EXPECT_EQ(0x2ae314cdU, frame0->context.ebp); - EXPECT_TRUE(frame0->windows_frame_info != NULL); + EXPECT_TRUE(frame0->windows_frame_info != nullptr); } { // To avoid reusing locals by mistake @@ -817,7 +820,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataScan) { EXPECT_EQ(0x50007ce9U, frame1->instruction + 1); EXPECT_EQ(0x50007ce9U, frame1->context.eip); EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); - EXPECT_TRUE(frame1->windows_frame_info != NULL); + EXPECT_TRUE(frame1->windows_frame_info != nullptr); } } @@ -889,7 +892,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataBadEIPScan) { EXPECT_EQ(0x40000700U, frame0->context.eip); EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); - EXPECT_TRUE(frame0->windows_frame_info != NULL); + EXPECT_TRUE(frame0->windows_frame_info != nullptr); } { // To avoid reusing locals by mistake @@ -907,7 +910,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataBadEIPScan) { EXPECT_EQ(0x5000d000U, frame1->context.eip); EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); - EXPECT_TRUE(frame1->windows_frame_info != NULL); + EXPECT_TRUE(frame1->windows_frame_info != nullptr); } } @@ -968,7 +971,7 @@ TEST_F(GetCallerFrame, WindowsFPOUnchangedEBP) { EXPECT_EQ(0x4000e8a8U, frame0->function_base); // The STACK WIN record for module1::discombobulated should have // produced a fully populated WindowsFrameInfo structure. - ASSERT_TRUE(frame0->windows_frame_info != NULL); + ASSERT_TRUE(frame0->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO, frame0->windows_frame_info->type_); @@ -989,7 +992,7 @@ TEST_F(GetCallerFrame, WindowsFPOUnchangedEBP) { EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); EXPECT_EQ(&module1, frame1->module); EXPECT_EQ("", frame1->function_name); - EXPECT_EQ(NULL, frame1->windows_frame_info); + EXPECT_EQ(nullptr, frame1->windows_frame_info); } } @@ -1051,7 +1054,7 @@ TEST_F(GetCallerFrame, WindowsFPOUsedEBP) { EXPECT_EQ(0x40009aa8U, frame0->function_base); // The STACK WIN record for module1::RaisedByTheAliens should have // produced a fully populated WindowsFrameInfo structure. - ASSERT_TRUE(frame0->windows_frame_info != NULL); + ASSERT_TRUE(frame0->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO, frame0->windows_frame_info->type_); @@ -1072,7 +1075,7 @@ TEST_F(GetCallerFrame, WindowsFPOUsedEBP) { EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); EXPECT_EQ(&module1, frame1->module); EXPECT_EQ("", frame1->function_name); - EXPECT_EQ(NULL, frame1->windows_frame_info); + EXPECT_EQ(nullptr, frame1->windows_frame_info); } } @@ -1329,7 +1332,7 @@ TEST_F(GetCallerFrame, WindowsFPOSystemCall) { EXPECT_EQ("ZwWaitForSingleObject", frame0->function_name); // The STACK WIN record for module3!ZwWaitForSingleObject should have // produced a fully populated WindowsFrameInfo structure. - ASSERT_TRUE(frame0->windows_frame_info != NULL); + ASSERT_TRUE(frame0->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO, frame0->windows_frame_info->type_); @@ -1353,7 +1356,7 @@ TEST_F(GetCallerFrame, WindowsFPOSystemCall) { EXPECT_EQ("WaitForSingleObjectEx", frame1->function_name); // The STACK WIN record for module4!WaitForSingleObjectEx should have // produced a fully populated WindowsFrameInfo structure. - ASSERT_TRUE(frame1->windows_frame_info != NULL); + ASSERT_TRUE(frame1->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, frame1->windows_frame_info->type_); @@ -1541,7 +1544,7 @@ TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) { EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); EXPECT_EQ(&msvcrt_dll, frame0->module); EXPECT_EQ("wcsstr", frame0->function_name); - ASSERT_TRUE(frame0->windows_frame_info != NULL); + ASSERT_TRUE(frame0->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, frame0->windows_frame_info->type_); @@ -1566,7 +1569,7 @@ TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) { EXPECT_EQ(frame2_ebp.Value(), frame1->context.ebp); EXPECT_EQ(&kernel32_dll, frame1->module); EXPECT_EQ("FindNextFileW", frame1->function_name); - ASSERT_TRUE(frame1->windows_frame_info != NULL); + ASSERT_TRUE(frame1->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, frame1->windows_frame_info->type_); @@ -1590,7 +1593,7 @@ TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) { EXPECT_EQ(frame3_ebp.Value(), frame2->context.ebp); EXPECT_EQ(&chrome_dll, frame2->module); EXPECT_EQ("file_util::FileEnumerator::Next()", frame2->function_name); - ASSERT_TRUE(frame2->windows_frame_info != NULL); + ASSERT_TRUE(frame2->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame2->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, frame2->windows_frame_info->type_); @@ -1744,7 +1747,7 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) { EXPECT_EQ(frame0_esp.Value(), frame->context.esp); EXPECT_EQ(frame0_ebp.Value(), frame->context.ebp); EXPECT_EQ(&chrome_dll, frame->module); - ASSERT_TRUE(frame->windows_frame_info != NULL); + ASSERT_TRUE(frame->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, frame->windows_frame_info->type_); @@ -1769,7 +1772,7 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) { EXPECT_EQ(frame1_esp.Value(), frame->context.esp); EXPECT_EQ(frame1_ebp.Value(), frame->context.ebp); EXPECT_EQ(&chrome_dll, frame->module); - ASSERT_TRUE(frame->windows_frame_info != NULL); + ASSERT_TRUE(frame->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, frame->windows_frame_info->type_); @@ -1791,7 +1794,7 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) { EXPECT_EQ(frame2_esp.Value(), frame->context.esp); EXPECT_EQ(frame2_ebp.Value(), frame->context.ebp); EXPECT_EQ(&chrome_dll, frame->module); - ASSERT_TRUE(frame->windows_frame_info != NULL); + ASSERT_TRUE(frame->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, frame->windows_frame_info->type_); @@ -1990,9 +1993,9 @@ void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl( EXPECT_EQ(raw_context.eip, frame0->context.eip); EXPECT_EQ(raw_context.ebp, frame0->context.ebp); EXPECT_EQ(raw_context.esp, frame0->context.esp); - EXPECT_EQ(NULL, frame0->module); // IP not in known module + EXPECT_EQ(nullptr, frame0->module); // IP not in known module EXPECT_EQ("", frame0->function_name); - ASSERT_EQ(NULL, frame0->windows_frame_info); + ASSERT_EQ(nullptr, frame0->windows_frame_info); } { // To avoid reusing locals by mistake @@ -2006,7 +2009,7 @@ void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl( EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); EXPECT_EQ(&remoting_core_dll, frame1->module); EXPECT_EQ("nsc_ECDSAVerifyStub", frame1->function_name); - ASSERT_TRUE(frame1->windows_frame_info != NULL); + ASSERT_TRUE(frame1->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, frame1->windows_frame_info->type_); @@ -2026,7 +2029,7 @@ void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl( EXPECT_EQ(frame2_esp.Value(), frame2->context.esp); EXPECT_EQ(&remoting_core_dll, frame2->module); EXPECT_EQ("NSC_Verify", frame2->function_name); - ASSERT_TRUE(frame2->windows_frame_info != NULL); + ASSERT_TRUE(frame2->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame2->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, frame2->windows_frame_info->type_); @@ -2046,7 +2049,7 @@ void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl( EXPECT_EQ(frame3_esp.Value(), frame3->context.esp); EXPECT_EQ(&remoting_core_dll, frame3->module); EXPECT_EQ("PK11_Verify", frame3->function_name); - ASSERT_TRUE(frame3->windows_frame_info != NULL); + ASSERT_TRUE(frame3->windows_frame_info != nullptr); EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame3->windows_frame_info->valid); EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, frame3->windows_frame_info->type_); @@ -2131,10 +2134,10 @@ struct CFIFixture: public StackwalkerX86Fixture { ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ("enchiridion", frame0->function_name); EXPECT_EQ(0x40004000U, frame0->function_base); - ASSERT_TRUE(frame0->windows_frame_info != NULL); + ASSERT_TRUE(frame0->windows_frame_info != nullptr); ASSERT_EQ(WindowsFrameInfo::VALID_PARAMETER_SIZE, frame0->windows_frame_info->valid); - ASSERT_TRUE(frame0->cfi_frame_info != NULL); + ASSERT_TRUE(frame0->cfi_frame_info != nullptr); } { // To avoid reusing locals by mistake diff --git a/src/processor/static_address_map-inl.h b/src/processor/static_address_map-inl.h index 9d2c1defb..0dd13f840 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. // diff --git a/src/processor/static_address_map.h b/src/processor/static_address_map.h index 9d1a467b0..156ecd635 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. // diff --git a/src/processor/static_address_map_unittest.cc b/src/processor/static_address_map_unittest.cc index 9f1215d6a..7626a0546 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. // @@ -31,9 +30,16 @@ // // Author: Siyang Xie (lambxsy@google.com) -#include -#include -#include +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "processor/static_address_map-inl.h" + +#include +#include +#include + #include #include #include @@ -41,7 +47,6 @@ #include "breakpad_googletest_includes.h" #include "common/using_std_string.h" #include "processor/address_map-inl.h" -#include "processor/static_address_map-inl.h" #include "processor/simple_serializer-inl.h" #include "map_serializers-inl.h" @@ -66,7 +71,7 @@ class TestStaticAddressMap : public ::testing::Test { testdata[2][i] = tempdata[i]; // Test data set3: - srand(time(NULL)); + srand(time(nullptr)); for (int i = 0; i < testsize[3]; ++i) testdata[3][i] = rand(); @@ -78,7 +83,7 @@ class TestStaticAddressMap : public ::testing::Test { sstream << "test " << testdata[testcase][data_item]; addr_map[testcase].Store(testdata[testcase][data_item], sstream.str()); } - map_data[testcase] = serializer.Serialize(addr_map[testcase], NULL); + map_data[testcase] = serializer.Serialize(addr_map[testcase], nullptr); test_map[testcase] = TestMap(map_data[testcase]); } } @@ -95,7 +100,7 @@ class TestStaticAddressMap : public ::testing::Test { int address_test; string entry; string entry_test; - const char* entry_cstring = NULL; + const char* entry_cstring = nullptr; bool found; bool found_test; @@ -121,7 +126,7 @@ class TestStaticAddressMap : public ::testing::Test { srand(time(0)); for (int data_item = 0; data_item < testsize[testcase]; ++data_item) { - // Retrive (aka, search) for target address and compare results from + // Retrieve (aka, search) for target address and compare results from // AddressMap and StaticAddressMap. // First, assign the search target to be one of original testdata that is diff --git a/src/processor/static_contained_range_map-inl.h b/src/processor/static_contained_range_map-inl.h index 87ea6c7f5..78a2fc15c 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. // @@ -46,12 +45,12 @@ template StaticContainedRangeMap::StaticContainedRangeMap( const char *base) : base_(*(reinterpret_cast(base))), - entry_size_(*(reinterpret_cast(base + sizeof(base_)))), + entry_size_(*(reinterpret_cast(base + sizeof(base_)))), entry_ptr_(reinterpret_cast( base + sizeof(base_) + sizeof(entry_size_))), map_(base + sizeof(base_) + sizeof(entry_size_) + entry_size_) { if (entry_size_ == 0) - entry_ptr_ = NULL; + entry_ptr_ = nullptr; } @@ -87,6 +86,23 @@ bool StaticContainedRangeMap::RetrieveRange( return true; } +template +bool StaticContainedRangeMap::RetrieveRanges( + const AddressType& address, + std::vector& entries) const { + MapConstIterator iterator = map_.lower_bound(address); + if (iterator == map_.end()) + return false; + const char* memory_child = + reinterpret_cast(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 14fa5e95e..eea03db72 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 #include "processor/static_map-inl.h" namespace google_breakpad { @@ -59,6 +59,11 @@ class StaticContainedRangeMap { // encompasses the address, returns false. 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& entry) const; + private: friend class ModuleComparer; // AddressToRangeMap stores pointers. This makes reparenting simpler in @@ -81,7 +86,7 @@ class StaticContainedRangeMap { // actually contain an entry, so its entry_ field is meaningless. For // this reason, the entry_ field should only be accessed on child // ContainedRangeMap objects, and never on |this|. - uint32_t entry_size_; + uint64_t entry_size_; const EntryType *entry_ptr_; // The map containing child ranges, keyed by each child range's high diff --git a/src/processor/static_contained_range_map_unittest.cc b/src/processor/static_contained_range_map_unittest.cc index 4ee47578e..261529e60 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. // @@ -32,10 +31,19 @@ // // Author: Siyang Xie (lambxsy@google.com) +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "processor/static_contained_range_map-inl.h" + +#include + +#include + #include "breakpad_googletest_includes.h" #include "common/scoped_ptr.h" #include "processor/contained_range_map-inl.h" -#include "processor/static_contained_range_map-inl.h" #include "processor/simple_serializer-inl.h" #include "processor/map_serializers-inl.h" #include "processor/logging.h" @@ -158,7 +166,7 @@ class TestStaticCRMMap : public ::testing::Test { protected: void SetUp(); - // A referrence map for testing StaticCRMMap. + // A reference map for testing StaticCRMMap. google_breakpad::ContainedRangeMap crm_map_; // Static version of crm_map using serialized data of crm_map. @@ -174,7 +182,7 @@ class TestStaticCRMMap : public ::testing::Test { void TestStaticCRMMap::SetUp() { // First, do the StoreRange tests. This validates the containment // rules. - // We confirm the referrence map correctly stores data during setup. + // We confirm the reference map correctly stores data during setup. ASSERT_TRUE (crm_map_.StoreRange(10, 10, 1)); ASSERT_FALSE(crm_map_.StoreRange(10, 10, 2)); // exactly equal to 1 ASSERT_FALSE(crm_map_.StoreRange(11, 10, 3)); // begins inside 1 and extends up @@ -225,7 +233,7 @@ void TestStaticCRMMap::SetUp() { ASSERT_FALSE(crm_map_.StoreRange(86, 2, 48)); // Serialize crm_map to generate serialized data. - unsigned int size; + uint64_t size; serialized_data_.reset(serializer_.Serialize(&crm_map_, &size)); BPLOG(INFO) << "Serialized data size: " << size << " Bytes."; @@ -236,12 +244,12 @@ void TestStaticCRMMap::SetUp() { TEST_F(TestStaticCRMMap, TestEmptyMap) { CRMMap empty_crm_map; - unsigned int size; + uint64_t size; scoped_array serialized_data; serialized_data.reset(serializer_.Serialize(&empty_crm_map, &size)); - scoped_ptr test_map(new TestMap(serialized_data.get())); + std::unique_ptr test_map(new TestMap(serialized_data.get())); - const unsigned int kCorrectSizeForEmptyMap = 16; + const unsigned int kCorrectSizeForEmptyMap = 24; ASSERT_EQ(kCorrectSizeForEmptyMap, size); const int *entry_test; @@ -256,12 +264,12 @@ TEST_F(TestStaticCRMMap, TestSingleElementMap) { int entry = 1; crm_map.StoreRange(10, 10, entry); - unsigned int size; + uint64_t size; scoped_array serialized_data; serialized_data.reset(serializer_.Serialize(&crm_map, &size)); - scoped_ptr test_map(new TestMap(serialized_data.get())); + std::unique_ptr test_map(new TestMap(serialized_data.get())); - const unsigned int kCorrectSizeForSingleElementMap = 40; + const unsigned int kCorrectSizeForSingleElementMap = 60; ASSERT_EQ(kCorrectSizeForSingleElementMap, size); const int *entry_test; @@ -273,6 +281,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); + + uint64_t size; + scoped_array serialized_data; + serialized_data.reset(serializer_.Serialize(&crm_map, &size)); + std::unique_ptr test_map(new TestMap(serialized_data.get())); + + std::vector 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 75a8a335a..2e827b9f7 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. // @@ -47,23 +47,23 @@ StaticMap::StaticMap(const char* raw_data) : raw_data_(raw_data), compare_() { // First 4 Bytes store the number of nodes. - num_nodes_ = *(reinterpret_cast(raw_data_)); + num_nodes_ = *(reinterpret_cast(raw_data_)); - offsets_ = reinterpret_cast( + offsets_ = reinterpret_cast( raw_data_ + sizeof(num_nodes_)); keys_ = reinterpret_cast( - raw_data_ + (1 + num_nodes_) * sizeof(uint32_t)); + raw_data_ + (1 + num_nodes_) * sizeof(uint64_t)); } // find(), lower_bound() and upper_bound() implement binary search algorithm. template StaticMapIterator StaticMap::find(const Key& key) const { - int begin = 0; - int end = num_nodes_; - int middle; - int compare_result; + int64_t begin = 0; + int64_t end = num_nodes_; + int64_t middle; + int64_t compare_result; while (begin < end) { middle = begin + (end - begin) / 2; compare_result = compare_(key, GetKeyAtIndex(middle)); @@ -81,10 +81,10 @@ StaticMap::find(const Key& key) const { template StaticMapIterator StaticMap::lower_bound(const Key& key) const { - int begin = 0; - int end = num_nodes_; - int middle; - int comp_result; + int64_t begin = 0; + int64_t end = num_nodes_; + int64_t middle; + int64_t comp_result; while (begin < end) { middle = begin + (end - begin) / 2; comp_result = compare_(key, GetKeyAtIndex(middle)); @@ -102,10 +102,10 @@ StaticMap::lower_bound(const Key& key) const { template StaticMapIterator StaticMap::upper_bound(const Key& key) const { - int begin = 0; - int end = num_nodes_; - int middle; - int compare_result; + int64_t begin = 0; + int64_t end = num_nodes_; + int64_t middle; + int64_t compare_result; while (begin < end) { middle = begin + (end - begin) / 2; compare_result = compare_(key, GetKeyAtIndex(middle)); @@ -124,22 +124,22 @@ template bool StaticMap::ValidateInMemoryStructure() const { // check the number of nodes is non-negative: if (!raw_data_) return false; - int32_t num_nodes = *(reinterpret_cast(raw_data_)); + int64_t num_nodes = *(reinterpret_cast(raw_data_)); if (num_nodes < 0) { BPLOG(INFO) << "StaticMap check failed: negative number of nodes"; return false; } - int node_index = 0; + int64_t node_index = 0; if (num_nodes_) { - uint64_t first_offset = sizeof(int32_t) * (num_nodes_ + 1) + uint64_t first_offset = sizeof(int64_t) * (num_nodes_ + 1) + sizeof(Key) * num_nodes_; // Num_nodes_ is too large. if (first_offset > 0xffffffffUL) { BPLOG(INFO) << "StaticMap check failed: size exceeds limit"; return false; } - if (offsets_[node_index] != static_cast(first_offset)) { + if (offsets_[node_index] != static_cast(first_offset)) { BPLOG(INFO) << "StaticMap check failed: first node offset is incorrect"; return false; } @@ -162,7 +162,7 @@ bool StaticMap::ValidateInMemoryStructure() const { } template -const Key StaticMap::GetKeyAtIndex(int index) const { +const Key StaticMap::GetKeyAtIndex(int64_t index) const { if (index < 0 || index >= num_nodes_) { BPLOG(ERROR) << "Key index out of range error"; // Key type is required to be primitive type. Return 0 if index is invalid. diff --git a/src/processor/static_map.h b/src/processor/static_map.h index e7d8c9600..be2c7d55a 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. // @@ -34,11 +34,11 @@ // // The chunk of memory should contain data with pre-defined pattern: // **************** header *************** -// uint32 (4 bytes): number of nodes -// uint32 (4 bytes): address offset of node1's mapped_value -// uint32 (4 bytes): address offset of node2's mapped_value +// int64 (8 bytes): number of nodes +// uint64 (8 bytes): address offset of node1's mapped_value +// uint64 (8 bytes): address offset of node2's mapped_value // ... -// uint32 (4 bytes): address offset of nodeN's mapped_value +// uint64 (8 bytes): address offset of nodeN's mapped_value // // ************* Key array ************ // (X bytes): node1's key @@ -54,9 +54,6 @@ // // REQUIREMENT: Key type MUST be primitive type or pointers so that: // X = sizeof(typename Key); -// -// Note: since address offset is stored as uint32, user should keep in mind that -// StaticMap only supports up to 4GB size of memory data. // Author: Siyang Xie (lambxsy@google.com) @@ -72,7 +69,7 @@ namespace google_breakpad { template class DefaultCompare { public: - int operator()(const Key& k1, const Key& k2) const { + int64_t operator()(const Key& k1, const Key& k2) const { if (k1 < k2) return -1; if (k1 == k2) return 0; return 1; @@ -93,13 +90,13 @@ class StaticMap { explicit StaticMap(const char* raw_data); inline bool empty() const { return num_nodes_ == 0; } - inline unsigned int size() const { return num_nodes_; } + inline uint64_t size() const { return num_nodes_; } // Return iterators. inline iterator begin() const { return IteratorAtIndex(0); } inline iterator last() const { return IteratorAtIndex(num_nodes_ - 1); } inline iterator end() const { return IteratorAtIndex(num_nodes_); } - inline iterator IteratorAtIndex(int index) const { + inline iterator IteratorAtIndex(int64_t index) const { return iterator(raw_data_, index); } @@ -120,18 +117,18 @@ class StaticMap { bool ValidateInMemoryStructure() const; private: - const Key GetKeyAtIndex(int i) const; + const Key GetKeyAtIndex(int64_t i) const; // Start address of a raw memory chunk with serialized data. const char* raw_data_; // Number of nodes in the static map. - int32_t num_nodes_; + int64_t num_nodes_; // Array of offset addresses for stored values. // For example: // address_of_i-th_node_value = raw_data_ + offsets_[i] - const uint32_t* offsets_; + const uint64_t* offsets_; // keys_[i] = key of i_th node const Key* keys_; diff --git a/src/processor/static_map_iterator-inl.h b/src/processor/static_map_iterator-inl.h index 84745842c..1e1d417ec 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,12 +43,12 @@ namespace google_breakpad { template StaticMapIterator::StaticMapIterator(const char* base, - const int& index): + int64_t index): index_(index), base_(base) { // See static_map.h for documentation on // bytes format of serialized StaticMap data. - num_nodes_ = *(reinterpret_cast(base_)); - offsets_ = reinterpret_cast(base_ + sizeof(num_nodes_)); + num_nodes_ = *(reinterpret_cast(base_)); + offsets_ = reinterpret_cast(base_ + sizeof(num_nodes_)); keys_ = reinterpret_cast( base_ + (1 + num_nodes_) * sizeof(num_nodes_)); } @@ -106,7 +106,7 @@ template const Key* StaticMapIterator::GetKeyPtr() const { if (!IsValid()) { BPLOG(ERROR) << "call GetKeyPtr() on invalid iterator"; - return NULL; + return nullptr; } return &(keys_[index_]); } @@ -115,7 +115,7 @@ template const char* StaticMapIterator::GetValueRawPtr() const { if (!IsValid()) { BPLOG(ERROR) << "call GetValuePtr() on invalid iterator"; - return NULL; + return nullptr; } return base_ + offsets_[index_]; } diff --git a/src/processor/static_map_iterator.h b/src/processor/static_map_iterator.h index c49a8b71b..53d7c5d77 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. // @@ -52,7 +52,7 @@ template class StaticMapIterator { public: // Constructors. - StaticMapIterator(): index_(-1), base_(NULL) { } + StaticMapIterator(): index_(-1), base_(nullptr) { } // Increment & Decrement operators: StaticMapIterator& operator++(); @@ -87,21 +87,21 @@ class StaticMapIterator { friend class StaticMap; // Only StaticMap can call this constructor. - explicit StaticMapIterator(const char* base, const int32_t& index); + explicit StaticMapIterator(const char* base, int64_t index); // Index of node that the iterator is pointing to. - int32_t index_; + int64_t index_; // Beginning address of the serialized map data. const char* base_; // Number of nodes in the map. Use it to identify end() iterator. - int32_t num_nodes_; + int64_t num_nodes_; // offsets_ is an array of offset addresses of mapped values. // For example: // address_of_i-th_node_value = base_ + offsets_[i] - const uint32_t* offsets_; + const uint64_t* offsets_; // keys_[i] = key of i_th node. const Key* keys_; diff --git a/src/processor/static_map_unittest.cc b/src/processor/static_map_unittest.cc index d17153d96..7ad9bb85c 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. // @@ -31,12 +30,18 @@ // // Author: Siyang Xie (lambxsy@google.com) -#include -#include +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif -#include "breakpad_googletest_includes.h" #include "processor/static_map-inl.h" +#include +#include + +#include + +#include "breakpad_googletest_includes.h" typedef int ValueType; typedef int KeyType; @@ -47,10 +52,10 @@ template class SimpleMapSerializer { public: static char* Serialize(const std::map& stdmap, - unsigned int* size = NULL) { + unsigned int* size = nullptr) { unsigned int size_per_node = - sizeof(uint32_t) + sizeof(Key) + sizeof(Value); - unsigned int memsize = sizeof(int32_t) + size_per_node * stdmap.size(); + sizeof(uint64_t) + sizeof(Key) + sizeof(Value); + unsigned int memsize = sizeof(int64_t) + size_per_node * stdmap.size(); if (size) *size = memsize; // Allocate memory for serialized data: @@ -58,12 +63,12 @@ class SimpleMapSerializer { char* address = mem; // Writer the number of nodes: - new (address) uint32_t(static_cast(stdmap.size())); - address += sizeof(uint32_t); + new (address) uint64_t(static_cast(stdmap.size())); + address += sizeof(uint64_t); // Nodes' offset: - uint32_t* offsets = reinterpret_cast(address); - address += sizeof(uint32_t) * stdmap.size(); + uint64_t* offsets = reinterpret_cast(address); + address += sizeof(uint64_t) * stdmap.size(); // Keys: Key* keys = reinterpret_cast(address); @@ -95,16 +100,16 @@ class TestInvalidMap : public ::testing::Test { }; TEST_F(TestInvalidMap, TestNegativeNumberNodes) { - memset(data, 0xff, sizeof(uint32_t)); // Set the number of nodes = -1 + memset(data, 0xff, sizeof(uint64_t)); // Set the number of nodes = -1 test_map = TestMap(data); ASSERT_FALSE(test_map.ValidateInMemoryStructure()); } TEST_F(TestInvalidMap, TestWrongOffsets) { - uint32_t* header = reinterpret_cast(data); - const uint32_t kNumNodes = 2; - const uint32_t kHeaderOffset = - sizeof(uint32_t) + kNumNodes * (sizeof(uint32_t) + sizeof(KeyType)); + uint64_t* header = reinterpret_cast(data); + const uint64_t kNumNodes = 2; + const uint64_t kHeaderOffset = + sizeof(uint64_t) + kNumNodes * (sizeof(uint64_t) + sizeof(KeyType)); header[0] = kNumNodes; header[1] = kHeaderOffset + 3; // Wrong offset for first node @@ -118,16 +123,16 @@ TEST_F(TestInvalidMap, TestWrongOffsets) { } TEST_F(TestInvalidMap, TestUnSortedKeys) { - uint32_t* header = reinterpret_cast(data); - const uint32_t kNumNodes = 2; - const uint32_t kHeaderOffset = - sizeof(uint32_t) + kNumNodes * (sizeof(uint32_t) + sizeof(KeyType)); + uint64_t* header = reinterpret_cast(data); + const uint64_t kNumNodes = 2; + const uint64_t kHeaderOffset = + sizeof(uint64_t) + kNumNodes * (sizeof(uint64_t) + sizeof(KeyType)); header[0] = kNumNodes; header[1] = kHeaderOffset; header[2] = kHeaderOffset + sizeof(ValueType); KeyType* keys = reinterpret_cast( - data + (kNumNodes + 1) * sizeof(uint32_t)); + data + (kNumNodes + 1) * sizeof(uint64_t)); // Set keys in non-increasing order. keys[0] = 10; keys[1] = 7; @@ -171,10 +176,10 @@ class TestValidMap : public ::testing::Test { // Set correct size of memory allocation for each test case. unsigned int size_per_node = - sizeof(uint32_t) + sizeof(KeyType) + sizeof(ValueType); + sizeof(uint64_t) + sizeof(KeyType) + sizeof(ValueType); for (testcase = 0; testcase < kNumberTestCases; ++testcase) { correct_size[testcase] = - sizeof(uint32_t) + std_map[testcase].size() * size_per_node; + sizeof(uint64_t) + std_map[testcase].size() * size_per_node; } } diff --git a/src/processor/static_range_map-inl.h b/src/processor/static_range_map-inl.h index 37fb6fae4..3ffeec975 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. // @@ -103,7 +102,7 @@ bool StaticRangeMap::RetrieveNearestRange( template bool StaticRangeMap::RetrieveRangeAtIndex( - int index, const EntryType*& entry, + int64_t index, const EntryType*& entry, AddressType* entry_base, AddressType* entry_size) const { if (index >= GetCount()) { diff --git a/src/processor/static_range_map.h b/src/processor/static_range_map.h index ea89fae4a..c63d2fa94 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. // @@ -74,12 +73,12 @@ class StaticRangeMap { // range. // // RetrieveRangeAtIndex is not optimized for speedy operation. - bool RetrieveRangeAtIndex(int index, const EntryType*& entry, + bool RetrieveRangeAtIndex(int64_t index, const EntryType*& entry, AddressType* entry_base, AddressType* entry_size) const; // Returns the number of ranges stored in the RangeMap. - inline int GetCount() const { return map_.size(); } + inline int64_t GetCount() const { return map_.size(); } private: friend class ModuleComparer; diff --git a/src/processor/static_range_map_unittest.cc b/src/processor/static_range_map_unittest.cc index 1593ed004..e7e65d1ca 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. // @@ -31,6 +30,12 @@ // // Author: Siyang Xie (lambxsy@google.com) +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + #include "breakpad_googletest_includes.h" #include "common/scoped_ptr.h" #include "processor/range_map-inl.h" @@ -228,10 +233,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) { @@ -319,7 +324,7 @@ void TestStaticRangeMap::RetrieveIndexTest(const TestMap* range_map, int set) { ASSERT_TRUE(range_map->RetrieveRangeAtIndex(object_index, entry, &base, - NULL)) + nullptr)) << "FAILED: RetrieveRangeAtIndex set " << set << " index " << object_index; @@ -343,16 +348,16 @@ void TestStaticRangeMap::RetrieveIndexTest(const TestMap* range_map, int set) { // Make sure that RetrieveRangeAtIndex doesn't allow lookups at indices that // are too high. ASSERT_FALSE(range_map->RetrieveRangeAtIndex( - object_count, entry, NULL, NULL)) << "FAILED: RetrieveRangeAtIndex set " - << set << " index " << object_count - << " (too large)"; + object_count, entry, nullptr, nullptr)) << "FAILED: RetrieveRangeAtIndex " + << "set " << set << " index " + << object_count << " (too large)"; } // RunTests runs a series of test sets. void TestStaticRangeMap::RunTestCase(int test_case) { // Maintain the range map in a pointer so that deletion can be meaningfully // tested. - scoped_ptr rmap(new RMap()); + std::unique_ptr rmap(new RMap()); const RangeTest* range_tests = range_test_sets[test_case].range_tests; unsigned int range_test_count = range_test_sets[test_case].range_test_count; @@ -370,8 +375,8 @@ void TestStaticRangeMap::RunTestCase(int test_case) { ++stored_count; } - scoped_array memaddr(serializer_.Serialize(*rmap, NULL)); - scoped_ptr static_range_map(new TestMap(memaddr.get())); + scoped_array memaddr(serializer_.Serialize(*rmap, nullptr)); + std::unique_ptr static_range_map(new TestMap(memaddr.get())); // The RangeMap's own count of objects should also match. EXPECT_EQ(static_range_map->GetCount(), stored_count); diff --git a/src/processor/symbolic_constants_win.cc b/src/processor/symbolic_constants_win.cc index 8cf283f6a..98c2b4dde 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. // @@ -33,6 +32,10 @@ // // Author: Ben Wagner +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "common/stdio_wrapper.h" diff --git a/src/processor/symbolic_constants_win.h b/src/processor/symbolic_constants_win.h index 3f4d38eb2..bc9ff3500 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 da61afc4b..3356ee7c0 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. // @@ -31,8 +30,14 @@ // synth_minidump.cc: Implementation of SynthMinidump. See synth_minidump.h +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "processor/synth_minidump.h" +#include + namespace google_breakpad { namespace SynthMinidump { diff --git a/src/processor/synth_minidump.h b/src/processor/synth_minidump.h index 2da4d5fe9..b747f2328 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. // @@ -260,8 +259,8 @@ class Module: public Section { 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 Section* cv_record = nullptr, + const Section* misc_record = nullptr); private: // A standard MDVSFixedFileInfo structure to use as a default for diff --git a/src/processor/synth_minidump_unittest.cc b/src/processor/synth_minidump_unittest.cc index 8835b4493..e19fc51cd 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. // @@ -32,6 +31,12 @@ // synth_minidump_unittest.cc: Unit tests for google_breakpad::SynthMinidump // classes. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + #include #include @@ -144,7 +149,12 @@ TEST(Context, ARM) { == 0); } +#if GTEST_OS_WINDOWS && !GTEST_HAS_ABSL +// GTest on Windows does not support complex regular expressions. +TEST(ContextDeathTest, DISABLED_X86BadFlags) { +#else TEST(ContextDeathTest, X86BadFlags) { +#endif Dump dump(0, kLittleEndian); MDRawContextX86 raw; raw.context_flags = MD_CONTEXT_AMD64; @@ -152,7 +162,12 @@ TEST(ContextDeathTest, X86BadFlags) { "context\\.context_flags & (0x[0-9a-f]+|MD_CONTEXT_X86)"); } +#if GTEST_OS_WINDOWS && !GTEST_HAS_ABSL +// GTest on Windows does not support complex regular expressions. +TEST(ContextDeathTest, DISABLED_X86BadEndianness) { +#else TEST(ContextDeathTest, X86BadEndianness) { +#endif Dump dump(0, kBigEndian); MDRawContextX86 raw; raw.context_flags = MD_CONTEXT_X86; diff --git a/src/processor/testdata/linux_inline.dmp b/src/processor/testdata/linux_inline.dmp new file mode 100644 index 000000000..5b216f8b8 Binary files /dev/null and b/src/processor/testdata/linux_inline.dmp differ diff --git a/src/processor/testdata/linux_test_app.cc b/src/processor/testdata/linux_test_app.cc index 9df6dccca..fcf78247f 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. // @@ -39,6 +38,10 @@ // generate an executable with STABS symbols (needs -m32), or -gdwarf-2 for one // with DWARF symbols (32- or 64-bit) +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -72,7 +75,7 @@ static void CrashFunction() { } // namespace int main(int argc, char** argv) { - google_breakpad::ExceptionHandler eh(".", NULL, callback, NULL, true); + google_breakpad::ExceptionHandler eh(".", nullptr, callback, nullptr, 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 8585c89b3..bad1b80f2 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 new file mode 100644 index 000000000..00cfc5a3a Binary files /dev/null and b/src/processor/testdata/minidump_crashpad_annotation.dmp differ diff --git a/src/processor/testdata/module1.out b/src/processor/testdata/module1.out index cd6e18d10..6774e4f1e 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 000000000..5cd832097 --- /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 000000000..775640f0d --- /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 c744a37a9..cd5eafd24 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. // @@ -32,6 +31,10 @@ // google_breakpad/src/client/windows/releasestaticcrt/exception_handler.lib // Then run test_app to generate a dump, and dump_syms to create the .sym file. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include "client/windows/handler/exception_handler.h" @@ -61,7 +64,7 @@ static void CrashFunction() { int main(int argc, char** argv) { google_breakpad::ExceptionHandler eh( - L".", NULL, callback, NULL, + L".", nullptr, callback, nullptr, google_breakpad::ExceptionHandler::HANDLER_ALL); CrashFunction(); printf("did not crash?\n"); diff --git a/src/processor/testdata/thread_name_list.dmp b/src/processor/testdata/thread_name_list.dmp new file mode 100644 index 000000000..fbe84b637 Binary files /dev/null and b/src/processor/testdata/thread_name_list.dmp differ diff --git a/src/processor/testdata/tiny-exe-fastfail.dmp b/src/processor/testdata/tiny-exe-fastfail.dmp new file mode 100644 index 000000000..f7a0a502b Binary files /dev/null and b/src/processor/testdata/tiny-exe-fastfail.dmp differ diff --git a/src/processor/testdata/tiny-exe-with-cet-xsave-x86.dmp b/src/processor/testdata/tiny-exe-with-cet-xsave-x86.dmp new file mode 100644 index 000000000..f5a08ca86 Binary files /dev/null and b/src/processor/testdata/tiny-exe-with-cet-xsave-x86.dmp differ diff --git a/src/processor/testdata/tiny-exe-with-cet-xsave.dmp b/src/processor/testdata/tiny-exe-with-cet-xsave.dmp new file mode 100644 index 000000000..9b641afb6 Binary files /dev/null and b/src/processor/testdata/tiny-exe-with-cet-xsave.dmp differ diff --git a/src/processor/testdata/write_av_non_canonical.dmp b/src/processor/testdata/write_av_non_canonical.dmp new file mode 100644 index 000000000..02da25eeb Binary files /dev/null and b/src/processor/testdata/write_av_non_canonical.dmp differ diff --git a/src/processor/tokenize.cc b/src/processor/tokenize.cc index 29e8125ab..87271c8f4 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. // @@ -27,8 +26,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include +#include #include #include @@ -58,11 +62,11 @@ bool Tokenize(char* line, while (token && --remaining > 0) { tokens->push_back(token); if (remaining > 1) - token = strtok_r(NULL, separators, &save_ptr); + token = strtok_r(nullptr, separators, &save_ptr); } // If there's anything left, just add it as a single token. - if (remaining == 0 && (token = strtok_r(NULL, "\r\n", &save_ptr))) { + if (remaining == 0 && (token = strtok_r(nullptr, "\r\n", &save_ptr))) { tokens->push_back(token); } diff --git a/src/processor/tokenize.h b/src/processor/tokenize.h index c4480aa80..b30c74155 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. // diff --git a/src/processor/windows_frame_info.h b/src/processor/windows_frame_info.h index 993832ad7..88e1b8bbe 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. // @@ -96,7 +95,7 @@ struct WindowsFrameInfo { uint32_t set_local_size, uint32_t set_max_stack_size, int set_allocates_base_pointer, - const string set_program_string) + const string& set_program_string) : type_(type), valid(VALID_ALL), prolog_size(set_prolog_size), @@ -112,7 +111,7 @@ struct WindowsFrameInfo { // a string. Returns NULL if parsing fails, or a new object // 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, + static WindowsFrameInfo *ParseFromString(const string& string, int& type, uint64_t& rva, uint64_t& code_size) { @@ -124,28 +123,28 @@ struct WindowsFrameInfo { StringToVector(string, buffer); std::vector tokens; if (!Tokenize(&buffer[0], " \r\n", 11, &tokens)) - return NULL; + return nullptr; - type = strtol(tokens[0], NULL, 16); + type = strtol(tokens[0], nullptr, 16); if (type < 0 || type > STACK_INFO_LAST - 1) - return NULL; - - rva = strtoull(tokens[1], NULL, 16); - code_size = strtoull(tokens[2], NULL, 16); - uint32_t prolog_size = strtoul(tokens[3], NULL, 16); - uint32_t epilog_size = strtoul(tokens[4], NULL, 16); - uint32_t parameter_size = strtoul(tokens[5], NULL, 16); - uint32_t saved_register_size = strtoul(tokens[6], NULL, 16); - uint32_t local_size = strtoul(tokens[7], NULL, 16); - uint32_t max_stack_size = strtoul(tokens[8], NULL, 16); - int has_program_string = strtoul(tokens[9], NULL, 16); + return nullptr; + + rva = strtoull(tokens[1], nullptr, 16); + code_size = strtoull(tokens[2], nullptr, 16); + uint32_t prolog_size = strtoul(tokens[3], nullptr, 16); + uint32_t epilog_size = strtoul(tokens[4], nullptr, 16); + uint32_t parameter_size = strtoul(tokens[5], nullptr, 16); + uint32_t saved_register_size = strtoul(tokens[6], nullptr, 16); + uint32_t local_size = strtoul(tokens[7], nullptr, 16); + uint32_t max_stack_size = strtoul(tokens[8], nullptr, 16); + int has_program_string = strtoul(tokens[9], nullptr, 16); const char *program_string = ""; int allocates_base_pointer = 0; if (has_program_string) { program_string = tokens[10]; } else { - allocates_base_pointer = strtoul(tokens[10], NULL, 16); + allocates_base_pointer = strtoul(tokens[10], nullptr, 16); } return new WindowsFrameInfo(static_cast(type), diff --git a/src/third_party/curl/curlbuild.h b/src/third_party/curl/curlbuild.h index 595df4e45..2fb1d0204 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/ia32_modrm.c b/src/third_party/libdisasm/ia32_modrm.c index b0fe2ed3d..c80c1b95e 100644 --- a/src/third_party/libdisasm/ia32_modrm.c +++ b/src/third_party/libdisasm/ia32_modrm.c @@ -2,6 +2,9 @@ #include "ia32_reg.h" #include "x86_imm.h" +#include +#include + /* NOTE: when decoding ModR/M and SIB, we have to add 1 to all register * values obtained from decoding the ModR/M or SIB byte, since they * are encoded with eAX = 0 and the tables in ia32_reg.c use eAX = 1. @@ -72,16 +75,18 @@ static unsigned int imm32_signsized( unsigned char *buf, size_t buf_len, return 0; } + int16_t local_short; switch (size) { case 1: *dest = *((signed char *) buf); break; case 2: - *dest = *((signed short *) buf); + memcpy(&local_short, buf, 2); + *dest = local_short; break; case 4: default: - *dest = *((signed int *) buf); + memcpy(dest, buf, 4); break; } diff --git a/src/third_party/libdisasm/libdisasm.gyp b/src/third_party/libdisasm/libdisasm.gyp deleted file mode 100644 index 5c8dc4586..000000000 --- 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/libdisasm/x86_format.c b/src/third_party/libdisasm/x86_format.c index 0ec960dc8..bb547ad4c 100644 --- a/src/third_party/libdisasm/x86_format.c +++ b/src/third_party/libdisasm/x86_format.c @@ -29,7 +29,7 @@ } while( 0 ) #define STRNCATF( buf, fmt, data, len ) do { \ - char _tmp[MAX_OP_STRING]; \ + char _tmp[MAX_OP_XML_STRING]; \ \ snprintf( _tmp, sizeof _tmp, fmt, data ); \ STRNCAT( buf, _tmp, len ); \ diff --git a/src/third_party/libdisasm/x86_imm.c b/src/third_party/libdisasm/x86_imm.c index cd59bfc9a..11c8a7de9 100644 --- a/src/third_party/libdisasm/x86_imm.c +++ b/src/third_party/libdisasm/x86_imm.c @@ -2,36 +2,15 @@ #include "x86_imm.h" #include +#include unsigned int x86_imm_signsized( unsigned char * buf, size_t buf_len, void *dest, unsigned int size ) { - signed char *cp = (signed char *) dest; - signed short *sp = (signed short *) dest; - int32_t *lp = (int32_t *) dest; - qword_t *qp = (qword_t *) dest; - if ( size > buf_len ) { return 0; } - /* Copy 'size' bytes from *buf to *op - * return number of bytes copied */ - switch (size) { - case 1: /* BYTE */ - *cp = *((signed char *) buf); - break; - case 2: /* WORD */ - *sp = *((signed short *) buf); - break; - case 6: - case 8: /* QWORD */ - *qp = *((qword_t *) buf); - break; - case 4: /* DWORD */ - default: - *lp = *((int32_t *) buf); - break; - } + memcpy(dest, buf, size); return (size); } diff --git a/src/third_party/linux/include/gflags/gflags_completions.h b/src/third_party/linux/include/gflags/gflags_completions.h index 9d9ce7a5f..fe06b47a3 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/mac_headers/README b/src/third_party/mac_headers/README index c681bb3d6..2b855b60c 100644 --- a/src/third_party/mac_headers/README +++ b/src/third_party/mac_headers/README @@ -1,2 +1,25 @@ -These headers were copied from the Mac OS X 10.7 SDK to enable building -the Mac dump_syms code that processes Mach-O files on Linux. +These headers were copied to enable building the Mac dump_syms code that +processes Mach-O files on Linux. + +From xnu-8792.41.9 (https://github.com/apple-oss-distributions/xnu at 5c2921b) +i386/_types.h +arm/_types.h +mach/boolean.h +mach/machine.h +mach/thread_status.h +mach/vm_prot.h +mach/i386/boolean.h +mach/i386/vm_types.h +mach/arm/boolean.h +mach/arm/vm_types.h +mach/machine/boolean.h +mach/machine/vm_types.h + +From cctools-986 (https://github.com/apple-oss-distributions/cctools at cbe977a) +mach-o/arch.h +mach-o/fat.h +mach-o/loader.h +mach-o/nlist.h + +From architecture-282 (https://github.com/apple-oss-distributions/architecture at fe86900) +architecture/byte_order.h diff --git a/src/third_party/mac_headers/architecture/byte_order.h b/src/third_party/mac_headers/architecture/byte_order.h index b772d9f38..1f723ae14 100644 --- a/src/third_party/mac_headers/architecture/byte_order.h +++ b/src/third_party/mac_headers/architecture/byte_order.h @@ -2,14 +2,14 @@ * Copyright (c) 1999-2008 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -17,7 +17,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ /* @@ -26,20 +26,14 @@ * Byte ordering conversion. * */ -/* This file mostly left blank */ -#ifndef _ARCHITECTURE_BYTE_ORDER_H_ +#ifndef _ARCHITECTURE_BYTE_ORDER_H_ #define _ARCHITECTURE_BYTE_ORDER_H_ -/* - * Identify the byte order - * of the current host. - */ - enum NXByteOrder { NX_UnknownByteOrder, NX_LittleEndian, NX_BigEndian }; -#endif /* _ARCHITECTURE_BYTE_ORDER_H_ */ +#endif /* _ARCHITECTURE_BYTE_ORDER_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/arm/_types.h b/src/third_party/mac_headers/arm/_types.h new file mode 100644 index 000000000..f464d6bd6 --- /dev/null +++ b/src/third_party/mac_headers/arm/_types.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. + */ +#ifndef _BSD_ARM__TYPES_H_ +#define _BSD_ARM__TYPES_H_ + +#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) + + +typedef long __darwin_intptr_t; +typedef unsigned int __darwin_natural_t; + + +#endif /* defined (__arm__) || defined (__arm64__) || defined (__aarch64__) */ + +#endif /* _BSD_ARM__TYPES_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/i386/_types.h b/src/third_party/mac_headers/i386/_types.h index 2ed7fd675..c0478d3ff 100644 --- a/src/third_party/mac_headers/i386/_types.h +++ b/src/third_party/mac_headers/i386/_types.h @@ -2,7 +2,7 @@ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,13 +22,17 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ -#ifndef _BSD_I386__TYPES_H_ -#define _BSD_I386__TYPES_H_ +#ifndef _BSD_I386__TYPES_H_ +#define _BSD_I386__TYPES_H_ + +#if defined (__i386__) || defined (__x86_64__) + +typedef long __darwin_intptr_t; +typedef unsigned int __darwin_natural_t; -typedef long __darwin_intptr_t; -typedef unsigned int __darwin_natural_t; +#endif /* defined (__i386__) || defined (__x86_64__) */ -#endif /* _BSD_I386__TYPES_H_ */ +#endif /* _BSD_I386__TYPES_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach-o/arch.h b/src/third_party/mac_headers/mach-o/arch.h index 526c10fc8..29b81c5ba 100644 --- a/src/third_party/mac_headers/mach-o/arch.h +++ b/src/third_party/mac_headers/mach-o/arch.h @@ -48,7 +48,7 @@ typedef struct { const char *description; } NXArchInfo; -#if __cplusplus +#ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -72,6 +72,36 @@ extern const NXArchInfo *NXGetArchInfoFromName(const char *name); extern const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype, cpu_subtype_t cpusubtype); +/* The above interfaces that return pointers to NXArchInfo structs in normal + * cases returns a pointer from the array returned in NXGetAllArchInfos(). + * In some cases when the cputype is CPU_TYPE_I386 or CPU_TYPE_POWERPC it will + * retun malloc(3)'ed NXArchInfo struct which contains a string in the + * description field also a malloc(3)'ed pointer. To allow programs not to + * leak memory they can call NXFreeArchInfo() on pointers returned from the + * above interfaces. Since this is a new API on older systems can use the + * code below. Going forward the above interfaces will only return pointers + * from the array returned in NXGetAllArchInfos(). + */ +extern void NXFreeArchInfo(const NXArchInfo *x); + +/* The code that can be used for NXFreeArchInfo() when it is not available is: + * + * static void NXFreeArchInfo( + * const NXArchInfo *x) + * { + * const NXArchInfo *p; + * + * p = NXGetAllArchInfos(); + * while(p->name != NULL){ + * if(x == p) + * return; + * p++; + * } + * free((char *)x->description); + * free((NXArchInfo *)x); + * } + */ + /* NXFindBestFatArch() is passed a cputype and cpusubtype and a set of * fat_arch structs and selects the best one that matches (if any) and returns * a pointer to that fat_arch struct (or NULL). The fat_arch structs must be @@ -86,6 +116,21 @@ extern struct fat_arch *NXFindBestFatArch(cpu_type_t cputype, struct fat_arch *fat_archs, uint32_t nfat_archs); +/* NXFindBestFatArch_64() is passed a cputype and cpusubtype and a set of + * fat_arch_64 structs and selects the best one that matches (if any) and + * returns a pointer to that fat_arch_64 struct (or NULL). The fat_arch_64 + * structs must be in the host byte order and correct such that the fat_archs64 + * really points to enough memory for nfat_arch structs. It is possible that + * this routine could fail if new cputypes or cpusubtypes are added and an old + * version of this routine is used. But if there is an exact match between the + * cputype and cpusubtype and one of the fat_arch_64 structs this routine will + * always succeed. + */ +extern struct fat_arch_64 *NXFindBestFatArch_64(cpu_type_t cputype, + cpu_subtype_t cpusubtype, + struct fat_arch_64 *fat_archs64, + uint32_t nfat_archs); + /* NXCombineCpuSubtypes() returns the resulting cpusubtype when combining two * different cpusubtypes for the specified cputype. If the two cpusubtypes * can't be combined (the specific subtypes are mutually exclusive) -1 is @@ -98,8 +143,8 @@ extern cpu_subtype_t NXCombineCpuSubtypes(cpu_type_t cputype, cpu_subtype_t cpusubtype1, cpu_subtype_t cpusubtype2); -#if __cplusplus +#ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* _MACH_O_ARCH_H_ */ +#endif /* _MACH_O_ARCH_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach-o/fat.h b/src/third_party/mac_headers/mach-o/fat.h index e2bcf433d..0e5927dc2 100644 --- a/src/third_party/mac_headers/mach-o/fat.h +++ b/src/third_party/mac_headers/mach-o/fat.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2016 Apple, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -49,7 +49,7 @@ #define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */ struct fat_header { - uint32_t magic; /* FAT_MAGIC */ + uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */ uint32_t nfat_arch; /* number of structs that follow */ }; @@ -61,4 +61,23 @@ struct fat_arch { uint32_t align; /* alignment as a power of 2 */ }; -#endif /* _MACH_O_FAT_H_ */ +/* + * The support for the 64-bit fat file format described here is a work in + * progress and not yet fully supported in all the Apple Developer Tools. + * + * When a slice is greater than 4mb or an offset to a slice is greater than 4mb + * then the 64-bit fat file format is used. + */ +#define FAT_MAGIC_64 0xcafebabf +#define FAT_CIGAM_64 0xbfbafeca /* NXSwapLong(FAT_MAGIC_64) */ + +struct fat_arch_64 { + cpu_type_t cputype; /* cpu specifier (int) */ + cpu_subtype_t cpusubtype; /* machine specifier (int) */ + uint64_t offset; /* file offset to this object file */ + uint64_t size; /* size of this object file */ + uint32_t align; /* alignment as a power of 2 */ + uint32_t reserved; /* reserved */ +}; + +#endif /* _MACH_O_FAT_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach-o/loader.h b/src/third_party/mac_headers/mach-o/loader.h index ff18e29c7..2b03dfdc4 100644 --- a/src/third_party/mac_headers/mach-o/loader.h +++ b/src/third_party/mac_headers/mach-o/loader.h @@ -115,11 +115,14 @@ struct mach_header_64 { #define MH_DYLIB 0x6 /* dynamically bound shared library */ #define MH_DYLINKER 0x7 /* dynamic link editor */ #define MH_BUNDLE 0x8 /* dynamically bound bundle file */ -#define MH_DYLIB_STUB 0x9 /* shared library stub for static */ - /* linking only, no section contents */ -#define MH_DSYM 0xa /* companion file with only debug */ - /* sections */ +#define MH_DYLIB_STUB 0x9 /* shared library stub for static + linking only, no section contents */ +#define MH_DSYM 0xa /* companion file with only debug + sections */ #define MH_KEXT_BUNDLE 0xb /* x86_64 kexts */ +#define MH_FILESET 0xc /* a file composed of other Mach-Os to + be run in the same userspace sharing + a single linkedit. */ /* Constants for the flags field of the mach_header */ #define MH_NOUNDEFS 0x1 /* the object file has no undefined @@ -207,6 +210,25 @@ struct mach_header_64 { require it. Only used in MH_EXECUTE filetypes. */ +#define MH_APP_EXTENSION_SAFE 0x02000000 /* The code was linked for use in an + application extension. */ + +#define MH_NLIST_OUTOFSYNC_WITH_DYLDINFO 0x04000000 /* The external symbols + listed in the nlist symbol table do + not include all the symbols listed in + the dyld info. */ + +#define MH_SIM_SUPPORT 0x08000000 /* Allow LC_MIN_VERSION_MACOS and + LC_BUILD_VERSION load commands with + the platforms macOS, macCatalyst, + iOSSimulator, tvOSSimulator and + watchOSSimulator. */ + +#define MH_DYLIB_IN_CACHE 0x80000000 /* Only for use on dylibs. When this bit + is set, the dylib is part of the dyld + shared cache, rather than loose in + the filesystem. */ + /* * The load commands directly follow the mach_header. The total size of all * of the commands is given by the sizeofcmds field in the mach_header. All @@ -290,6 +312,20 @@ struct load_command { #define LC_FUNCTION_STARTS 0x26 /* compressed table of function start addresses */ #define LC_DYLD_ENVIRONMENT 0x27 /* string for dyld to treat like environment variable */ +#define LC_MAIN (0x28|LC_REQ_DYLD) /* replacement for LC_UNIXTHREAD */ +#define LC_DATA_IN_CODE 0x29 /* table of non-instructions in __text */ +#define LC_SOURCE_VERSION 0x2A /* source version used to build binary */ +#define LC_DYLIB_CODE_SIGN_DRS 0x2B /* Code signing DRs copied from linked dylibs */ +#define LC_ENCRYPTION_INFO_64 0x2C /* 64-bit encrypted segment information */ +#define LC_LINKER_OPTION 0x2D /* linker options in MH_OBJECT files */ +#define LC_LINKER_OPTIMIZATION_HINT 0x2E /* optimization hints in MH_OBJECT files */ +#define LC_VERSION_MIN_TVOS 0x2F /* build for AppleTV min OS version */ +#define LC_VERSION_MIN_WATCHOS 0x30 /* build for Watch min OS version */ +#define LC_NOTE 0x31 /* arbitrary data included within a Mach-O file */ +#define LC_BUILD_VERSION 0x32 /* build for platform min OS version */ +#define LC_DYLD_EXPORTS_TRIE (0x33 | LC_REQ_DYLD) /* used with linkedit_data_command, payload is trie */ +#define LC_DYLD_CHAINED_FIXUPS (0x34 | LC_REQ_DYLD) /* used with linkedit_data_command */ +#define LC_FILESET_ENTRY (0x35 | LC_REQ_DYLD) /* used with fileset_entry_command */ /* * A variable length string in a load command is represented by an lc_str @@ -367,6 +403,9 @@ struct segment_command_64 { /* for 64-bit architectures */ first page of the segment is not protected. All other pages of the segment are protected. */ +#define SG_READ_ONLY 0x10 /* This segment is made read-only after fixups */ + + /* * A segment is made up of zero or more sections. Non-MH_OBJECT files have @@ -492,6 +531,8 @@ struct section_64 { /* for 64-bit architectures */ #define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15 /* functions to call to initialize TLV values */ +#define S_INIT_FUNC_OFFSETS 0x16 /* 32-bit offsets to + initializers */ /* * Constants for the section attributes part of the flags field of a section @@ -753,14 +794,14 @@ struct dylinker_command { * Thread commands contain machine-specific data structures suitable for * use in the thread state primitives. The machine specific data structures * follow the struct thread_command as follows. - * Each flavor of machine specific data structure is preceded by an unsigned - * long constant for the flavor of that data structure, an uint32_t - * that is the count of longs of the size of the state data structure and then + * Each flavor of machine specific data structure is preceded by an uint32_t + * constant for the flavor of that data structure, an uint32_t that is the + * count of uint32_t's of the size of the state data structure and then * the state data structure follows. This triple may be repeated for many * flavors. The constants for the flavors, counts and state data structure * definitions are expected to be in the header file . * These machine specific data structures sizes must be multiples of - * 4 bytes The cmdsize reflects the total size of the thread_command + * 4 bytes. The cmdsize reflects the total size of the thread_command * and all of the sizes of the constants for the flavors, counts and state * data structures. * @@ -774,7 +815,7 @@ struct thread_command { uint32_t cmd; /* LC_THREAD or LC_UNIXTHREAD */ uint32_t cmdsize; /* total size of this command */ /* uint32_t flavor flavor of thread state */ - /* uint32_t count count of longs in thread state */ + /* uint32_t count count of uint32_t's in thread state */ /* struct XXX_thread_state state thread state for this flavor */ /* ... */ }; @@ -1149,7 +1190,11 @@ struct rpath_command { */ struct linkedit_data_command { uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, - or LC_FUNCTION_STARTS */ + LC_FUNCTION_STARTS, LC_DATA_IN_CODE, + LC_DYLIB_CODE_SIGN_DRS, + LC_LINKER_OPTIMIZATION_HINT, + LC_DYLD_EXPORTS_TRIE, or + LC_DYLD_CHAINED_FIXUPS. */ uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */ uint32_t dataoff; /* file offset of data in __LINKEDIT segment */ uint32_t datasize; /* file size of data in __LINKEDIT segment */ @@ -1168,18 +1213,75 @@ struct encryption_info_command { 0 means not-encrypted yet */ }; +/* + * The encryption_info_command_64 contains the file offset and size of an + * of an encrypted segment (for use in x86_64 targets). + */ +struct encryption_info_command_64 { + uint32_t cmd; /* LC_ENCRYPTION_INFO_64 */ + uint32_t cmdsize; /* sizeof(struct encryption_info_command_64) */ + uint32_t cryptoff; /* file offset of encrypted range */ + uint32_t cryptsize; /* file size of encrypted range */ + uint32_t cryptid; /* which enryption system, + 0 means not-encrypted yet */ + uint32_t pad; /* padding to make this struct's size a multiple + of 8 bytes */ +}; + /* * The version_min_command contains the min OS version on which this * binary was built to run. */ struct version_min_command { uint32_t cmd; /* LC_VERSION_MIN_MACOSX or - LC_VERSION_MIN_IPHONEOS */ + LC_VERSION_MIN_IPHONEOS or + LC_VERSION_MIN_WATCHOS or + LC_VERSION_MIN_TVOS */ uint32_t cmdsize; /* sizeof(struct min_version_command) */ uint32_t version; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ - uint32_t reserved; /* zero */ + uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ +}; + +/* + * The build_version_command contains the min OS version on which this + * binary was built to run for its platform. The list of known platforms and + * tool values following it. + */ +struct build_version_command { + uint32_t cmd; /* LC_BUILD_VERSION */ + uint32_t cmdsize; /* sizeof(struct build_version_command) plus */ + /* ntools * sizeof(struct build_tool_version) */ + uint32_t platform; /* platform */ + uint32_t minos; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ + uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ + uint32_t ntools; /* number of tool entries following this */ +}; + +struct build_tool_version { + uint32_t tool; /* enum for the tool */ + uint32_t version; /* version number of the tool */ }; +/* Known values for the platform field above. */ +#define PLATFORM_MACOS 1 +#define PLATFORM_IOS 2 +#define PLATFORM_TVOS 3 +#define PLATFORM_WATCHOS 4 +#define PLATFORM_BRIDGEOS 5 +#define PLATFORM_MACCATALYST 6 +#define PLATFORM_IOSSIMULATOR 7 +#define PLATFORM_TVOSSIMULATOR 8 +#define PLATFORM_WATCHOSSIMULATOR 9 +#define PLATFORM_DRIVERKIT 10 + +#ifndef __APPLE_BLEACH_SDK__ +#endif /* __APPLE_BLEACH_SDK__ */ + +/* Known values for the tool field above. */ +#define TOOL_CLANG 1 +#define TOOL_SWIFT 2 +#define TOOL_LD 3 + /* * The dyld_info_command contains the file offsets and sizes of * the new compressed form of the information dyld needs to @@ -1265,14 +1367,19 @@ struct dyld_info_command { * Nodes for a symbol start with a uleb128 that is the length of * the exported symbol information for the string so far. * If there is no exported symbol, the node starts with a zero byte. - * If there is exported info, it follows the length. First is - * a uleb128 containing flags. Normally, it is followed by a - * uleb128 encoded offset which is location of the content named + * If there is exported info, it follows the length. + * + * First is a uleb128 containing flags. Normally, it is followed by + * a uleb128 encoded offset which is location of the content named * by the symbol from the mach_header for the image. If the flags * is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is * a uleb128 encoded library ordinal, then a zero terminated * UTF8 string. If the string is zero length, then the symbol * is re-export from the specified dylib with the same name. + * If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following + * the flags is two uleb128s: the stub offset and the resolver offset. + * The stub is used by non-lazy pointers. The resolver is used + * by lazy pointers and must be called to get the actual address to use. * * After the optional exported symbol information is a byte of * how many edges (0-255) that this node has leaving it, @@ -1316,6 +1423,7 @@ struct dyld_info_command { #define BIND_SPECIAL_DYLIB_SELF 0 #define BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE -1 #define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2 +#define BIND_SPECIAL_DYLIB_WEAK_LOOKUP -3 #define BIND_SYMBOL_FLAGS_WEAK_IMPORT 0x1 #define BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION 0x8 @@ -1335,6 +1443,9 @@ struct dyld_info_command { #define BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB 0xA0 #define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED 0xB0 #define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xC0 +#define BIND_OPCODE_THREADED 0xD0 +#define BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB 0x00 +#define BIND_SUBOPCODE_THREADED_APPLY 0x01 /* @@ -1344,9 +1455,23 @@ struct dyld_info_command { #define EXPORT_SYMBOL_FLAGS_KIND_MASK 0x03 #define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00 #define EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL 0x01 +#define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02 #define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04 #define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08 #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10 +#define EXPORT_SYMBOL_FLAGS_STATIC_RESOLVER 0x20 + + +/* + * The linker_option_command contains linker options embedded in object files. + */ +struct linker_option_command { + uint32_t cmd; /* LC_LINKER_OPTION only used in MH_OBJECT filetypes */ + uint32_t cmdsize; + uint32_t count; /* number of strings */ + /* concatenation of zero terminated UTF8 strings. + Zero filled at end to align */ +}; /* * The symseg_command contains the offset and size of the GNU style @@ -1388,6 +1513,50 @@ struct fvmfile_command { uint32_t header_addr; /* files virtual address */ }; + +/* + * The entry_point_command is a replacement for thread_command. + * It is used for main executables to specify the location (file offset) + * of main(). If -stack_size was used at link time, the stacksize + * field will contain the stack size need for the main thread. + */ +struct entry_point_command { + uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */ + uint32_t cmdsize; /* 24 */ + uint64_t entryoff; /* file (__TEXT) offset of main() */ + uint64_t stacksize;/* if not zero, initial stack size */ +}; + + +/* + * The source_version_command is an optional load command containing + * the version of the sources used to build the binary. + */ +struct source_version_command { + uint32_t cmd; /* LC_SOURCE_VERSION */ + uint32_t cmdsize; /* 16 */ + uint64_t version; /* A.B.C.D.E packed as a24.b10.c10.d10.e10 */ +}; + + +/* + * The LC_DATA_IN_CODE load commands uses a linkedit_data_command + * to point to an array of data_in_code_entry entries. Each entry + * describes a range of data in a code section. + */ +struct data_in_code_entry { + uint32_t offset; /* from mach_header to start of data range*/ + uint16_t length; /* number of bytes in data range */ + uint16_t kind; /* a DICE_KIND_* value */ +}; +#define DICE_KIND_DATA 0x0001 +#define DICE_KIND_JUMP_TABLE8 0x0002 +#define DICE_KIND_JUMP_TABLE16 0x0003 +#define DICE_KIND_JUMP_TABLE32 0x0004 +#define DICE_KIND_ABS_JUMP_TABLE32 0x0005 + + + /* * Sections of type S_THREAD_LOCAL_VARIABLES contain an array * of tlv_descriptor structures. @@ -1399,4 +1568,39 @@ struct tlv_descriptor unsigned long offset; }; -#endif /* _MACHO_LOADER_H_ */ +/* + * LC_NOTE commands describe a region of arbitrary data included in a Mach-O + * file. Its initial use is to record extra data in MH_CORE files. + */ +struct note_command { + uint32_t cmd; /* LC_NOTE */ + uint32_t cmdsize; /* sizeof(struct note_command) */ + char data_owner[16]; /* owner name for this LC_NOTE */ + uint64_t offset; /* file offset of this data */ + uint64_t size; /* length of data region */ +}; + +/* + * LC_FILESET_ENTRY commands describe constituent Mach-O files that are part + * of a fileset. In one implementation, entries are dylibs with individual + * mach headers and repositionable text and data segments. Each entry is + * further described by its own mach header. + */ +struct fileset_entry_command { + uint32_t cmd; /* LC_FILESET_ENTRY */ + uint32_t cmdsize; /* includes entry_id string */ + uint64_t vmaddr; /* memory address of the entry */ + uint64_t fileoff; /* file offset of the entry */ + union lc_str entry_id; /* contained entry id */ + uint32_t reserved; /* reserved */ +}; + +/* + * These deprecated values may still be used within Apple but are mechanically + * removed from public API. The mechanical process may produce unusual results. + */ +#if (!defined(PLATFORM_IOSMAC)) +#define PLATFORM_IOSMAC PLATFORM_MACCATALYST +#endif + +#endif /* _MACHO_LOADER_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach-o/nlist.h b/src/third_party/mac_headers/mach-o/nlist.h index 1c1941012..7b979a52a 100644 --- a/src/third_party/mac_headers/mach-o/nlist.h +++ b/src/third_party/mac_headers/mach-o/nlist.h @@ -78,7 +78,7 @@ struct nlist { #ifndef __LP64__ char *n_name; /* for use when in-core */ #endif - int32_t n_strx; /* index into the string table */ + uint32_t n_strx; /* index into the string table */ } n_un; uint8_t n_type; /* type flag, see below */ uint8_t n_sect; /* section number or NO_SECT */ @@ -296,17 +296,29 @@ struct nlist_64 { */ #define N_SYMBOL_RESOLVER 0x0100 +/* + * The N_ALT_ENTRY bit of the n_desc field indicates that the + * symbol is pinned to the previous content. + */ +#define N_ALT_ENTRY 0x0200 + +/* + * The N_COLD_FUNC bit of the n_desc field indicates that the symbol is used + * infrequently and the linker should order it towards the end of the section. + */ +#define N_COLD_FUNC 0x0400 + #ifndef __STRICT_BSD__ -#if __cplusplus +#ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * The function nlist(3) from the C library. */ extern int nlist (const char *filename, struct nlist *list); -#if __cplusplus +#ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __STRICT_BSD__ */ -#endif /* _MACHO_LIST_H_ */ +#endif /* _MACHO_LIST_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach/arm/boolean.h b/src/third_party/mac_headers/mach/arm/boolean.h new file mode 100644 index 000000000..d653a394c --- /dev/null +++ b/src/third_party/mac_headers/mach/arm/boolean.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + */ + +/* + * File: boolean.h + * + * Boolean type, for ARM. + */ + +#ifndef _MACH_ARM_BOOLEAN_H_ +#define _MACH_ARM_BOOLEAN_H_ + +#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) + +typedef int boolean_t; + +#endif /* defined (__arm__) || defined (__arm64__) */ + +#endif /* _MACH_ARM_BOOLEAN_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach/arm/vm_types.h b/src/third_party/mac_headers/mach/arm/vm_types.h new file mode 100644 index 000000000..3650a8690 --- /dev/null +++ b/src/third_party/mac_headers/mach/arm/vm_types.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + */ + +/* + * File: vm_types.h + * Author: Avadis Tevanian, Jr. + * Date: 1985 + * + * Header file for VM data types. ARM version. + */ + +#ifndef _MACH_ARM_VM_TYPES_H_ +#define _MACH_ARM_VM_TYPES_H_ + +#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) + +#ifndef ASSEMBLER + +#include +#include +#include + +/* + * natural_t and integer_t are Mach's legacy types for machine- + * independent integer types (unsigned, and signed, respectively). + * Their original purpose was to define other types in a machine/ + * compiler independent way. + * + * They also had an implicit "same size as pointer" characteristic + * to them (i.e. Mach's traditional types are very ILP32 or ILP64 + * centric). We will likely support x86 ABIs that do not follow + * either ofthese models (specifically LP64). Therefore, we had to + * make a choice between making these types scale with pointers or stay + * tied to integers. Because their use is predominantly tied to + * to the size of an integer, we are keeping that association and + * breaking free from pointer size guarantees. + * + * New use of these types is discouraged. + */ +typedef __darwin_natural_t natural_t; +typedef int integer_t; + +/* + * A vm_offset_t is a type-neutral pointer, + * e.g. an offset into a virtual memory space. + */ +#ifdef __LP64__ +typedef uintptr_t vm_offset_t ; +typedef uintptr_t vm_size_t; + +typedef uint64_t mach_vm_address_t ; +typedef uint64_t mach_vm_offset_t ; +typedef uint64_t mach_vm_size_t; + +typedef uint64_t vm_map_offset_t ; +typedef uint64_t vm_map_address_t ; +typedef uint64_t vm_map_size_t; +#else +typedef natural_t vm_offset_t ; +/* + * A vm_size_t is the proper type for e.g. + * expressing the difference between two + * vm_offset_t entities. + */ +typedef natural_t vm_size_t; + +/* + * This new type is independent of a particular vm map's + * implementation size - and represents appropriate types + * for all possible maps. This is used for interfaces + * where the size of the map is not known - or we don't + * want to have to distinguish. + */ +typedef uint64_t mach_vm_address_t ; +typedef uint64_t mach_vm_offset_t ; +typedef uint64_t mach_vm_size_t; + +typedef uint32_t vm_map_offset_t ; +typedef uint32_t vm_map_address_t ; +typedef uint32_t vm_map_size_t; +#endif /* __LP64__ */ + + +typedef uint32_t vm32_offset_t; +typedef uint32_t vm32_address_t; +typedef uint32_t vm32_size_t; + +typedef vm_offset_t mach_port_context_t; + +#ifdef MACH_KERNEL_PRIVATE +typedef vm32_offset_t mach_port_context32_t; +typedef mach_vm_offset_t mach_port_context64_t; +#endif + +#endif /* ASSEMBLER */ + +/* + * If composing messages by hand (please do not) + */ +#define MACH_MSG_TYPE_INTEGER_T MACH_MSG_TYPE_INTEGER_32 + +#endif /* defined (__arm__) || defined (__arm64__) || defined (__aarch64__) */ + +#endif /* _MACH_ARM_VM_TYPES_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach/boolean.h b/src/third_party/mac_headers/mach/boolean.h index 641c3962d..ba8842934 100644 --- a/src/third_party/mac_headers/mach/boolean.h +++ b/src/third_party/mac_headers/mach/boolean.h @@ -2,7 +2,7 @@ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,34 +22,34 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ */ -/* +/* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University * All Rights Reserved. - * + * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * + * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to - * + * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 - * + * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ @@ -62,27 +62,27 @@ * */ -#ifndef _MACH_BOOLEAN_H_ -#define _MACH_BOOLEAN_H_ +#ifndef _MACH_BOOLEAN_H_ +#define _MACH_BOOLEAN_H_ /* * Pick up "boolean_t" type definition */ -#ifndef ASSEMBLER +#ifndef ASSEMBLER #include -#endif /* ASSEMBLER */ +#endif /* ASSEMBLER */ /* * Define TRUE and FALSE if not defined. */ -#ifndef TRUE -#define TRUE 1 -#endif /* TRUE */ +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ -#ifndef FALSE -#define FALSE 0 -#endif /* FALSE */ +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ -#endif /* _MACH_BOOLEAN_H_ */ +#endif /* _MACH_BOOLEAN_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach/i386/boolean.h b/src/third_party/mac_headers/mach/i386/boolean.h index 100f7e7b5..b1d69a193 100644 --- a/src/third_party/mac_headers/mach/i386/boolean.h +++ b/src/third_party/mac_headers/mach/i386/boolean.h @@ -2,7 +2,7 @@ * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,34 +22,34 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ */ -/* +/* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. - * + * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * + * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to - * + * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 - * + * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ @@ -62,13 +62,17 @@ * Boolean type, for I386. */ -#ifndef _MACH_I386_BOOLEAN_H_ +#ifndef _MACH_I386_BOOLEAN_H_ #define _MACH_I386_BOOLEAN_H_ +#if defined (__i386__) || defined (__x86_64__) + #if defined(__x86_64__) && !defined(KERNEL) -typedef unsigned int boolean_t; +typedef unsigned int boolean_t; #else -typedef int boolean_t; +typedef int boolean_t; #endif -#endif /* _MACH_I386_BOOLEAN_H_ */ +#endif /* defined (__i386__) || defined (__x86_64__) */ + +#endif /* _MACH_I386_BOOLEAN_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach/i386/vm_param.h b/src/third_party/mac_headers/mach/i386/vm_param.h deleted file mode 100644 index edcb83496..000000000 --- a/src/third_party/mac_headers/mach/i386/vm_param.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. - * - * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. The rights granted to you under the License - * may not be used to create, or enable the creation or redistribution of, - * unlawful or unlicensed copies of an Apple operating system, or to - * circumvent, violate, or enable the circumvention or violation of, any - * terms of an Apple operating system software license agreement. - * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ - */ -/* - * @OSF_COPYRIGHT@ - */ -/* - * Mach Operating System - * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie Mellon - * the rights to redistribute these changes. - */ - -/* - * Copyright (c) 1994 The University of Utah and - * the Computer Systems Laboratory at the University of Utah (CSL). - * All rights reserved. - * - * Permission to use, copy, modify and distribute this software is hereby - * granted provided that (1) source code retains these copyright, permission, - * and disclaimer notices, and (2) redistributions including binaries - * reproduce the notices in supporting documentation, and (3) all advertising - * materials mentioning features or use of this software display the following - * acknowledgement: ``This product includes software developed by the - * Computer Systems Laboratory at the University of Utah.'' - * - * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS - * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF - * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * CSL requests users of this software to return to csl-dist@cs.utah.edu any - * improvements that they make and grant CSL redistribution rights. - * - */ - -/* - * File: vm_param.h - * Author: Avadis Tevanian, Jr. - * Date: 1985 - * - * I386 machine dependent virtual memory parameters. - * Most of the declarations are preceeded by I386_ (or i386_) - * which is OK because only I386 specific code will be using - * them. - */ - -#ifndef _MACH_I386_VM_PARAM_H_ -#define _MACH_I386_VM_PARAM_H_ - -#define BYTE_SIZE 8 /* byte size in bits */ - -#define I386_PGBYTES 4096 /* bytes per 80386 page */ -#define I386_PGSHIFT 12 /* bitshift for pages */ - -#define PAGE_SIZE I386_PGBYTES -#define PAGE_SHIFT I386_PGSHIFT -#define PAGE_MASK (PAGE_SIZE - 1) - -#define I386_LPGBYTES 2*1024*1024 /* bytes per large page */ -#define I386_LPGSHIFT 21 /* bitshift for large pages */ -#define I386_LPGMASK (I386_LPGBYTES-1) - -/* - * Convert bytes to pages and convert pages to bytes. - * No rounding is used. - */ - -#define i386_btop(x) ((ppnum_t)((x) >> I386_PGSHIFT)) -#define machine_btop(x) i386_btop(x) -#define i386_ptob(x) (((pmap_paddr_t)(x)) << I386_PGSHIFT) - -/* - * Round off or truncate to the nearest page. These will work - * for either addresses or counts. (i.e. 1 byte rounds to 1 page - * bytes. - */ - -#define i386_round_page(x) ((((pmap_paddr_t)(x)) + I386_PGBYTES - 1) & \ - ~(I386_PGBYTES-1)) -#define i386_trunc_page(x) (((pmap_paddr_t)(x)) & ~(I386_PGBYTES-1)) - - - -#define VM_MIN_ADDRESS64 ((user_addr_t) 0x0000000000000000ULL) -/* - * default top of user stack... it grows down from here - */ -#define VM_USRSTACK64 ((user_addr_t) 0x00007FFF5FC00000ULL) -#define VM_DYLD64 ((user_addr_t) 0x00007FFF5FC00000ULL) -#define VM_LIB64_SHR_DATA ((user_addr_t) 0x00007FFF60000000ULL) -#define VM_LIB64_SHR_TEXT ((user_addr_t) 0x00007FFF80000000ULL) -/* - * the end of the usable user address space , for now about 47 bits. - * the 64 bit commpage is past the end of this - */ -#define VM_MAX_PAGE_ADDRESS ((user_addr_t) 0x00007FFFFFE00000ULL) -/* - * canonical end of user address space for limits checking - */ -#define VM_MAX_USER_PAGE_ADDRESS ((user_addr_t)0x00007FFFFFFFF000ULL) - - -/* system-wide values */ -#define MACH_VM_MIN_ADDRESS ((mach_vm_offset_t) 0) -#define MACH_VM_MAX_ADDRESS ((mach_vm_offset_t) VM_MAX_PAGE_ADDRESS) - -/* process-relative values (all 32-bit legacy only for now) */ -#define VM_MIN_ADDRESS ((vm_offset_t) 0) -#define VM_USRSTACK32 ((vm_offset_t) 0xC0000000) -#define VM_MAX_ADDRESS ((vm_offset_t) 0xFFE00000) - - - -#endif /* _MACH_I386_VM_PARAM_H_ */ diff --git a/src/third_party/mac_headers/mach/i386/vm_types.h b/src/third_party/mac_headers/mach/i386/vm_types.h index 2c38fa2d7..0c3bb6ba4 100644 --- a/src/third_party/mac_headers/mach/i386/vm_types.h +++ b/src/third_party/mac_headers/mach/i386/vm_types.h @@ -1,8 +1,8 @@ /* - * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2016 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,34 +22,34 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ */ -/* +/* * Mach Operating System * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University * All Rights Reserved. - * + * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * + * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to - * + * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 - * + * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ @@ -64,14 +64,16 @@ * Header file for VM data types. I386 version. */ -#ifndef _MACH_I386_VM_TYPES_H_ +#ifndef _MACH_I386_VM_TYPES_H_ #define _MACH_I386_VM_TYPES_H_ -#ifndef ASSEMBLER +#if defined (__i386__) || defined (__x86_64__) + +#ifndef ASSEMBLER #include -#include #include +#include /* * natural_t and integer_t are Mach's legacy types for machine- @@ -90,18 +92,18 @@ * * New use of these types is discouraged. */ -typedef __darwin_natural_t natural_t; -typedef int integer_t; +typedef __darwin_natural_t natural_t; +typedef int integer_t; /* * A vm_offset_t is a type-neutral pointer, * e.g. an offset into a virtual memory space. */ #ifdef __LP64__ -typedef uintptr_t vm_offset_t; -#else /* __LP64__ */ -typedef natural_t vm_offset_t; -#endif /* __LP64__ */ +typedef uintptr_t vm_offset_t ; +#else /* __LP64__ */ +typedef natural_t vm_offset_t ; +#endif /* __LP64__ */ /* * A vm_size_t is the proper type for e.g. @@ -109,10 +111,10 @@ typedef natural_t vm_offset_t; * vm_offset_t entities. */ #ifdef __LP64__ -typedef uintptr_t vm_size_t; -#else /* __LP64__ */ -typedef natural_t vm_size_t; -#endif /* __LP64__ */ +typedef uintptr_t vm_size_t; +#else /* __LP64__ */ +typedef natural_t vm_size_t; +#endif /* __LP64__ */ /* * This new type is independent of a particular vm map's @@ -121,20 +123,35 @@ typedef natural_t vm_size_t; * where the size of the map is not known - or we don't * want to have to distinguish. */ -typedef uint64_t mach_vm_address_t; -typedef uint64_t mach_vm_offset_t; -typedef uint64_t mach_vm_size_t; +typedef uint64_t mach_vm_address_t ; +typedef uint64_t mach_vm_offset_t ; +typedef uint64_t mach_vm_size_t; + +typedef uint64_t vm_map_offset_t ; +typedef uint64_t vm_map_address_t ; +typedef uint64_t vm_map_size_t; + +typedef mach_vm_address_t mach_port_context_t; -typedef uint64_t vm_map_offset_t; -typedef uint64_t vm_map_address_t; -typedef uint64_t vm_map_size_t; +#ifdef MACH_KERNEL_PRIVATE +/* + * These are types used internal to Mach to implement the + * legacy 32-bit VM APIs published by the kernel. + */ +typedef uint32_t vm32_address_t; +typedef uint32_t vm32_offset_t; +typedef uint32_t vm32_size_t; -#endif /* ASSEMBLER */ +#endif /* MACH_KERNEL_PRIVATE */ + +#endif /* ASSEMBLER */ /* * If composing messages by hand (please do not) */ -#define MACH_MSG_TYPE_INTEGER_T MACH_MSG_TYPE_INTEGER_32 +#define MACH_MSG_TYPE_INTEGER_T MACH_MSG_TYPE_INTEGER_32 + +#endif /* defined (__i386__) || defined (__x86_64__) */ -#endif /* _MACH_I386_VM_TYPES_H_ */ +#endif /* _MACH_I386_VM_TYPES_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach/machine.h b/src/third_party/mac_headers/mach/machine.h index 5bb21e48b..53457cca7 100644 --- a/src/third_party/mac_headers/mach/machine.h +++ b/src/third_party/mac_headers/mach/machine.h @@ -1,8 +1,9 @@ /* - * Copyright (c) 2000-2007 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2007-2016 Apple, Inc. All rights reserved. + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +12,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,31 +23,31 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ -/* +/* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University * All Rights Reserved. - * + * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * + * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to - * + * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 - * + * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ @@ -57,60 +58,114 @@ * Machine independent machine abstraction. */ -#ifndef _MACH_MACHINE_H_ +#ifndef _MACH_MACHINE_H_ #define _MACH_MACHINE_H_ +#ifndef __ASSEMBLER__ + #include #include #include -typedef integer_t cpu_type_t; -typedef integer_t cpu_subtype_t; -typedef integer_t cpu_threadtype_t; +typedef integer_t cpu_type_t; +typedef integer_t cpu_subtype_t; +typedef integer_t cpu_threadtype_t; + +#define CPU_STATE_MAX 4 + +#define CPU_STATE_USER 0 +#define CPU_STATE_SYSTEM 1 +#define CPU_STATE_IDLE 2 +#define CPU_STATE_NICE 3 + +#ifdef KERNEL_PRIVATE + +#include + +__BEGIN_DECLS +cpu_type_t cpu_type(void); + +cpu_subtype_t cpu_subtype(void); + +cpu_threadtype_t cpu_threadtype(void); +__END_DECLS -#define CPU_STATE_MAX 4 +#ifdef MACH_KERNEL_PRIVATE -#define CPU_STATE_USER 0 -#define CPU_STATE_SYSTEM 1 -#define CPU_STATE_IDLE 2 -#define CPU_STATE_NICE 3 +struct machine_info { + integer_t major_version; /* kernel major version id */ + integer_t minor_version; /* kernel minor version id */ + integer_t max_cpus; /* max number of CPUs possible */ + uint32_t memory_size; /* size of memory in bytes, capped at 2 GB */ + uint64_t max_mem; /* actual size of physical memory */ + uint32_t physical_cpu; /* number of physical CPUs now available */ + integer_t physical_cpu_max; /* max number of physical CPUs possible */ + uint32_t logical_cpu; /* number of logical cpu now available */ + integer_t logical_cpu_max; /* max number of physical CPUs possible */ +}; +typedef struct machine_info *machine_info_t; +typedef struct machine_info machine_info_data_t; + +extern struct machine_info machine_info; + +__BEGIN_DECLS +cpu_type_t slot_type( + int slot_num); + +cpu_subtype_t slot_subtype( + int slot_num); + +cpu_threadtype_t slot_threadtype( + int slot_num); +__END_DECLS + +#endif /* MACH_KERNEL_PRIVATE */ +#endif /* KERNEL_PRIVATE */ /* * Capability bits used in the definition of cpu_type. */ -#define CPU_ARCH_MASK 0xff000000 /* mask for architecture bits */ -#define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */ +#define CPU_ARCH_MASK 0xff000000 /* mask for architecture bits */ +#define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */ +#define CPU_ARCH_ABI64_32 0x02000000 /* ABI for 64-bit hardware with 32-bit types; LP32 */ /* * Machine types known by all. */ - -#define CPU_TYPE_ANY ((cpu_type_t) -1) -#define CPU_TYPE_VAX ((cpu_type_t) 1) +#define CPU_TYPE_ANY ((cpu_type_t) -1) + +#define CPU_TYPE_VAX ((cpu_type_t) 1) /* skip ((cpu_type_t) 2) */ /* skip ((cpu_type_t) 3) */ /* skip ((cpu_type_t) 4) */ /* skip ((cpu_type_t) 5) */ -#define CPU_TYPE_MC680x0 ((cpu_type_t) 6) -#define CPU_TYPE_X86 ((cpu_type_t) 7) -#define CPU_TYPE_I386 CPU_TYPE_X86 /* compatibility */ -#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) +#define CPU_TYPE_MC680x0 ((cpu_type_t) 6) +#define CPU_TYPE_X86 ((cpu_type_t) 7) +#define CPU_TYPE_I386 CPU_TYPE_X86 /* compatibility */ +#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) /* skip CPU_TYPE_MIPS ((cpu_type_t) 8) */ -/* skip ((cpu_type_t) 9) */ -#define CPU_TYPE_MC98000 ((cpu_type_t) 10) +/* skip ((cpu_type_t) 9) */ +#define CPU_TYPE_MC98000 ((cpu_type_t) 10) #define CPU_TYPE_HPPA ((cpu_type_t) 11) -#define CPU_TYPE_ARM ((cpu_type_t) 12) -#define CPU_TYPE_MC88000 ((cpu_type_t) 13) -#define CPU_TYPE_SPARC ((cpu_type_t) 14) -#define CPU_TYPE_I860 ((cpu_type_t) 15) +#define CPU_TYPE_ARM ((cpu_type_t) 12) +#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) +#define CPU_TYPE_ARM64_32 (CPU_TYPE_ARM | CPU_ARCH_ABI64_32) +#define CPU_TYPE_MC88000 ((cpu_type_t) 13) +#define CPU_TYPE_SPARC ((cpu_type_t) 14) +#define CPU_TYPE_I860 ((cpu_type_t) 15) /* skip CPU_TYPE_ALPHA ((cpu_type_t) 16) */ /* skip ((cpu_type_t) 17) */ -#define CPU_TYPE_POWERPC ((cpu_type_t) 18) -#define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) +#define CPU_TYPE_POWERPC ((cpu_type_t) 18) +#define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) +/* skip ((cpu_type_t) 19) */ +/* skip ((cpu_type_t) 20 */ +/* skip ((cpu_type_t) 21 */ +/* skip ((cpu_type_t) 22 */ +/* skip ((cpu_type_t) 23 */ /* * Machine subtypes (these are defined here, instead of in a machine @@ -121,9 +176,16 @@ typedef integer_t cpu_threadtype_t; /* * Capability bits used in the definition of cpu_subtype. */ -#define CPU_SUBTYPE_MASK 0xff000000 /* mask for feature flags */ -#define CPU_SUBTYPE_LIB64 0x80000000 /* 64 bit libraries */ +#define CPU_SUBTYPE_MASK 0xff000000 /* mask for feature flags */ +#define CPU_SUBTYPE_LIB64 0x80000000 /* 64 bit libraries */ +#define CPU_SUBTYPE_PTRAUTH_ABI 0x80000000 /* pointer authentication with versioned ABI */ +/* + * When selecting a slice, ANY will pick the slice with the best + * grading for the selected cpu_type_t, unlike the "ALL" subtypes, + * which are the slices that can run on any hardware for that cpu type. + */ +#define CPU_SUBTYPE_ANY ((cpu_subtype_t) -1) /* * Object files that are hand-crafted to run on any @@ -136,42 +198,42 @@ typedef integer_t cpu_threadtype_t; * It is the responsibility of the implementor to make sure the * software handles unsupported implementations elegantly. */ -#define CPU_SUBTYPE_MULTIPLE ((cpu_subtype_t) -1) -#define CPU_SUBTYPE_LITTLE_ENDIAN ((cpu_subtype_t) 0) -#define CPU_SUBTYPE_BIG_ENDIAN ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_MULTIPLE ((cpu_subtype_t) -1) +#define CPU_SUBTYPE_LITTLE_ENDIAN ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_BIG_ENDIAN ((cpu_subtype_t) 1) /* * Machine threadtypes. * This is none - not defined - for most machine types/subtypes. */ -#define CPU_THREADTYPE_NONE ((cpu_threadtype_t) 0) +#define CPU_THREADTYPE_NONE ((cpu_threadtype_t) 0) /* * VAX subtypes (these do *not* necessary conform to the actual cpu * ID assigned by DEC available via the SID register). */ -#define CPU_SUBTYPE_VAX_ALL ((cpu_subtype_t) 0) -#define CPU_SUBTYPE_VAX780 ((cpu_subtype_t) 1) -#define CPU_SUBTYPE_VAX785 ((cpu_subtype_t) 2) -#define CPU_SUBTYPE_VAX750 ((cpu_subtype_t) 3) -#define CPU_SUBTYPE_VAX730 ((cpu_subtype_t) 4) -#define CPU_SUBTYPE_UVAXI ((cpu_subtype_t) 5) -#define CPU_SUBTYPE_UVAXII ((cpu_subtype_t) 6) -#define CPU_SUBTYPE_VAX8200 ((cpu_subtype_t) 7) -#define CPU_SUBTYPE_VAX8500 ((cpu_subtype_t) 8) -#define CPU_SUBTYPE_VAX8600 ((cpu_subtype_t) 9) -#define CPU_SUBTYPE_VAX8650 ((cpu_subtype_t) 10) -#define CPU_SUBTYPE_VAX8800 ((cpu_subtype_t) 11) -#define CPU_SUBTYPE_UVAXIII ((cpu_subtype_t) 12) +#define CPU_SUBTYPE_VAX_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_VAX780 ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_VAX785 ((cpu_subtype_t) 2) +#define CPU_SUBTYPE_VAX750 ((cpu_subtype_t) 3) +#define CPU_SUBTYPE_VAX730 ((cpu_subtype_t) 4) +#define CPU_SUBTYPE_UVAXI ((cpu_subtype_t) 5) +#define CPU_SUBTYPE_UVAXII ((cpu_subtype_t) 6) +#define CPU_SUBTYPE_VAX8200 ((cpu_subtype_t) 7) +#define CPU_SUBTYPE_VAX8500 ((cpu_subtype_t) 8) +#define CPU_SUBTYPE_VAX8600 ((cpu_subtype_t) 9) +#define CPU_SUBTYPE_VAX8650 ((cpu_subtype_t) 10) +#define CPU_SUBTYPE_VAX8800 ((cpu_subtype_t) 11) +#define CPU_SUBTYPE_UVAXIII ((cpu_subtype_t) 12) /* - * 680x0 subtypes + * 680x0 subtypes * * The subtype definitions here are unusual for historical reasons. * NeXT used to consider 68030 code as generic 68000 code. For * backwards compatability: - * + * * CPU_SUBTYPE_MC68030 symbol has been preserved for source code * compatability. * @@ -182,119 +244,119 @@ typedef integer_t cpu_threadtype_t; * files to be tagged as containing 68030-specific instructions. */ -#define CPU_SUBTYPE_MC680x0_ALL ((cpu_subtype_t) 1) -#define CPU_SUBTYPE_MC68030 ((cpu_subtype_t) 1) /* compat */ -#define CPU_SUBTYPE_MC68040 ((cpu_subtype_t) 2) -#define CPU_SUBTYPE_MC68030_ONLY ((cpu_subtype_t) 3) +#define CPU_SUBTYPE_MC680x0_ALL ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_MC68030 ((cpu_subtype_t) 1) /* compat */ +#define CPU_SUBTYPE_MC68040 ((cpu_subtype_t) 2) +#define CPU_SUBTYPE_MC68030_ONLY ((cpu_subtype_t) 3) /* * I386 subtypes */ -#define CPU_SUBTYPE_INTEL(f, m) ((cpu_subtype_t) (f) + ((m) << 4)) - -#define CPU_SUBTYPE_I386_ALL CPU_SUBTYPE_INTEL(3, 0) -#define CPU_SUBTYPE_386 CPU_SUBTYPE_INTEL(3, 0) -#define CPU_SUBTYPE_486 CPU_SUBTYPE_INTEL(4, 0) -#define CPU_SUBTYPE_486SX CPU_SUBTYPE_INTEL(4, 8) // 8 << 4 = 128 -#define CPU_SUBTYPE_586 CPU_SUBTYPE_INTEL(5, 0) -#define CPU_SUBTYPE_PENT CPU_SUBTYPE_INTEL(5, 0) -#define CPU_SUBTYPE_PENTPRO CPU_SUBTYPE_INTEL(6, 1) -#define CPU_SUBTYPE_PENTII_M3 CPU_SUBTYPE_INTEL(6, 3) -#define CPU_SUBTYPE_PENTII_M5 CPU_SUBTYPE_INTEL(6, 5) -#define CPU_SUBTYPE_CELERON CPU_SUBTYPE_INTEL(7, 6) -#define CPU_SUBTYPE_CELERON_MOBILE CPU_SUBTYPE_INTEL(7, 7) -#define CPU_SUBTYPE_PENTIUM_3 CPU_SUBTYPE_INTEL(8, 0) -#define CPU_SUBTYPE_PENTIUM_3_M CPU_SUBTYPE_INTEL(8, 1) -#define CPU_SUBTYPE_PENTIUM_3_XEON CPU_SUBTYPE_INTEL(8, 2) -#define CPU_SUBTYPE_PENTIUM_M CPU_SUBTYPE_INTEL(9, 0) -#define CPU_SUBTYPE_PENTIUM_4 CPU_SUBTYPE_INTEL(10, 0) -#define CPU_SUBTYPE_PENTIUM_4_M CPU_SUBTYPE_INTEL(10, 1) -#define CPU_SUBTYPE_ITANIUM CPU_SUBTYPE_INTEL(11, 0) -#define CPU_SUBTYPE_ITANIUM_2 CPU_SUBTYPE_INTEL(11, 1) -#define CPU_SUBTYPE_XEON CPU_SUBTYPE_INTEL(12, 0) -#define CPU_SUBTYPE_XEON_MP CPU_SUBTYPE_INTEL(12, 1) - -#define CPU_SUBTYPE_INTEL_FAMILY(x) ((x) & 15) -#define CPU_SUBTYPE_INTEL_FAMILY_MAX 15 - -#define CPU_SUBTYPE_INTEL_MODEL(x) ((x) >> 4) -#define CPU_SUBTYPE_INTEL_MODEL_ALL 0 +#define CPU_SUBTYPE_INTEL(f, m) ((cpu_subtype_t) (f) + ((m) << 4)) + +#define CPU_SUBTYPE_I386_ALL CPU_SUBTYPE_INTEL(3, 0) +#define CPU_SUBTYPE_386 CPU_SUBTYPE_INTEL(3, 0) +#define CPU_SUBTYPE_486 CPU_SUBTYPE_INTEL(4, 0) +#define CPU_SUBTYPE_486SX CPU_SUBTYPE_INTEL(4, 8) // 8 << 4 = 128 +#define CPU_SUBTYPE_586 CPU_SUBTYPE_INTEL(5, 0) +#define CPU_SUBTYPE_PENT CPU_SUBTYPE_INTEL(5, 0) +#define CPU_SUBTYPE_PENTPRO CPU_SUBTYPE_INTEL(6, 1) +#define CPU_SUBTYPE_PENTII_M3 CPU_SUBTYPE_INTEL(6, 3) +#define CPU_SUBTYPE_PENTII_M5 CPU_SUBTYPE_INTEL(6, 5) +#define CPU_SUBTYPE_CELERON CPU_SUBTYPE_INTEL(7, 6) +#define CPU_SUBTYPE_CELERON_MOBILE CPU_SUBTYPE_INTEL(7, 7) +#define CPU_SUBTYPE_PENTIUM_3 CPU_SUBTYPE_INTEL(8, 0) +#define CPU_SUBTYPE_PENTIUM_3_M CPU_SUBTYPE_INTEL(8, 1) +#define CPU_SUBTYPE_PENTIUM_3_XEON CPU_SUBTYPE_INTEL(8, 2) +#define CPU_SUBTYPE_PENTIUM_M CPU_SUBTYPE_INTEL(9, 0) +#define CPU_SUBTYPE_PENTIUM_4 CPU_SUBTYPE_INTEL(10, 0) +#define CPU_SUBTYPE_PENTIUM_4_M CPU_SUBTYPE_INTEL(10, 1) +#define CPU_SUBTYPE_ITANIUM CPU_SUBTYPE_INTEL(11, 0) +#define CPU_SUBTYPE_ITANIUM_2 CPU_SUBTYPE_INTEL(11, 1) +#define CPU_SUBTYPE_XEON CPU_SUBTYPE_INTEL(12, 0) +#define CPU_SUBTYPE_XEON_MP CPU_SUBTYPE_INTEL(12, 1) + +#define CPU_SUBTYPE_INTEL_FAMILY(x) ((x) & 15) +#define CPU_SUBTYPE_INTEL_FAMILY_MAX 15 + +#define CPU_SUBTYPE_INTEL_MODEL(x) ((x) >> 4) +#define CPU_SUBTYPE_INTEL_MODEL_ALL 0 /* * X86 subtypes. */ -#define CPU_SUBTYPE_X86_ALL ((cpu_subtype_t)3) -#define CPU_SUBTYPE_X86_64_ALL ((cpu_subtype_t)3) -#define CPU_SUBTYPE_X86_ARCH1 ((cpu_subtype_t)4) -#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell feature subset */ +#define CPU_SUBTYPE_X86_ALL ((cpu_subtype_t)3) +#define CPU_SUBTYPE_X86_64_ALL ((cpu_subtype_t)3) +#define CPU_SUBTYPE_X86_ARCH1 ((cpu_subtype_t)4) +#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell feature subset */ -#define CPU_THREADTYPE_INTEL_HTT ((cpu_threadtype_t) 1) +#define CPU_THREADTYPE_INTEL_HTT ((cpu_threadtype_t) 1) /* * Mips subtypes. */ -#define CPU_SUBTYPE_MIPS_ALL ((cpu_subtype_t) 0) -#define CPU_SUBTYPE_MIPS_R2300 ((cpu_subtype_t) 1) -#define CPU_SUBTYPE_MIPS_R2600 ((cpu_subtype_t) 2) -#define CPU_SUBTYPE_MIPS_R2800 ((cpu_subtype_t) 3) -#define CPU_SUBTYPE_MIPS_R2000a ((cpu_subtype_t) 4) /* pmax */ -#define CPU_SUBTYPE_MIPS_R2000 ((cpu_subtype_t) 5) -#define CPU_SUBTYPE_MIPS_R3000a ((cpu_subtype_t) 6) /* 3max */ -#define CPU_SUBTYPE_MIPS_R3000 ((cpu_subtype_t) 7) +#define CPU_SUBTYPE_MIPS_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_MIPS_R2300 ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_MIPS_R2600 ((cpu_subtype_t) 2) +#define CPU_SUBTYPE_MIPS_R2800 ((cpu_subtype_t) 3) +#define CPU_SUBTYPE_MIPS_R2000a ((cpu_subtype_t) 4) /* pmax */ +#define CPU_SUBTYPE_MIPS_R2000 ((cpu_subtype_t) 5) +#define CPU_SUBTYPE_MIPS_R3000a ((cpu_subtype_t) 6) /* 3max */ +#define CPU_SUBTYPE_MIPS_R3000 ((cpu_subtype_t) 7) /* * MC98000 (PowerPC) subtypes */ -#define CPU_SUBTYPE_MC98000_ALL ((cpu_subtype_t) 0) -#define CPU_SUBTYPE_MC98601 ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_MC98000_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_MC98601 ((cpu_subtype_t) 1) /* * HPPA subtypes for Hewlett-Packard HP-PA family of - * risc processors. Port by NeXT to 700 series. + * risc processors. Port by NeXT to 700 series. */ -#define CPU_SUBTYPE_HPPA_ALL ((cpu_subtype_t) 0) -#define CPU_SUBTYPE_HPPA_7100 ((cpu_subtype_t) 0) /* compat */ -#define CPU_SUBTYPE_HPPA_7100LC ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_HPPA_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_HPPA_7100 ((cpu_subtype_t) 0) /* compat */ +#define CPU_SUBTYPE_HPPA_7100LC ((cpu_subtype_t) 1) /* * MC88000 subtypes. */ -#define CPU_SUBTYPE_MC88000_ALL ((cpu_subtype_t) 0) -#define CPU_SUBTYPE_MC88100 ((cpu_subtype_t) 1) -#define CPU_SUBTYPE_MC88110 ((cpu_subtype_t) 2) +#define CPU_SUBTYPE_MC88000_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_MC88100 ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_MC88110 ((cpu_subtype_t) 2) /* * SPARC subtypes */ -#define CPU_SUBTYPE_SPARC_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_SPARC_ALL ((cpu_subtype_t) 0) /* * I860 subtypes */ -#define CPU_SUBTYPE_I860_ALL ((cpu_subtype_t) 0) -#define CPU_SUBTYPE_I860_860 ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_I860_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_I860_860 ((cpu_subtype_t) 1) /* * PowerPC subtypes */ -#define CPU_SUBTYPE_POWERPC_ALL ((cpu_subtype_t) 0) -#define CPU_SUBTYPE_POWERPC_601 ((cpu_subtype_t) 1) -#define CPU_SUBTYPE_POWERPC_602 ((cpu_subtype_t) 2) -#define CPU_SUBTYPE_POWERPC_603 ((cpu_subtype_t) 3) -#define CPU_SUBTYPE_POWERPC_603e ((cpu_subtype_t) 4) -#define CPU_SUBTYPE_POWERPC_603ev ((cpu_subtype_t) 5) -#define CPU_SUBTYPE_POWERPC_604 ((cpu_subtype_t) 6) -#define CPU_SUBTYPE_POWERPC_604e ((cpu_subtype_t) 7) -#define CPU_SUBTYPE_POWERPC_620 ((cpu_subtype_t) 8) -#define CPU_SUBTYPE_POWERPC_750 ((cpu_subtype_t) 9) -#define CPU_SUBTYPE_POWERPC_7400 ((cpu_subtype_t) 10) -#define CPU_SUBTYPE_POWERPC_7450 ((cpu_subtype_t) 11) -#define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100) +#define CPU_SUBTYPE_POWERPC_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_POWERPC_601 ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_POWERPC_602 ((cpu_subtype_t) 2) +#define CPU_SUBTYPE_POWERPC_603 ((cpu_subtype_t) 3) +#define CPU_SUBTYPE_POWERPC_603e ((cpu_subtype_t) 4) +#define CPU_SUBTYPE_POWERPC_603ev ((cpu_subtype_t) 5) +#define CPU_SUBTYPE_POWERPC_604 ((cpu_subtype_t) 6) +#define CPU_SUBTYPE_POWERPC_604e ((cpu_subtype_t) 7) +#define CPU_SUBTYPE_POWERPC_620 ((cpu_subtype_t) 8) +#define CPU_SUBTYPE_POWERPC_750 ((cpu_subtype_t) 9) +#define CPU_SUBTYPE_POWERPC_7400 ((cpu_subtype_t) 10) +#define CPU_SUBTYPE_POWERPC_7450 ((cpu_subtype_t) 11) +#define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100) /* * ARM subtypes @@ -303,8 +365,38 @@ typedef integer_t cpu_threadtype_t; #define CPU_SUBTYPE_ARM_V4T ((cpu_subtype_t) 5) #define CPU_SUBTYPE_ARM_V6 ((cpu_subtype_t) 6) #define CPU_SUBTYPE_ARM_V5TEJ ((cpu_subtype_t) 7) -#define CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8) -#define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9) +#define CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8) +#define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9) /* ARMv7-A and ARMv7-R */ +#define CPU_SUBTYPE_ARM_V7F ((cpu_subtype_t) 10) /* Cortex A9 */ +#define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t) 11) /* Swift */ +#define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t) 12) +#define CPU_SUBTYPE_ARM_V8 ((cpu_subtype_t) 13) +#define CPU_SUBTYPE_ARM_V6M ((cpu_subtype_t) 14) /* Not meant to be run under xnu */ +#define CPU_SUBTYPE_ARM_V7M ((cpu_subtype_t) 15) /* Not meant to be run under xnu */ +#define CPU_SUBTYPE_ARM_V7EM ((cpu_subtype_t) 16) /* Not meant to be run under xnu */ +#define CPU_SUBTYPE_ARM_V8M ((cpu_subtype_t) 17) /* Not meant to be run under xnu */ + +/* + * ARM64 subtypes + */ +#define CPU_SUBTYPE_ARM64_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_ARM64_V8 ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_ARM64E ((cpu_subtype_t) 2) + +/* CPU subtype feature flags for ptrauth on arm64e platforms */ +#define CPU_SUBTYPE_ARM64_PTR_AUTH_MASK 0x0f000000 +#define CPU_SUBTYPE_ARM64_PTR_AUTH_VERSION(x) (((x) & CPU_SUBTYPE_ARM64_PTR_AUTH_MASK) >> 24) +#ifdef PRIVATE +#define CPU_SUBTYPE_ARM64_PTR_AUTH_CURRENT_VERSION 0 +#endif /* PRIVATE */ + +/* + * ARM64_32 subtypes + */ +#define CPU_SUBTYPE_ARM64_32_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_ARM64_32_V8 ((cpu_subtype_t) 1) + +#endif /* !__ASSEMBLER__ */ /* * CPU families (sysctl hw.cpufamily) @@ -317,31 +409,53 @@ typedef integer_t cpu_threadtype_t; * Use feature flags (eg, hw.optional.altivec) to test for optional * functionality. */ -#define CPUFAMILY_UNKNOWN 0 -#define CPUFAMILY_POWERPC_G3 0xcee41549 -#define CPUFAMILY_POWERPC_G4 0x77c184ae -#define CPUFAMILY_POWERPC_G5 0xed76d8aa -#define CPUFAMILY_INTEL_6_13 0xaa33392b -#define CPUFAMILY_INTEL_YONAH 0x73d67300 -#define CPUFAMILY_INTEL_MEROM 0x426f69ef -#define CPUFAMILY_INTEL_PENRYN 0x78ea4fbc -#define CPUFAMILY_INTEL_NEHALEM 0x6b5a4cd2 -#define CPUFAMILY_INTEL_WESTMERE 0x573b5eec -#define CPUFAMILY_INTEL_SANDYBRIDGE 0x5490b78c -#define CPUFAMILY_ARM_9 0xe73283ae -#define CPUFAMILY_ARM_11 0x8ff620d8 -#define CPUFAMILY_ARM_XSCALE 0x53b005f5 -#define CPUFAMILY_ARM_13 0x0cc90e64 -#define CPUFAMILY_ARM_14 0x96077ef1 +#define CPUFAMILY_UNKNOWN 0 +#define CPUFAMILY_POWERPC_G3 0xcee41549 +#define CPUFAMILY_POWERPC_G4 0x77c184ae +#define CPUFAMILY_POWERPC_G5 0xed76d8aa +#define CPUFAMILY_INTEL_6_13 0xaa33392b +#define CPUFAMILY_INTEL_PENRYN 0x78ea4fbc +#define CPUFAMILY_INTEL_NEHALEM 0x6b5a4cd2 +#define CPUFAMILY_INTEL_WESTMERE 0x573b5eec +#define CPUFAMILY_INTEL_SANDYBRIDGE 0x5490b78c +#define CPUFAMILY_INTEL_IVYBRIDGE 0x1f65e835 +#define CPUFAMILY_INTEL_HASWELL 0x10b282dc +#define CPUFAMILY_INTEL_BROADWELL 0x582ed09c +#define CPUFAMILY_INTEL_SKYLAKE 0x37fc219f +#define CPUFAMILY_INTEL_KABYLAKE 0x0f817246 +#define CPUFAMILY_INTEL_ICELAKE 0x38435547 +#define CPUFAMILY_ARM_9 0xe73283ae +#define CPUFAMILY_ARM_11 0x8ff620d8 +#define CPUFAMILY_ARM_XSCALE 0x53b005f5 +#define CPUFAMILY_ARM_12 0xbd1b0ae9 +#define CPUFAMILY_ARM_13 0x0cc90e64 +#define CPUFAMILY_ARM_14 0x96077ef1 +#define CPUFAMILY_ARM_15 0xa8511bca +#define CPUFAMILY_ARM_SWIFT 0x1e2d6381 +#define CPUFAMILY_ARM_CYCLONE 0x37a09642 +#define CPUFAMILY_ARM_TYPHOON 0x2c91a47e +#define CPUFAMILY_ARM_TWISTER 0x92fb37c8 +#define CPUFAMILY_ARM_HURRICANE 0x67ceee93 +#define CPUFAMILY_ARM_MONSOON_MISTRAL 0xe81e7ef6 +#define CPUFAMILY_ARM_VORTEX_TEMPEST 0x07d34b9f +#define CPUFAMILY_ARM_LIGHTNING_THUNDER 0x462504d2 +#ifndef RC_HIDE_XNU_FIRESTORM +#define CPUFAMILY_ARM_FIRESTORM_ICESTORM 0x1b588bb3 +#endif /* !RC_HIDE_XNU_FIRESTORM */ + +/* Described in rdar://64125549 */ +#define CPUSUBFAMILY_UNKNOWN 0 +#define CPUSUBFAMILY_ARM_HP 1 +#define CPUSUBFAMILY_ARM_HG 2 +#define CPUSUBFAMILY_ARM_M 3 +#ifndef RC_HIDE_XNU_FIRESTORM +#define CPUSUBFAMILY_ARM_HS 4 +#define CPUSUBFAMILY_ARM_HC_HD 5 +#endif /* !RC_HIDE_XNU_FIRESTORM */ /* The following synonyms are deprecated: */ -#define CPUFAMILY_INTEL_6_14 CPUFAMILY_INTEL_YONAH -#define CPUFAMILY_INTEL_6_15 CPUFAMILY_INTEL_MEROM -#define CPUFAMILY_INTEL_6_23 CPUFAMILY_INTEL_PENRYN -#define CPUFAMILY_INTEL_6_26 CPUFAMILY_INTEL_NEHALEM - -#define CPUFAMILY_INTEL_CORE CPUFAMILY_INTEL_YONAH -#define CPUFAMILY_INTEL_CORE2 CPUFAMILY_INTEL_MEROM +#define CPUFAMILY_INTEL_6_23 CPUFAMILY_INTEL_PENRYN +#define CPUFAMILY_INTEL_6_26 CPUFAMILY_INTEL_NEHALEM -#endif /* _MACH_MACHINE_H_ */ +#endif /* _MACH_MACHINE_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach/machine/boolean.h b/src/third_party/mac_headers/mach/machine/boolean.h index ffdc2390a..adca083dc 100644 --- a/src/third_party/mac_headers/mach/machine/boolean.h +++ b/src/third_party/mac_headers/mach/machine/boolean.h @@ -2,7 +2,7 @@ * Copyright (c) 2000-2007 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,7 +22,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ @@ -31,10 +31,10 @@ #if defined (__i386__) || defined(__x86_64__) #include "mach/i386/boolean.h" -#elif defined (__arm__) +#elif defined (__arm__) || defined (__arm64__) || defined(__aarch64__) #include "mach/arm/boolean.h" #else #error architecture not supported #endif -#endif /* _MACH_MACHINE_BOOLEAN_H_ */ +#endif /* _MACH_MACHINE_BOOLEAN_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach/machine/thread_state.h b/src/third_party/mac_headers/mach/machine/thread_state.h index 1547acac7..fceb4279e 100644 --- a/src/third_party/mac_headers/mach/machine/thread_state.h +++ b/src/third_party/mac_headers/mach/machine/thread_state.h @@ -6,4 +6,4 @@ #define THREAD_STATE_MAX 1 -#endif /* _MACH_MACHINE_THREAD_STATE_H_ */ +#endif /* _MACH_MACHINE_THREAD_STATE_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach/machine/thread_status.h b/src/third_party/mac_headers/mach/machine/thread_status.h index d1ab56ad5..4309afdc3 100644 --- a/src/third_party/mac_headers/mach/machine/thread_status.h +++ b/src/third_party/mac_headers/mach/machine/thread_status.h @@ -1 +1 @@ -/* This file intentionally left blank */ +/* This file intentionally left blank */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach/machine/vm_types.h b/src/third_party/mac_headers/mach/machine/vm_types.h index 8ccd24be5..7ee7ac8e8 100644 --- a/src/third_party/mac_headers/mach/machine/vm_types.h +++ b/src/third_party/mac_headers/mach/machine/vm_types.h @@ -2,7 +2,7 @@ * Copyright (c) 2000-2007 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,7 +22,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ @@ -31,10 +31,10 @@ #if defined (__i386__) || defined(__x86_64__) #include "mach/i386/vm_types.h" -#elif defined (__arm__) +#elif defined (__arm__) || defined (__arm64__) || defined(__aarch64__) #include "mach/arm/vm_types.h" #else #error architecture not supported #endif -#endif /* _MACH_MACHINE_VM_TYPES_H_ */ +#endif /* _MACH_MACHINE_VM_TYPES_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach/thread_status.h b/src/third_party/mac_headers/mach/thread_status.h index aead09bf9..f742500ca 100644 --- a/src/third_party/mac_headers/mach/thread_status.h +++ b/src/third_party/mac_headers/mach/thread_status.h @@ -2,7 +2,7 @@ * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,7 +22,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* @@ -32,24 +32,24 @@ * Mach Operating System * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University * All Rights Reserved. - * + * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * + * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to - * + * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 - * + * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ @@ -65,8 +65,8 @@ * */ -#ifndef _MACH_THREAD_STATUS_H_ -#define _MACH_THREAD_STATUS_H_ +#ifndef _MACH_THREAD_STATUS_H_ +#define _MACH_THREAD_STATUS_H_ /* * The actual structure that comprises the thread state is defined @@ -80,15 +80,21 @@ * Generic definition for machine-dependent thread status. */ -typedef natural_t *thread_state_t; /* Variable-length array */ +typedef natural_t *thread_state_t; /* Variable-length array */ /* THREAD_STATE_MAX is now defined in */ -typedef natural_t thread_state_data_t[THREAD_STATE_MAX]; +typedef natural_t thread_state_data_t[THREAD_STATE_MAX]; + +#define THREAD_STATE_FLAVOR_LIST 0 /* List of valid flavors */ +#define THREAD_STATE_FLAVOR_LIST_NEW 128 +#define THREAD_STATE_FLAVOR_LIST_10_9 129 +#define THREAD_STATE_FLAVOR_LIST_10_13 130 +#define THREAD_STATE_FLAVOR_LIST_10_15 131 -#define THREAD_STATE_FLAVOR_LIST 0 /* List of valid flavors */ -#define THREAD_STATE_FLAVOR_LIST_NEW 128 +typedef int thread_state_flavor_t; +typedef thread_state_flavor_t *thread_state_flavor_array_t; -typedef int thread_state_flavor_t; -typedef thread_state_flavor_t *thread_state_flavor_array_t; +#define THREAD_CONVERT_THREAD_STATE_TO_SELF 1 +#define THREAD_CONVERT_THREAD_STATE_FROM_SELF 2 -#endif /* _MACH_THREAD_STATUS_H_ */ +#endif /* _MACH_THREAD_STATUS_H_ */ \ No newline at end of file diff --git a/src/third_party/mac_headers/mach/vm_prot.h b/src/third_party/mac_headers/mach/vm_prot.h index 07c2114e5..b19c8e247 100644 --- a/src/third_party/mac_headers/mach/vm_prot.h +++ b/src/third_party/mac_headers/mach/vm_prot.h @@ -1,8 +1,8 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2021 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,34 +22,34 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ */ -/* +/* * Mach Operating System * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University * All Rights Reserved. - * + * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * + * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to - * + * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 - * + * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ @@ -63,8 +63,8 @@ * */ -#ifndef _MACH_VM_PROT_H_ -#define _MACH_VM_PROT_H_ +#ifndef _MACH_VM_PROT_H_ +#define _MACH_VM_PROT_H_ /* * Types defined: @@ -72,29 +72,36 @@ * vm_prot_t VM protection values. */ -typedef int vm_prot_t; +typedef int vm_prot_t; /* * Protection values, defined as bits within the vm_prot_t type */ -#define VM_PROT_NONE ((vm_prot_t) 0x00) +#define VM_PROT_NONE ((vm_prot_t) 0x00) -#define VM_PROT_READ ((vm_prot_t) 0x01) /* read permission */ -#define VM_PROT_WRITE ((vm_prot_t) 0x02) /* write permission */ -#define VM_PROT_EXECUTE ((vm_prot_t) 0x04) /* execute permission */ +#define VM_PROT_READ ((vm_prot_t) 0x01) /* read permission */ +#define VM_PROT_WRITE ((vm_prot_t) 0x02) /* write permission */ +#define VM_PROT_EXECUTE ((vm_prot_t) 0x04) /* execute permission */ /* * The default protection for newly-created virtual memory */ -#define VM_PROT_DEFAULT (VM_PROT_READ|VM_PROT_WRITE) +#define VM_PROT_DEFAULT (VM_PROT_READ|VM_PROT_WRITE) /* * The maximum privileges possible, for parameter checking. */ -#define VM_PROT_ALL (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE) +#define VM_PROT_ALL (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE) + +/* + * This is an alias to VM_PROT_EXECUTE to identify callers that + * want to allocate an hardware assisted Read-only/read-write + * trusted path in userland. + */ +#define VM_PROT_RORW_TP (VM_PROT_EXECUTE) /* * An invalid protection value. @@ -103,15 +110,16 @@ typedef int vm_prot_t; * looks like VM_PROT_ALL and then some. */ -#define VM_PROT_NO_CHANGE ((vm_prot_t) 0x08) +#define VM_PROT_NO_CHANGE_LEGACY ((vm_prot_t) 0x08) +#define VM_PROT_NO_CHANGE ((vm_prot_t) 0x01000000) -/* +/* * When a caller finds that he cannot obtain write permission on a * mapped entry, the following flag can be used. The entry will * be made "needs copy" effectively copying the object (using COW), * and write permission will be added to the maximum protections - * for the associated entry. - */ + * for the associated entry. + */ #define VM_PROT_COPY ((vm_prot_t) 0x10) @@ -127,14 +135,59 @@ typedef int vm_prot_t; * walking down the shadow chain. */ -#define VM_PROT_WANTS_COPY ((vm_prot_t) 0x10) +#define VM_PROT_WANTS_COPY ((vm_prot_t) 0x10) +#ifdef PRIVATE +/* + * The caller wants this memory region treated as if it had a valid + * code signature. + */ + +#define VM_PROT_TRUSTED ((vm_prot_t) 0x20) +#endif /* PRIVATE */ /* - * Another invalid protection value. + * Another invalid protection value. * Indicates that the other protection bits are to be applied as a mask * against the actual protection bits of the map entry. */ -#define VM_PROT_IS_MASK ((vm_prot_t) 0x40) +#define VM_PROT_IS_MASK ((vm_prot_t) 0x40) + +/* + * Another invalid protection value to support execute-only protection. + * VM_PROT_STRIP_READ is a special marker that tells mprotect to not + * set VM_PROT_READ. We have to do it this way because existing code + * expects the system to set VM_PROT_READ if VM_PROT_EXECUTE is set. + * VM_PROT_EXECUTE_ONLY is just a convenience value to indicate that + * the memory should be executable and explicitly not readable. It will + * be ignored on platforms that do not support this type of protection. + */ +#define VM_PROT_STRIP_READ ((vm_prot_t) 0x80) +#define VM_PROT_EXECUTE_ONLY (VM_PROT_EXECUTE|VM_PROT_STRIP_READ) + +#ifdef PRIVATE +/* + * When using VM_PROT_COPY, fail instead of copying an executable mapping, + * since that could cause code-signing violations. + */ +#define VM_PROT_COPY_FAIL_IF_EXECUTABLE ((vm_prot_t)0x100) +#endif /* PRIVATE */ + +#if defined(__x86_64__) +/* + * Another invalid protection value to support specifying different + * execute permissions for user- and supervisor- modes. When + * MBE is enabled in a VM, VM_PROT_EXECUTE is used to indicate + * supervisor-mode execute permission, and VM_PROT_UEXEC specifies + * user-mode execute permission. Currently only used by the + * x86 Hypervisor kext. + */ +#define VM_PROT_UEXEC ((vm_prot_t) 0x8) /* User-mode Execute Permission */ + +#define VM_PROT_ALLEXEC (VM_PROT_EXECUTE | VM_PROT_UEXEC) +#else +#define VM_PROT_ALLEXEC (VM_PROT_EXECUTE) +#endif /* defined(__x86_64__) */ + -#endif /* _MACH_VM_PROT_H_ */ +#endif /* _MACH_VM_PROT_H_ */ \ No newline at end of file diff --git a/src/tools/linux/core2md/core2md.cc b/src/tools/linux/core2md/core2md.cc index c3a9da398..ec4a012a9 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. // @@ -29,17 +28,23 @@ // core2md.cc: A utility to convert an ELF core file to a minidump file. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #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 \n", argv0); + fprintf(stderr, "Usage: %s \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 index 3148cc53c..8a1d97662 100644 --- a/src/tools/linux/core_handler/core_handler.cc +++ b/src/tools/linux/core_handler/core_handler.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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,6 +28,10 @@ // core_handler.cc: A tool to handle coredumps on Linux +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -40,6 +43,7 @@ #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 { @@ -58,7 +62,8 @@ using google_breakpad::scoped_array; const int core_read_size = 1024 * 1024; void ShowUsage(const char* argv0) { - fprintf(stderr, "Usage: %s \n\n", argv0); + fprintf(stderr, "Usage: %s \n\n", + google_breakpad::BaseName(argv0).c_str()); fprintf(stderr, "A tool which serves as a core dump handler and produces " "minidump files.\n"); diff --git a/src/tools/linux/dump_syms/dump_syms.cc b/src/tools/linux/dump_syms/dump_syms.cc index 42e582c6e..f5f89f410 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. // @@ -27,55 +26,84 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include +#include #include -#include #include #include #include #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] " - "[directories-for-debug-file]\n\n", self); + fprintf(stderr, + "Usage: %s [OPTION] " + "[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, " -a Preserve the load address - Do not normalize " + "the load address to zero.\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, " -b Use specified id for the module id\n"); fprintf(stderr, " -n Use specified name for name of the object\n"); fprintf(stderr, " -o 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) { if (argc < 2) return usage(argv[0]); + bool preserve_load_address = false; 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; + std::string module_id; const char* obj_os = "Linux"; int arg_index = 1; while (arg_index < argc && strlen(argv[arg_index]) > 0 && argv[arg_index][0] == '-') { if (strcmp("-i", argv[arg_index]) == 0) { header_only = true; + } else if (strcmp("-a", argv[arg_index]) == 0) { + preserve_load_address = 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) { log_to_stderr = true; + } else if (strcmp("-b", argv[arg_index]) == 0) { + if (arg_index + 1 >= argc) { + fprintf(stderr, "Missing argument to -b\n"); + return usage(argv[0]); + } + module_id = argv[arg_index + 1]; + ++arg_index; } else if (strcmp("-n", argv[arg_index]) == 0) { if (arg_index + 1 >= argc) { fprintf(stderr, "Missing argument to -n\n"); @@ -90,6 +118,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]); @@ -119,14 +149,16 @@ int main(int argc, char** argv) { obj_name = binary; if (header_only) { - if (!WriteSymbolFileHeader(binary, obj_name, obj_os, std::cout)) { + if (!WriteSymbolFileHeader(binary, obj_name, obj_os, module_id, std::cout)) { fprintf(saved_stderr, "Failed to process file.\n"); return 1; } } else { - SymbolData symbol_data = cfi ? ALL_SYMBOL_DATA : NO_CFI; - google_breakpad::DumpOptions options(symbol_data, handle_inter_cu_refs); - if (!WriteSymbolFile(binary, obj_name, obj_os, debug_dirs, options, + 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, preserve_load_address); + if (!WriteSymbolFile(binary, obj_name, obj_os, module_id, debug_dirs, options, std::cout)) { fprintf(saved_stderr, "Failed to write symbol file.\n"); return 1; diff --git a/src/tools/linux/md2core/minidump-2-core.cc b/src/tools/linux/md2core/minidump-2-core.cc index aade82c99..d60de5fcf 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. // @@ -31,6 +30,10 @@ // Large parts lifted from the userspace core dumper: // http://code.google.com/p/google-coredumper/ +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -46,6 +49,7 @@ #include #include "common/linux/memory_mapped_file.h" +#include "common/memory_allocator.h" #include "common/minidump_type_helper.h" #include "common/path_helper.h" #include "common/scoped_ptr.h" @@ -77,6 +81,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 +90,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 @@ -92,6 +98,7 @@ typedef gregset_t user_regs_struct; using google_breakpad::MDTypeHelper; using google_breakpad::MemoryMappedFile; using google_breakpad::MinidumpMemoryRange; +using google_breakpad::PageAllocator; typedef MDTypeHelper::MDRawDebug MDRawDebug; typedef MDTypeHelper::MDRawLinkMap MDRawLinkMap; @@ -142,7 +149,7 @@ static void SetupOptions(int argc, const char* argv[], Options* options) { extern int optind; int ch; - const char* output_file = NULL; + const char* output_file = nullptr; // Initialize the options struct as needed. options->verbose = false; @@ -154,11 +161,9 @@ SetupOptions(int argc, const char* argv[], Options* options) { case 'h': Usage(argc, argv); exit(0); - break; case '?': Usage(argc, argv); exit(1); - break; case 'f': options->use_filename = true; @@ -184,7 +189,7 @@ SetupOptions(int argc, const char* argv[], Options* options) { exit(1); } - if (output_file == NULL || !strcmp(output_file, "-")) { + if (output_file == nullptr || !strcmp(output_file, "-")) { options->out_fd = STDOUT_FILENO; } else { options->out_fd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0664); @@ -261,7 +266,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 @@ -279,8 +284,8 @@ typedef struct prpsinfo { /* Information about process */ // We parse the minidump file and keep the parsed information in this structure struct CrashedProcess { CrashedProcess() - : crashing_tid(-1), - auxv(NULL), + : exception{-1}, + auxv(nullptr), auxv_length(0) { memset(&prps, 0, sizeof(prps)); prps.pr_sname = 'R'; @@ -303,12 +308,11 @@ struct CrashedProcess { }; std::map mappings; - pid_t crashing_tid; int fatal_signal; struct Thread { pid_t tid; -#if defined(__mips__) +#if defined(__mips__) || defined(__riscv) mcontext_t mcontext; #else user_regs_struct regs; @@ -327,6 +331,7 @@ struct CrashedProcess { size_t stack_length; }; std::vector threads; + Thread exception; const uint8_t* auxv; size_t auxv_length; @@ -346,6 +351,34 @@ struct CrashedProcess { std::vector link_map; }; +/* NT_FILE note as defined by linux kernel in fs/binfmt_elf.c + * is structured as: + * long count -- how many files are mapped + * long page_size -- units for file_ofs + * array of [COUNT] elements of + * long start + * long end + * long file_ofs + * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... + * we can re-use the file mappings info + */ +struct NtFileNote { + NtFileNote() + // XXX: we really should source page size from the minidump itself but + // I cannot find anywhere in the minidump generation code where this + // would be stashed. + : page_sz((unsigned long)getpagesize()), + filename_count(0), + filenames_length(0) { + } + + unsigned long page_sz; + unsigned long filename_count; + std::vector file_mappings; + std::vector filenames; + size_t filenames_length; +}; + #if defined(__i386__) static uint32_t U32(const uint8_t* data) { @@ -535,6 +568,67 @@ 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(0); +# elif __riscv_xlen == 64 + const MDRawContextRISCV64* rawregs = range.GetData(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; + + // Breakpad only supports RISCV32 with 32 bit floating point. + // Breakpad only supports RISCV64 with 64 bit floating point. +#if __riscv_xlen == 32 + for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; ++i) { + thread->mcontext.__fpregs.__f.__f[i] = rawregs->fpregs[i]; + } + thread->mcontext.__fpregs.__f.__fcsr = rawregs->fcsr; +#elif __riscv_xlen == 64 + for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; ++i) { + thread->mcontext.__fpregs.__d.__f[i] = rawregs->fpregs[i]; + } + thread->mcontext.__fpregs.__d.__fcsr = rawregs->fcsr; +#else +#error "Unexpected __riscv_xlen" +#endif +} #else #error "This code has not been ported to your platform yet" #endif @@ -602,7 +696,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 +718,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 +761,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, @@ -718,8 +832,8 @@ ParseMaps(const Options& options, CrashedProcess* crashinfo, eol ? eol - ptr : range.data() + range.length() - ptr); ptr = eol ? eol + 1 : range.data() + range.length(); unsigned long long start, stop, offset; - char* permissions = NULL; - char* filename = NULL; + char* permissions = nullptr; + char* filename = nullptr; sscanf(line.c_str(), "%llx-%llx %m[-rwxp] %llx %*[:0-9a-f] %*d %ms", &start, &stop, &permissions, &offset, &filename); if (filename && *filename == '/') { @@ -911,10 +1025,25 @@ ParseDSODebugInfo(const Options& options, CrashedProcess* crashinfo, static void ParseExceptionStream(const Options& options, CrashedProcess* crashinfo, - const MinidumpMemoryRange& range) { + const MinidumpMemoryRange& range, + const MinidumpMemoryRange& full_file) { const MDRawExceptionStream* exp = range.GetData(0); - crashinfo->crashing_tid = exp->thread_id; + if (!exp) { + return; + } + if (options.verbose) { + fprintf(stderr, + "MD_EXCEPTION_STREAM:\n" + "Found exception thread %" PRIu32 " \n" + "\n\n", + exp->thread_id); + } crashinfo->fatal_signal = (int) exp->exception_record.exception_code; + crashinfo->exception = {}; + crashinfo->exception.tid = exp->thread_id; + // crashinfo->threads[].tid == crashinfo->exception.tid provides the stack. + ParseThreadRegisters(&crashinfo->exception, + full_file.Subrange(exp->thread_context)); } static bool @@ -928,6 +1057,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 @@ -1061,8 +1192,7 @@ AddDataToMapping(CrashedProcess* crashinfo, const string& data, CrashedProcess::Mapping mapping; mapping.permissions = PF_R | PF_W; mapping.start_address = addr & ~4095; - mapping.end_address = - (addr + data.size() + 4095) & ~4095; + mapping.end_address = PageAllocator::AlignUp(addr + data.size(), 4096); mapping.data.assign(addr & 4095, 0).append(data); mapping.data.append(-mapping.data.size() & 4095, 0); crashinfo->mappings[mapping.start_address] = mapping; @@ -1161,9 +1291,9 @@ AugmentMappings(const Options& options, CrashedProcess* crashinfo, if (std::distance(iter, crashinfo->link_map.end()) == 1) { link_map.l_next = 0; } else { - link_map.l_next = (struct link_map*)(start_addr + data.size() + - sizeof(link_map) + - ((filename.size() + 8) & ~7)); + link_map.l_next = + (struct link_map*)(start_addr + data.size() + sizeof(link_map) + + PageAllocator::AlignUp(filename.size(), 8)); } data.append((char*)&link_map, sizeof(link_map)); data.append(filename); @@ -1197,6 +1327,8 @@ AugmentMappings(const Options& options, CrashedProcess* crashinfo, } AddDataToMapping(crashinfo, crashinfo->dynamic_data, (uintptr_t)crashinfo->debug.dynamic); + } else { + fprintf(stderr, "dynamic data empty\n"); } } @@ -1275,7 +1407,7 @@ main(int argc, const char* argv[]) { break; case MD_EXCEPTION_STREAM: ParseExceptionStream(options, &crashinfo, - dump.Subrange(dirent->location)); + dump.Subrange(dirent->location), dump); break; case MD_MODULE_LIST_STREAM: ParseModuleStream(options, &crashinfo, dump.Subrange(dirent->location), @@ -1316,19 +1448,40 @@ main(int argc, const char* argv[]) { if (!writea(options.out_fd, &ehdr, sizeof(Ehdr))) return 1; + struct NtFileNote nt_file; + for (auto iter = crashinfo.mappings.begin(); + iter != crashinfo.mappings.end(); iter++) { + if (iter->second.filename.empty()) + continue; + nt_file.file_mappings.push_back(iter->second.start_address); + nt_file.file_mappings.push_back(iter->second.end_address); + nt_file.file_mappings.push_back(iter->second.offset); + nt_file.filenames.push_back(iter->second.filename); + nt_file.filenames_length += iter->second.filename.length() + 1; + nt_file.filename_count += 1; + } + // implementation of NT_FILE note seems to pad alignment by 4 bytes but + // keep the header size the true size of the note. so we keep nt_file_align + // as separate field. + size_t nt_file_data_sz = (2 * sizeof(unsigned long)) + + (nt_file.file_mappings.size() * sizeof(unsigned long)) + + nt_file.filenames_length; + size_t nt_file_align = nt_file_data_sz % 4 == 0 ? 0 : 4 - + (nt_file_data_sz % 4); size_t offset = sizeof(Ehdr) + ehdr.e_phnum * sizeof(Phdr); size_t filesz = sizeof(Nhdr) + 8 + sizeof(prpsinfo) + - // sizeof(Nhdr) + 8 + sizeof(user) + - sizeof(Nhdr) + 8 + crashinfo.auxv_length + - crashinfo.threads.size() * ( - (sizeof(Nhdr) + 8 + sizeof(prstatus)) + // sizeof(Nhdr) + 8 + sizeof(user) + + sizeof(Nhdr) + 8 + crashinfo.auxv_length + + sizeof(Nhdr) + 8 + nt_file_data_sz + nt_file_align + + crashinfo.threads.size() * ( + (sizeof(Nhdr) + 8 + sizeof(prstatus)) #if defined(__i386__) || defined(__x86_64__) - + sizeof(Nhdr) + 8 + sizeof(user_fpregs_struct) + + sizeof(Nhdr) + 8 + sizeof(user_fpregs_struct) #endif #if defined(__i386__) - + sizeof(Nhdr) + 8 + sizeof(user_fpxregs_struct) + + sizeof(Nhdr) + 8 + sizeof(user_fpxregs_struct) #endif - ); + ); Phdr phdr; memset(&phdr, 0, sizeof(Phdr)); @@ -1391,16 +1544,43 @@ main(int argc, const char* argv[]) { return 1; } - for (unsigned i = 0; i < crashinfo.threads.size(); ++i) { - if (crashinfo.threads[i].tid == crashinfo.crashing_tid) { - WriteThread(options, crashinfo.threads[i], crashinfo.fatal_signal); + nhdr.n_descsz = nt_file_data_sz; + nhdr.n_type = NT_FILE; + if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) || + !writea(options.out_fd, "CORE\0\0\0\0", 8) || + !writea(options.out_fd, + &nt_file.filename_count, sizeof(nt_file.filename_count)) || + !writea(options.out_fd, &nt_file.page_sz, sizeof(nt_file.page_sz))) { + return 1; + } + for (auto iter = nt_file.file_mappings.begin(); + iter != nt_file.file_mappings.end(); iter++) { + if (!writea(options.out_fd, &*iter, sizeof(*iter))) + return 1; + } + for (auto iter = nt_file.filenames.begin(); + iter != nt_file.filenames.end(); iter++) { + if (!writea(options.out_fd, iter->c_str(), iter->length() + 1)) + return 1; + } + if (!writea(options.out_fd, "\0\0\0\0", nt_file_align)) + return 1; + + for (const auto& current_thread : crashinfo.threads) { + if (current_thread.tid == crashinfo.exception.tid) { + // Use the exception record's context for the crashed thread instead of + // the thread's own context. For the crashed thread the thread's own + // context is the state inside the exception handler. Using it would not + // result in the expected stack trace from the time of the crash. + // The stack memory has already been provided by current_thread. + WriteThread(options, crashinfo.exception, crashinfo.fatal_signal); break; } } - for (unsigned i = 0; i < crashinfo.threads.size(); ++i) { - if (crashinfo.threads[i].tid != crashinfo.crashing_tid) - WriteThread(options, crashinfo.threads[i], 0); + for (const auto& current_thread : crashinfo.threads) { + if (current_thread.tid != crashinfo.exception.tid) + WriteThread(options, current_thread, 0); } if (note_align) { diff --git a/src/tools/linux/md2core/minidump_memory_range.h b/src/tools/linux/md2core/minidump_memory_range.h index a793e2cfb..6cf074703 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 fe4ded83d..9c597df40 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. // @@ -30,6 +29,10 @@ // minidump_memory_range_unittest.cc: // Unit tests for google_breakpad::MinidumpMemoryRange. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "tools/linux/md2core/minidump_memory_range.h" @@ -82,11 +85,11 @@ const struct { { 0, 4, 9, kBufferPointer + 36 }, { kBufferSize - 1, 1, 0, kBufferPointer + kBufferSize - 1 }, // Invalid array elemenets - { 0, 1, kBufferSize, NULL }, - { 0, 4, 10, NULL }, - { kBufferSize - 1, 1, 1, NULL }, - { kBufferSize - 1, 2, 0, NULL }, - { kBufferSize, 1, 0, NULL }, + { 0, 1, kBufferSize, nullptr }, + { 0, 4, 10, nullptr }, + { kBufferSize - 1, 1, 1, nullptr }, + { kBufferSize - 1, 2, 0, nullptr }, + { kBufferSize, 1, 0, nullptr }, }; const size_t kNumElements = sizeof(kElements) / sizeof(kElements[0]); @@ -94,7 +97,7 @@ const size_t kNumElements = sizeof(kElements) / sizeof(kElements[0]); TEST(MinidumpMemoryRangeTest, DefaultConstructor) { MinidumpMemoryRange range; - EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(nullptr, range.data()); EXPECT_EQ(0U, range.length()); } @@ -107,7 +110,7 @@ TEST(MinidumpMemoryRangeTest, ConstructorWithDataAndLength) { TEST(MinidumpMemoryRangeTest, Reset) { MinidumpMemoryRange range; range.Reset(); - EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(nullptr, range.data()); EXPECT_EQ(0U, range.length()); range.Set(kBuffer, kBufferSize); @@ -115,7 +118,7 @@ TEST(MinidumpMemoryRangeTest, Reset) { EXPECT_EQ(kBufferSize, range.length()); range.Reset(); - EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(nullptr, range.data()); EXPECT_EQ(0U, range.length()); } @@ -125,15 +128,15 @@ TEST(MinidumpMemoryRangeTest, Set) { EXPECT_EQ(kBufferPointer, range.data()); EXPECT_EQ(kBufferSize, range.length()); - range.Set(NULL, 0); - EXPECT_EQ(NULL, range.data()); + range.Set(nullptr, 0); + EXPECT_EQ(nullptr, range.data()); EXPECT_EQ(0U, range.length()); } TEST(MinidumpMemoryRangeTest, SubrangeOfEmptyMemoryRange) { MinidumpMemoryRange range; MinidumpMemoryRange subrange = range.Subrange(0, 10); - EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(nullptr, subrange.data()); EXPECT_EQ(0U, subrange.length()); } @@ -155,8 +158,8 @@ TEST(MinidumpMemoryRangeTest, SubrangeAndGetData) { EXPECT_EQ(sub_length, subrange.length()); } else { EXPECT_FALSE(range.Covers(sub_offset, sub_length)); - EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length)); - EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(nullptr, range.GetData(sub_offset, sub_length)); + EXPECT_EQ(nullptr, subrange.data()); EXPECT_EQ(0U, subrange.length()); } } @@ -183,8 +186,8 @@ TEST(MinidumpMemoryRangeTest, SubrangeWithMDLocationDescriptor) { EXPECT_EQ(sub_length, subrange.length()); } else { EXPECT_FALSE(range.Covers(sub_offset, sub_length)); - EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length)); - EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(nullptr, range.GetData(sub_offset, sub_length)); + EXPECT_EQ(nullptr, subrange.data()); EXPECT_EQ(0U, subrange.length()); } } diff --git a/src/tools/linux/pid2md/pid2md.cc b/src/tools/linux/pid2md/pid2md.cc index 0481997eb..add12a738 100644 --- a/src/tools/linux/pid2md/pid2md.cc +++ b/src/tools/linux/pid2md/pid2md.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2020, Google Inc. -// All rights reserved. +// Copyright 2020 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google 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,15 +28,21 @@ // pid2md.cc: An utility to generate a minidump from a running process +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include #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 \n\n", argv[0]); + fprintf(stderr, "Usage: %s \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 " diff --git a/src/tools/linux/symupload/minidump_upload.cc b/src/tools/linux/symupload/minidump_upload.cc index f24e9716d..645da8c9e 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. // @@ -34,6 +33,10 @@ // ver: the product version // symbol_file: the breakpad format symbol file +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -41,6 +44,7 @@ #include #include "common/linux/http_upload.h" +#include "common/path_helper.h" #include "common/using_std_string.h" using google_breakpad::HTTPUpload; @@ -74,7 +78,7 @@ static void Start(Options *options) { options->proxy_user_pwd, "", &response, - NULL, + nullptr, &error); if (success) { @@ -91,8 +95,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 -v " - "\n", argv[0]); + fprintf(stderr, + "Usage: %s [options...] -p -v " + "\n", + google_breakpad::BaseName(argv[0]).c_str()); fprintf(stderr, "Options:\n"); fprintf(stderr, " should be a minidump.\n"); fprintf(stderr, " is the destination for the upload\n"); diff --git a/src/tools/linux/symupload/sym_upload.cc b/src/tools/linux/symupload/sym_upload.cc index 57df81cf7..a76c55f7d 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. // @@ -39,6 +38,10 @@ // cpu: the CPU that the module was built for // symbol_file: the contents of the breakpad-format symbol file +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include @@ -47,6 +50,7 @@ #include #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 +70,11 @@ static void Usage(int argc, const char *argv[]) { fprintf(stderr, "Submit symbol information.\n"); fprintf(stderr, "Usage: %s [options...] \n", - argv[0]); + google_breakpad::BaseName(argv[0]).c_str()); fprintf(stderr, "Options:\n"); - fprintf(stderr, " should be created by using the dump_syms" - "tool.\n"); + fprintf(stderr, + " should be created by using the dump_syms " + "tool.\n"); fprintf(stderr, " is the destination for the upload\n"); fprintf(stderr, "-p:\t One of ['sym-upload-v1'," " 'sym-upload-v2'], defaults to 'sym-upload-v1'.\n"); @@ -125,7 +130,6 @@ SetupOptions(int argc, const char *argv[], Options *options) { // the bad arg value, so return an error code if optopt is set, // otherwise exit cleanly. exit(optopt == 0 ? 0 : 1); - break; case 'u': options->proxy_user_pwd = optarg; break; @@ -170,7 +174,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 020e4c1c7..000000000 --- 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 f68200c7c..000000000 --- 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 - -#include -#include - -#include - -#include - -#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(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(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 symbol_supplier( - new OnDemandSymbolSupplier(search_dir, symbol_search_dir)); - scoped_ptr - minidump_processor(new MinidumpProcessor(symbol_supplier.get(), &resolver)); - ProcessState process_state; - scoped_ptr 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_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(process_state.threads()->size()); - const std::vector - *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 " - "/.\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 33204f7e2..000000000 --- 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 = ""; }; - 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 = ""; }; - 162F64FD161C5ECB00CD68D5 /* arch_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = ""; }; - 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 = ""; }; - 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 = ""; }; - 4247E63E2110D5A500482558 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = ""; }; - 4247E63F2110D5A500482558 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = ""; }; - 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 = ""; }; - 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = source_line_resolver_interface.h; sourceTree = ""; }; - 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 = ""; }; - 9BDF16F90B1B8ACD00F8391B /* breakpad_types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = breakpad_types.h; sourceTree = ""; }; - 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_format.h; sourceTree = ""; }; - 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = call_stack.h; sourceTree = ""; }; - 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = memory_region.h; sourceTree = ""; }; - 9BDF16FE0B1B8ACD00F8391B /* minidump.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump.h; sourceTree = ""; }; - 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_processor.h; sourceTree = ""; }; - 9BDF17000B1B8ACD00F8391B /* process_state.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = process_state.h; sourceTree = ""; }; - 9BDF17010B1B8ACD00F8391B /* stack_frame.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame.h; sourceTree = ""; }; - 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame_cpu.h; sourceTree = ""; }; - 9BDF17030B1B8ACD00F8391B /* stackwalker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stackwalker.h; sourceTree = ""; }; - 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = symbol_supplier.h; sourceTree = ""; }; - 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 = ""; }; - 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = on_demand_symbol_supplier.mm; sourceTree = ""; }; - 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 = ""; }; - 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 = ""; }; - F407DC42185773C10064622B /* stackwalker_arm64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_arm64.cc; path = ../../../processor/stackwalker_arm64.cc; sourceTree = ""; }; - F407DC43185773C10064622B /* stackwalker_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_arm64.h; path = ../../../processor/stackwalker_arm64.h; sourceTree = ""; }; - F407DC44185773C10064622B /* stackwalker_mips.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_mips.cc; path = ../../../processor/stackwalker_mips.cc; sourceTree = ""; }; - F407DC45185773C10064622B /* stackwalker_mips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_mips.h; path = ../../../processor/stackwalker_mips.h; sourceTree = ""; }; - F407DC46185773C10064622B /* stackwalker_ppc64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_ppc64.cc; path = ../../../processor/stackwalker_ppc64.cc; sourceTree = ""; }; - F407DC47185773C10064622B /* stackwalker_ppc64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_ppc64.h; path = ../../../processor/stackwalker_ppc64.h; sourceTree = ""; }; - F44DDD8419C85CD50047280E /* dump_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_context.cc; path = ../../../processor/dump_context.cc; sourceTree = ""; }; - F44DDD8519C85CD50047280E /* dump_object.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_object.cc; path = ../../../processor/dump_object.cc; sourceTree = ""; }; - F44DDD8619C85CD50047280E /* microdump_processor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump_processor.cc; path = ../../../processor/microdump_processor.cc; sourceTree = ""; }; - F44DDD8A19C85CFB0047280E /* dump_context.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_context.h; path = ../../../google_breakpad/processor/dump_context.h; sourceTree = ""; }; - F44DDD8B19C85CFB0047280E /* dump_object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_object.h; path = ../../../google_breakpad/processor/dump_object.h; sourceTree = ""; }; - F44DDD8C19C85CFC0047280E /* microdump_processor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump_processor.h; path = ../../../google_breakpad/processor/microdump_processor.h; sourceTree = ""; }; - F44DDD8D19C85CFC0047280E /* process_result.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = process_result.h; path = ../../../google_breakpad/processor/process_result.h; sourceTree = ""; }; - F47180541D745DEF0032F208 /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = ""; }; - F47180551D745DEF0032F208 /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = ""; }; - 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 = ""; }; - 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 = ""; }; - F4D43B2E1A38490700C290B2 /* microdump.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump.cc; path = ../../../processor/microdump.cc; sourceTree = ""; }; - F4D43B301A38492000C290B2 /* microdump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump.h; path = ../../../google_breakpad/processor/microdump.h; sourceTree = ""; }; - 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 = ""; - }; - 08FB7795FE84155DC02AAC07 /* breakpad */ = { - isa = PBXGroup; - children = ( - 9BE650AB0B52FE1A00611104 /* common */, - 9BDF17280B1B8B0200F8391B /* processor */, - 9BDF16F70B1B8ACD00F8391B /* google_breakpad */, - ); - name = breakpad; - sourceTree = ""; - }; - 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { - isa = PBXGroup; - children = ( - 08FB779EFE84155DC02AAC07 /* Foundation.framework */, - ); - name = "External Frameworks and Libraries"; - sourceTree = ""; - }; - 1AB674ADFE9D54B511CA2CBB /* Products */ = { - isa = PBXGroup; - children = ( - 8DD76FA10486AA7600D96B5E /* crash_report */, - ); - name = Products; - sourceTree = ""; - }; - 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 = ""; - }; - 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 = ""; - }; - 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 = ""; - }; - 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 = ""; - }; - 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 = ""; - }; - 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 = ""; - }; -/* 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 69b41405c..000000000 --- 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 -#include -#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 module_file_map_; - - // Map of allocated data buffers, keyed by module->code_file(). - map 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 cfcecee8c..000000000 --- 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 -#include -#include -#include -#include -#include -#include - -#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::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::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.xcodeproj/project.pbxproj b/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj index 5b644e24c..c98b6ac54 100644 --- a/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj +++ b/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj @@ -1251,7 +1251,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 8B3102D411F0D60300FCF3E4 /* BreakpadDebug.xcconfig */; buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; HEADER_SEARCH_PATHS = ( ../../.., ../../../common/mac/include/, @@ -1264,7 +1264,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 8B3102D511F0D60300FCF3E4 /* BreakpadRelease.xcconfig */; buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; HEADER_SEARCH_PATHS = ( ../../.., ../../../common/mac/include/, diff --git a/src/tools/mac/dump_syms/dump_syms_tool.cc b/src/tools/mac/dump_syms/dump_syms_tool.cc index 8d73f0bdd..3eb721630 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. // @@ -32,34 +31,41 @@ // dump_syms_tool.cc: Command line tool that uses the DumpSymbols class. // TODO(waylonis): accept stdin +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include #include #include +#include +#include #include #include "common/mac/dump_syms.h" #include "common/mac/arch_utilities.h" #include "common/mac/macho_utilities.h" -#include "common/scoped_ptr.h" using google_breakpad::DumpSymbols; using google_breakpad::Module; -using google_breakpad::scoped_ptr; using std::vector; struct Options { - Options() - : srcPath(), dsymPath(), arch(), header_only(false), - cfi(true), handle_inter_cu_refs(true) {} + Options() = default; string srcPath; string dsymPath; - const NXArchInfo *arch; - bool header_only; - bool cfi; - bool handle_inter_cu_refs; + std::optional arch; + bool header_only = false; + bool cfi = true; + bool handle_inter_cu_refs = true; + bool handle_inlines = false; + bool enable_multiple = false; + string module_name; + bool prefer_extern_name = false; + bool report_warnings = false; }; static bool StackFrameEntryComparator(const Module::StackFrameEntry* a, @@ -101,14 +107,43 @@ 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(*from_entry)); } } } +static bool SetArchitecture(DumpSymbols& dump_symbols, + const ArchInfo& arch, + const std::string& filename) { + if (!dump_symbols.SetArchitecture(arch)) { + fprintf(stderr, "%s: no architecture '%s' is present in file.\n", + filename.c_str(), + GetNameFromCPUType(arch.cputype, arch.cpusubtype)); + 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]; + fprintf(stderr, "%s\n", + GetNameFromCPUType(arch->cputype, arch->cpusubtype)); + } + return false; + } + return true; +} + 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); + 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, options.module_name, + options.prefer_extern_name); // 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 @@ -123,44 +158,24 @@ static bool Start(const Options& options) { const string& primary_file = split_module ? options.dsymPath : options.srcPath; + dump_symbols.SetReportWarnings(options.report_warnings); + 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) return dump_symbols.WriteSymbolFileHeader(std::cout); // Read the primary file into a Breakpad Module. - Module* module = NULL; + Module* module = nullptr; if (!dump_symbols.ReadSymbolData(&module)) return false; - scoped_ptr scoped_module(module); + std::unique_ptr scoped_module(module); // If this is a split module, read the secondary Mach-O file, from which the // CFI data will be extracted. @@ -168,18 +183,47 @@ static bool Start(const Options& options) { if (!dump_symbols.Read(options.srcPath)) return false; - Module* cfi_module = NULL; + if (options.arch && + !SetArchitecture(dump_symbols, *options.arch, options.srcPath)) { + return false; + } + Module* cfi_module = nullptr; if (!dump_symbols.ReadSymbolData(&cfi_module)) return false; - scoped_ptr scoped_cfi_module(cfi_module); + std::unique_ptr scoped_cfi_module(cfi_module); + + bool name_matches; + if (!options.module_name.empty()) { + // Ignore the basename of the dSYM and binary and use the passed-in module + // name. + name_matches = true; + } else { + name_matches = cfi_module->name() == module->name(); + } // Ensure that the modules are for the same debug code file. - if (cfi_module->name() != module->name() || - cfi_module->os() != module->os() || + if (!name_matches || cfi_module->os() != module->os() || cfi_module->architecture() != module->architecture() || cfi_module->identifier() != module->identifier()) { fprintf(stderr, "Cannot generate a symbol file from split sources that do" " not match.\n"); + if (!name_matches) { + fprintf(stderr, "Name mismatch: binary=[%s], dSYM=[%s]\n", + cfi_module->name().c_str(), module->name().c_str()); + } + if (cfi_module->os() != module->os()) { + fprintf(stderr, "OS mismatch: binary=[%s], dSYM=[%s]\n", + cfi_module->os().c_str(), module->os().c_str()); + } + if (cfi_module->architecture() != module->architecture()) { + fprintf(stderr, "Architecture mismatch: binary=[%s], dSYM=[%s]\n", + cfi_module->architecture().c_str(), + module->architecture().c_str()); + } + if (cfi_module->identifier() != module->identifier()) { + fprintf(stderr, "Identifier mismatch: binary=[%s], dSYM=[%s]\n", + cfi_module->identifier().c_str(), module->identifier().c_str()); + } return false; } @@ -192,15 +236,28 @@ static bool Start(const Options& options) { //============================================================================= static void Usage(int argc, const char *argv[]) { fprintf(stderr, "Output a Breakpad symbol file from a Mach-o file.\n"); - fprintf(stderr, "Usage: %s [-a ARCHITECTURE] [-c] [-g dSYM path] " - "\n", argv[0]); + fprintf(stderr, + "Usage: %s [-a ARCHITECTURE] [-c] [-g dSYM path] " + "[-n MODULE] [-x] \n", + argv[0]); fprintf(stderr, "\t-i: Output module header information only.\n"); + fprintf(stderr, "\t-w: Output warning information.\n"); fprintf(stderr, "\t-a: Architecture type [default: native, or whatever is\n"); fprintf(stderr, "\t in the file, if it contains only one architecture]\n"); fprintf(stderr, "\t-g: Debug symbol file (dSYM) to dump in addition to the " "Mach-o file\n"); fprintf(stderr, "\t-c: Do not generate CFI section\n"); fprintf(stderr, "\t-r: Do not handle inter-compilation unit references\n"); + fprintf(stderr, "\t-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-n: Use MODULE as the name of the module rather than \n" + "the basename of the Mach-O file/dSYM.\n"); + fprintf(stderr, + "\t-x: Prefer the PUBLIC (extern) name over the FUNC if\n" + "they do not match.\n"); fprintf(stderr, "\t-h: Usage\n"); fprintf(stderr, "\t-?: Usage\n"); } @@ -210,14 +267,16 @@ 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, "iwa:g:crdm?hn:x")) != -1) { switch (ch) { case 'i': options->header_only = true; break; + case 'w': + options->report_warnings = true; + break; case 'a': { - const NXArchInfo *arch_info = - google_breakpad::BreakpadGetArchInfoFromName(optarg); + std::optional arch_info = GetArchInfoFromName(optarg); if (!arch_info) { fprintf(stderr, "%s: Invalid architecture: %s\n", argv[0], optarg); Usage(argc, argv); @@ -235,6 +294,18 @@ 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 'n': + options->module_name = optarg; + break; + case 'x': + options->prefer_extern_name = 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 deleted file mode 100644 index 34f82ab1f..000000000 --- a/src/tools/mac/dump_syms/macho_dump.cc +++ /dev/null @@ -1,203 +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. - -// Original author: Jim Blandy - -// macho_dump.cc: Dump the contents of a Mach-O file. This is mostly -// a test program for the Mach_O::FatReader and Mach_O::Reader classes. - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "common/byte_cursor.h" -#include "common/mac/arch_utilities.h" -#include "common/mac/macho_reader.h" -#include "common/path_helper.h" - -using google_breakpad::ByteBuffer; -using std::ostringstream; -using std::string; -using std::vector; - -namespace { -namespace mach_o = google_breakpad::mach_o; - -string program_name; - -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, - filename, strerror(errno)); - exit(1); - } - return result; -} - -class DumpSection: public mach_o::Reader::SectionHandler { - public: - DumpSection() : index_(0) { } - bool HandleSection(const mach_o::Section& section) { - printf(" section %d '%s' in segment '%s'\n" - " address: 0x%llx\n" - " alignment: 1 << %d B\n" - " flags: %d\n" - " size: %ld\n", - index_++, section.section_name.c_str(), section.segment_name.c_str(), - section.address, section.align, - mach_o::SectionFlags(section.flags), - section.contents.Size()); - return true; - } - - private: - int index_; -}; - -class DumpCommand: public mach_o::Reader::LoadCommandHandler { - public: - DumpCommand(mach_o::Reader* reader) : reader_(reader), index_(0) { } - bool UnknownCommand(mach_o::LoadCommandType type, - const ByteBuffer& contents) { - printf(" load command %d: %d", index_++, type); - return true; - } - 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" - " maximum protection: 0x%x\n" - " initial protection: 0x%x\n" - " flags: %d\n" - " section_list size: %ld B\n", - index_++, (segment.bits_64 ? "64" : "32"), segment.name.c_str(), - segment.vmaddr, segment.vmsize, segment.maxprot, - segment.initprot, mach_o::SegmentFlags(segment.flags), - segment.section_list.Size()); - - DumpSection dump_section; - return reader_->WalkSegmentSections(segment, &dump_section); - } - private: - mach_o::Reader* reader_; - int index_; -}; - -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, - MAP_PRIVATE, fd, 0); - close(fd); - 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(mapping), - attributes.st_size)) { - exit(1); - } - printf("filename: %s\n", filename); - size_t object_files_size; - const SuperFatArch* super_fat_object_files = - fat_reader.object_files(&object_files_size); - 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 = - google_breakpad::BreakpadGetArchInfoFromCpuType( - file.cputype, file.cpusubtype); - printf("\n object file %ld:\n" - " fat header:\n:" - " CPU type: %s (%s)\n" - " size: %d B\n" - " alignment: 1<<%d B\n", - i, fat_arch_info->name, fat_arch_info->description, - file.size, file.align); - - ostringstream name; - name << filename; - if (object_files_size > 1) - name << ", object file #" << i; - ByteBuffer file_contents(reinterpret_cast(mapping) - + file.offset, file.size); - mach_o::Reader::Reporter reporter(name.str()); - mach_o::Reader reader(&reporter); - if (!reader.Read(file_contents, file.cputype, file.cpusubtype)) { - exit(1); - } - - const NXArchInfo* macho_arch_info = - NXGetArchInfoFromCpuType(reader.cpu_type(), - reader.cpu_subtype()); - printf(" Mach-O header:\n" - " word size: %s\n" - " CPU type: %s (%s)\n" - " File type: %d\n" - " flags: %x\n", - (reader.bits_64() ? "64 bits" : "32 bits"), - macho_arch_info->name, macho_arch_info->description, - reader.file_type(), reader.flags()); - - DumpCommand dump_command(&reader); - reader.WalkLoadCommands(&dump_command); - } - munmap(mapping, attributes.st_size); -} - -} // namespace - -int main(int argc, char** argv) { - program_name = google_breakpad::BaseName(argv[0]); - if (argc == 1) { - fprintf(stderr, "Usage: %s FILE ...\n" - "Dump the contents of the Mach-O or fat binary files " - "'FILE ...'.\n", program_name.c_str()); - } - for (int i = 1; i < argc; i++) { - DumpFile(argv[i]); - } -} diff --git a/src/tools/mac/symupload/symupload.m b/src/tools/mac/symupload/symupload.mm similarity index 89% rename from src/tools/mac/symupload/symupload.m rename to src/tools/mac/symupload/symupload.mm index 61c2450d1..521b811f0 100644 --- a/src/tools/mac/symupload/symupload.m +++ b/src/tools/mac/symupload/symupload.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. // @@ -27,7 +26,7 @@ // (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 +// 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" @@ -47,8 +46,13 @@ #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; @@ -68,6 +72,7 @@ NSString* type; NSString* codeFile; NSString* debugID; + NSString* productName; } Options; //============================================================================= @@ -207,7 +212,8 @@ static void StartSymUploadProtocolV2(Options* options, withUploadKey:[URLResponse uploadKey] withDebugFile:debugFile withDebugID:debugID - withType:options->type]; + withType:options->type + withProductName:options->productName]; [URLResponse release]; if (completeUploadResult == CompleteUploadResultError) { fprintf(stdout, "Failed to complete upload.\n"); @@ -266,16 +272,20 @@ static void Usage(int argc, const char* argv[]) { "[Only in sym-upload-v2 protocol mode]\n"); fprintf( stderr, - "-t:\t Explicitly set symbol upload type (" + "\t-t: 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, "-c:\t Explicitly set 'code_file' for symbol " + fprintf(stderr, "\t-c: Explicitly set 'code_file' for symbol " "upload (basename of executable).\n"); - fprintf(stderr, "-i:\t Explicitly set 'debug_id' for symbol " - "upload (typically build ID of executable).\n"); + fprintf(stderr, "\t-i: 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: Optionally set 'product_name' for " + "symbol upload\n"); fprintf(stderr, "\t-h: Usage\n"); fprintf(stderr, "\t-?: Usage\n"); fprintf(stderr, "\n"); @@ -322,11 +332,12 @@ static void SetupOptions(int argc, const char* argv[], Options* options) { options->codeFile = nil; options->debugID = nil; options->force = NO; + options->productName = nil; extern int optind; - char ch; + int ch; - while ((ch = getopt(argc, (char* const*)argv, "p:k:t:c:i:hf?")) != -1) { + 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) { @@ -355,12 +366,15 @@ static void SetupOptions(int argc, const char* argv[], Options* options) { 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; @@ -410,6 +424,27 @@ static void SetupOptions(int argc, const char* argv[], Options* options) { 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, diff --git a/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj b/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj index 1653b3885..b1dd6a112 100644 --- a/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj +++ b/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj @@ -14,8 +14,31 @@ 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 */; }; @@ -36,7 +59,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 08FB7796FE84155DC02AAC07 /* symupload.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = symupload.m; sourceTree = ""; tabWidth = 2; }; + 08FB7796FE84155DC02AAC07 /* symupload.mm */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.objcpp; path = symupload.mm; sourceTree = ""; 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 = ""; tabWidth = 2; }; 5B6060BC222716FC0015F0A0 /* HTTPRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPRequest.m; path = ../../../common/mac/HTTPRequest.m; sourceTree = ""; tabWidth = 2; }; @@ -54,6 +77,56 @@ 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; }; + 930DA19025ED543A008558E3 /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = ""; }; + 930DA19125ED543A008558E3 /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = ""; }; + 930DA21F25ED55A8008558E3 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = ""; }; + 930DA22025ED55A8008558E3 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = ""; }; + 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 = ""; }; + 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 = ""; }; + 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 = ""; }; + 930DA22425ED55A8008558E3 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = ""; }; + 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 = ""; }; + 930DA22625ED55A9008558E3 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = ""; }; + 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 = ""; }; + 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 = ""; }; + 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 = ""; }; + 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 = ""; }; + 930DA23525ED55B6008558E3 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = ""; }; + 930DA23625ED55B6008558E3 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = ""; }; + 930DA23A25ED55BF008558E3 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = ""; }; + 930DA23B25ED55BF008558E3 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = ""; }; + 930DA23C25ED55BF008558E3 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = ""; }; + 930DA23D25ED55BF008558E3 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = ""; }; + 930DA23E25ED55BF008558E3 /* macho_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_reader.h; path = ../../../common/mac/macho_reader.h; sourceTree = ""; }; + 930DA23F25ED55BF008558E3 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = ""; }; + 930DA24025ED55BF008558E3 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = ""; }; + 930DA24125ED55BF008558E3 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = ""; }; + 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 = ""; }; + 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 = ""; }; + 930DA24E25ED56DB008558E3 /* cfi_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cfi_assembler.cc; path = ../../../common/dwarf/cfi_assembler.cc; sourceTree = ""; }; + 930DA24F25ED56DB008558E3 /* dwarf2enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2enums.h; path = ../../../common/dwarf/dwarf2enums.h; sourceTree = ""; }; + 930DA25025ED56DB008558E3 /* bytereader-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "bytereader-inl.h"; path = "../../../common/dwarf/bytereader-inl.h"; sourceTree = ""; }; + 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 = ""; }; + 930DA25225ED56DB008558E3 /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = ""; }; + 930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = ""; }; + 930DA25425ED56DB008558E3 /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = ""; }; + 930DA25525ED56DB008558E3 /* bytereader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bytereader.h; path = ../../../common/dwarf/bytereader.h; sourceTree = ""; }; + 930DA25625ED56DB008558E3 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = ""; }; + 930DA25725ED56DB008558E3 /* dwarf2reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2reader.h; path = ../../../common/dwarf/dwarf2reader.h; sourceTree = ""; }; + 930DA25825ED56DB008558E3 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = ""; }; + 930DA25925ED56DB008558E3 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = ""; }; + 930DA25A25ED56DB008558E3 /* cfi_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cfi_assembler.h; path = ../../../common/dwarf/cfi_assembler.h; sourceTree = ""; }; + 930DA26725ED56FF008558E3 /* test_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test_assembler.h; path = ../../../common/test_assembler.h; sourceTree = ""; }; + 930DA26825ED56FF008558E3 /* test_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test_assembler.cc; path = ../../../common/test_assembler.cc; sourceTree = ""; }; + 930DA26C25ED571F008558E3 /* arch_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = ""; }; + 930DA26D25ED571F008558E3 /* arch_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = ""; }; + 930DA27125ED572C008558E3 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = ""; }; + 930DA27225ED572C008558E3 /* byteswap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byteswap.h; path = ../../../common/mac/byteswap.h; sourceTree = ""; }; + 930DA27325ED572C008558E3 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = ""; }; + 930DA27425ED572C008558E3 /* byte_cursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byte_cursor.h; path = ../../../common/byte_cursor.h; sourceTree = ""; }; + 930DA27525ED572C008558E3 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = ""; }; + 930DA27625ED572C008558E3 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = ""; }; + 930DA27725ED572D008558E3 /* md5.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = md5.cc; path = ../../../common/md5.cc; sourceTree = ""; }; 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = ""; tabWidth = 2; }; 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = ""; tabWidth = 2; }; 9BD835FB0B0544950055103E /* minidump_upload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = minidump_upload; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -83,6 +156,7 @@ 08FB7794FE84155DC02AAC07 /* symupload */ = { isa = PBXGroup; children = ( + 930DA21E25ED5586008558E3 /* dump_syms */, 5B6060CE22273BDA0015F0A0 /* SymbolCollectorClient.h */, 5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */, 5B6060C82227374E0015F0A0 /* HTTPSimplePostRequest.h */, @@ -98,7 +172,7 @@ 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 */, @@ -125,6 +199,63 @@ name = Products; sourceTree = ""; }; + 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 = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -191,14 +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; }; @@ -217,7 +371,13 @@ 1DEB927508733DD40010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - HEADER_SEARCH_PATHS = ../../..; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + HEADER_SEARCH_PATHS = ( + ../../.., + ../../../common/mac/include, + ../../../third_party/musl/include/, + ); PRODUCT_NAME = symupload; }; name = Debug; @@ -225,7 +385,17 @@ 1DEB927608733DD40010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - HEADER_SEARCH_PATHS = ../../..; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + 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 7457573b4..000000000 --- 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/arch_constants.h similarity index 95% rename from src/tools/mac/upload_system_symbols/arch_constants.h rename to src/tools/mac/upload_system_symbols/arch/arch_constants.h index e12e53e22..b6dbc89a0 100644 --- a/src/tools/mac/upload_system_symbols/arch_constants.h +++ b/src/tools/mac/upload_system_symbols/arch/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/arch_reader.go similarity index 90% rename from src/tools/mac/upload_system_symbols/arch_reader.go rename to src/tools/mac/upload_system_symbols/arch/arch_reader.go index ed98fa60f..6553c8ba1 100644 --- a/src/tools/mac/upload_system_symbols/arch_reader.go +++ b/src/tools/mac/upload_system_symbols/arch/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. @@ -28,7 +27,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package main +package arch import ( "debug/macho" @@ -39,10 +38,10 @@ import ( */ import "C" -// getArchStringFromHeader takes a MachO FileHeader and returns a string that +// GetArchStringFromHeader takes a MachO FileHeader and returns a string that // represents the CPU type and subtype. // This function is a Go version of src/common/mac/arch_utilities.cc:BreakpadGetArchInfoFromCpuType(). -func getArchStringFromHeader(header macho.FileHeader) string { +func GetArchStringFromHeader(header macho.FileHeader) string { // TODO(rsesek): As of 10.9.4, OS X doesn't list these in /usr/include/mach/machine.h. if header.Cpu == C.kCPU_TYPE_ARM64 && header.SubCpu == C.kCPU_SUBTYPE_ARM64_ALL { return "arm64" diff --git a/src/tools/mac/upload_system_symbols/archive/extract.go b/src/tools/mac/upload_system_symbols/archive/extract.go new file mode 100644 index 000000000..965e154e3 --- /dev/null +++ b/src/tools/mac/upload_system_symbols/archive/extract.go @@ -0,0 +1,517 @@ +package archive + +// #cgo LDFLAGS: -lParallelCompression +// #include +// #include +// #include +// +// typedef struct +// { +// int64_t unknown1; +// int64_t unknown2; +// char *input; +// char *output; +// char *patch; +// uint32_t not_cryptex_cache; +// uint32_t threads; +// uint32_t verbose; +// } RawImage; +// +// extern int32_t RawImagePatch(RawImage *) __attribute__((weak)); +import "C" + +import ( + "archive/zip" + "bytes" + "errors" + "fmt" + "io" + "log" + "os" + "os/exec" + "path" + "path/filepath" + "strconv" + "strings" + "unsafe" +) + +type ArchiveFormat int + +const ( + IPSW ArchiveFormat = iota + Installer +) + +// ExtractCaches extracts any dyld shared caches from `archive` to `destination`. +func ExtractCaches(format ArchiveFormat, archive string, destination string, verbose bool) error { + opts := ExtractorOptions{Verbose: true, Source: archive, Destination: destination} + var e *Extractor + switch format { + case IPSW: + e = NewIPSWExtractor(opts) + case Installer: + e = NewInstallAssistantExtractor(opts) + default: + return fmt.Errorf("unknown format %v", format) + } + return e.Extract() +} + +// NewIPSWExtractor returns an `Extractor` that can handle `.ipsw` files. +func NewIPSWExtractor(opts ExtractorOptions) *Extractor { + ie := &ipswExtractor{} + ie.Extractor = &Extractor{opts: opts, impl: ie} + return ie.Extractor +} + +// NewInstallAssistantExtractor returns an extractor that can handle Apple installers. +func NewInstallAssistantExtractor(opts ExtractorOptions) *Extractor { + ie := &installAssistantExtractor{} + ie.Extractor = &Extractor{opts: opts, impl: ie} + return ie.Extractor +} + +// ExtractorOptions are provided to an extractor to specify source file, destination, +// and whether verbose logging should be used. +type ExtractorOptions struct { + Verbose bool + Source string + Destination string +} + +// Extractor encapsulates the process of extracting dyld shared caches from an IPSW or installer. +type Extractor struct { + opts ExtractorOptions + impl extractorImpl + + scratchDir string + + // If non-empty, the path at which the DMG was mounted. This will + // be un-mounted at the end of Extract(). + dmgMountPaths []string +} + +// Extract extracts any dyld shared caches in `opts.Source` to `opts.Destination`. +func (e *Extractor) Extract() error { + scratchDir, err := os.MkdirTemp("", "extracted_system") + if err != nil { + return fmt.Errorf("couldn't create scratch directory to extract: %v", err) + } + defer os.RemoveAll(scratchDir) + e.scratchDir = scratchDir + + err = e.impl.doExtract() + + for _, path := range e.dmgMountPaths { + unmountErr := unmountDMG(path) + if unmountErr != nil { + err = errors.Join(err, unmountErr) + } + } + + return err +} + +// vlog logs if `opts.Verbose` is set and is a no-op otherwise. +func (e *Extractor) vlog(format string, args ...interface{}) { + if e.opts.Verbose { + fmt.Printf(format+"\n", args...) + } +} + +// mountDMG mounts the disk image at `dmgPath` to mountpoint and tracks it so that +// it can be unmounted by the end of `Extract` +func (e *Extractor) mountDMG(dmgPath string, mountpoint string) error { + cmd := exec.Command("hdiutil", "attach", dmgPath, "-mountpoint", mountpoint, "-quiet", "-nobrowse", "-readonly") + err := cmd.Run() + if err == nil { + e.dmgMountPaths = append(e.dmgMountPaths, mountpoint) + } + return err +} + +// extractorImpl is a private interface implemented by the backend +// extractors. +type extractorImpl interface { + doExtract() error +} + +// ipswExtractor extracts IPSWs +type ipswExtractor struct { + *Extractor +} + +// doExtract extracts dyld shared caches from an IPSW. +// It: +// Extracts the system disk image from the IPSW and mounts it. +// Copies any dyld shared caches from /System/Library/dyld on the mounted +// image to `opts.Destination`. +func (e *ipswExtractor) doExtract() error { + e.vlog("Extracting and mounting system disk:\n") + system, err := e.mountSystemDMG(e.opts.Source) + if err != nil { + return fmt.Errorf("couldn't mount system DMG: %v", err) + } + e.vlog("System mounted at %v\n", system) + e.vlog("Extracting shared caches:\n") + cachesPath := path.Join(system, "System/Library/dyld") + if !pathExists(cachesPath) { + return errors.New("couldn't find /System/Library/dyld") + } + + caches, err := filepath.Glob(path.Join(cachesPath, "dyld_shared_cache*")) + if err != nil { + // "The only possible returned error is ErrBadPattern" so treat + // this like a programmer error. + log.Fatalf("Failed to glob %v", path.Join(cachesPath, "dyld_shared_cache*")) + } + + for _, cache := range caches { + src, err := os.Open(cache) + if err != nil { + return err + } + defer src.Close() + filename := path.Base(cache) + dst, err := os.Create(path.Join(e.opts.Destination, filename)) + if err != nil { + return err + } + defer dst.Close() + e.vlog("Extracted %v\n", filename) + if _, err := io.Copy(dst, src); err != nil { + return err + } + } + + return nil +} + +// mountSystemDMG finds the name of the system image disk in the build manifest inside the +// IPSW at `ipswPath`, mounts it inside `e.scratchDir` and returns the mountpoint. +func (e *ipswExtractor) mountSystemDMG(ipswPath string) (string, error) { + r, err := zip.OpenReader(ipswPath) + if err != nil { + return "", fmt.Errorf("couldn't open ipsw at %s: %v", ipswPath, err) + } + defer r.Close() + dmgPath := "" + for _, f := range r.File { + if f.Name == "BuildManifest.plist" { + manifest, err := os.Create(path.Join(e.scratchDir, f.Name)) + if err != nil { + return "", err + } + if err := extractFileToPath(f, path.Join(e.scratchDir, f.Name)); err != nil { + return "", err + } + path, err := e.getSystemDMGPath(manifest.Name()) + if err != nil { + return "", err + } + dmgPath = path + } + } + if dmgPath == "" { + return "", errors.New("couldn't find build manifest") + } + for _, f := range r.File { + if filepath.Base(f.Name) == dmgPath { + dmgPath := path.Join(e.scratchDir, f.Name) + if err := extractFileToPath(f, dmgPath); err != nil { + return "", err + } + dmgMountpoint := path.Join(e.scratchDir, "Root") + e.vlog("Mounting %v at %v\n", dmgPath, dmgMountpoint) + if err := e.mountDMG(dmgPath, dmgMountpoint); err != nil { + return "", err + } + return dmgMountpoint, nil + } + } + return "", fmt.Errorf("%v not present in %v", dmgPath, ipswPath) +} + +// getSystemDMGPath finds the system disk image inside a IPSW from the build manifest +// at `manifest`. +func (e *ipswExtractor) getSystemDMGPath(manifest string) (string, error) { + print_cmd := "print :BuildIdentities:1:Manifest:Cryptex1,SystemOS:Info:Path" + result, err := exec.Command("/usr/libexec/PlistBuddy", "-c", print_cmd, manifest).Output() + if err != nil { + return "", err + } + return strings.TrimSpace(string(result)), nil +} + +// installAssistantExtractor extracts Apple installers. +type installAssistantExtractor struct { + *Extractor +} + +// doExtract extracts dyld shared caches from an Apple installer. +// It: +// 1. Expands the installer to disk +// 2. Finds and mounts SharedSupport.dmg +// 3. Determines based on system version whether this installer contains cryptexes or not. +// 4. If cryptexes are present, extracts them to disk images, mounts them, then copies any shared caches +// to `opts.Destination`. Otherwise, finds any payload zips containing shared caches, extracts them, and +// copies the caches to `opts.Destination` +func (e *installAssistantExtractor) doExtract() error { + expandedPath := path.Join(e.scratchDir, "installer") + e.vlog("Expanding installer to %v\n", expandedPath) + if err := e.expandInstaller(e.opts.Source, expandedPath); err != nil { + return fmt.Errorf("expand installer: %v", err) + } + + dmgPath := path.Join(expandedPath, "SharedSupport.dmg") + if !pathExists(dmgPath) { + return fmt.Errorf("couldn't find SharedSupport.dmg at %v", dmgPath) + } + dmgMountpoint := path.Join(e.scratchDir, "shared_support") + e.vlog("Mounting %v at %v\n", dmgPath, dmgMountpoint) + if err := e.mountDMG(dmgPath, dmgMountpoint); err != nil { + return fmt.Errorf("mount %v: %v", dmgPath, err) + } + + zipsPath := path.Join(dmgMountpoint, "com_apple_MobileAsset_MacSoftwareUpdate") + if !pathExists(zipsPath) { + return fmt.Errorf("couldn't find com_apple_MobileAsset_MacSoftwareUpdate on SharedSupport.dmg") + } + hasCryptexes, err := e.hasCryptexes(path.Join(zipsPath, "com_apple_MobileAsset_MacSoftwareUpdate.xml")) + if err != nil { + return fmt.Errorf("couldn't determine system version: %v", err) + } + zips, err := filepath.Glob(path.Join(zipsPath, "*.zip")) + if err != nil { + // "The only possible returned error is ErrBadPattern" so treat + // this like a programmer error. + log.Fatalf("Failed to glob %v", path.Join(zipsPath, "*.zip")) + } + return e.extractCachesFromZips(zips, e.opts.Destination, hasCryptexes) +} + +// expandInstaller expands the installer at `installerPath` to `destinaton`. +func (e *installAssistantExtractor) expandInstaller(installerPath string, destination string) error { + return exec.Command("pkgutil", "--expand-full", installerPath, destination).Run() +} + +// hasCryptexes returns true if the installer containing the plist at `plistPath` is for +// macOS version 13 or higher, and accordingly stores dyld shared caches inside cryptexes. +func (e *installAssistantExtractor) hasCryptexes(plistPath string) (bool, error) { + print_cmd := "print :Assets:0:OSVersion" + result, err := exec.Command("/usr/libexec/PlistBuddy", "-c", print_cmd, plistPath).Output() + if err != nil { + return false, fmt.Errorf("couldn't read OS version from %s: %v", plistPath, err) + } + majorVersion := strings.Split(string(result), ".")[0] + if v, err := strconv.Atoi(majorVersion); err != nil { + return false, fmt.Errorf("couldn't parse major version %s:%v", majorVersion, err) + } else { + return v >= 13, nil + } +} + +// extractCachesFromZips extracts zips that contain dyld shared caches, and extracts the dyld shared caches from them. +// The specifics depend on whether this installer uses cryptexes or payload files. +func (e *installAssistantExtractor) extractCachesFromZips(zips []string, destination string, hasCryptexes bool) error { + containerPath := path.Join(e.scratchDir, "container") + if !hasCryptexes { + if err := e.unarchiveZipsMatching(zips, containerPath, "AssetData/payloadv2/payload.0??"); err != nil { + return err + } + if err := e.extractCachesFromPayloads(containerPath, destination); err != nil { + return fmt.Errorf("couldn't extract caches from %v: %v", containerPath, err) + } + } else { + if err := e.unarchiveZipsMatching(zips, containerPath, "AssetData/payloadv2/image_patches/cryptex-system-*"); err != nil { + return err + } + if err := e.extractCachesFromCryptexes(containerPath, destination); err != nil { + return fmt.Errorf("couldn't extract caches from %v: %v", containerPath, err) + } + } + return nil +} + +// unarchiveZipsMatching unarchives all files matching `glob` from the zip files in `zips` to destination. +func (e *installAssistantExtractor) unarchiveZipsMatching(zips []string, destination string, glob string) error { + for _, zipFile := range zips { + archive, err := zip.OpenReader(zipFile) + if err != nil { + return fmt.Errorf("couldn't read %v: %v", zipFile, err) + } + defer archive.Close() + e.vlog("Unarchiving %v\n", zipFile) + if err := e.unarchiveFilesMatching(archive, destination, glob); err != nil { + return fmt.Errorf("couldn't unarchive files matching %v from %v", glob, zipFile) + } + } + return nil +} + +// unarchiveFilesMatching unarchives all files matching `glob` from `r` to destination. +func (e *installAssistantExtractor) unarchiveFilesMatching(r *zip.ReadCloser, destination string, glob string) error { + if err := os.MkdirAll(destination, 0755); err != nil { + return err + } + for _, file := range r.File { + if file.FileInfo().IsDir() { + continue + } + if ok, err := path.Match(glob, file.Name); !ok || err != nil { + continue + } + _, filename := path.Split(file.Name) + writePath := path.Join(destination, filename) + if err := extractFileToPath(file, writePath); err != nil { + return err + } + } + return nil +} + +// extractCachesFromPayloads unarchives any files containing dyld shared caches from `payloadsPath` +// then copies any shared caches to `destination`. +func (e *installAssistantExtractor) extractCachesFromPayloads(payloadsPath string, destination string) error { + scratchDir, err := os.MkdirTemp(e.scratchDir, "payload") + if err != nil { + return err + } + files, err := os.ReadDir(payloadsPath) + if err != nil { + return err + } + for _, f := range files { + payload := path.Join(payloadsPath, f.Name()) + if e.payloadHasSharedCache(payload) { + e.vlog("Extracting %v\n", payload) + if err := e.extractPayload(payload, scratchDir); err != nil { + return err + } + } + } + return e.copySharedCaches(scratchDir, destination) +} + +// payloadHasSharedCache returns true if the archive at `payloadPath` contains a dyld shared cache. +func (e *installAssistantExtractor) payloadHasSharedCache(payloadPath string) bool { + out, err := exec.Command("yaa", "list", "-i", payloadPath).Output() + return err == nil && bytes.Contains(out, []byte("/dyld_shared_cache")) +} + +// extractPayload extracts the apple archive at `payloadPath` to `destination`. +func (e *installAssistantExtractor) extractPayload(payloadPath string, destination string) error { + return exec.Command("yaa", "extract", "-i", payloadPath, "-d", destination).Run() +} + +// copySharedCaches copies the contents of `System/Library/dyld` in `from` to `to`. +func (e *installAssistantExtractor) copySharedCaches(from, to string) error { + dyldPath := path.Join(from, "System/Library/dyld") + if !pathExists(dyldPath) { + return fmt.Errorf("couldn't find System/Library/dyld in %s", dyldPath) + } + cacheFiles, err := os.ReadDir(dyldPath) + if err != nil { + return err + } + for _, cacheFile := range cacheFiles { + name := cacheFile.Name() + src := path.Join(dyldPath, name) + dst := path.Join(to, name) + e.vlog("Copying %v to %v\n", src, dst) + if err := copyFile(src, dst); err != nil { + return fmt.Errorf("couldn't copy %s to %s: %v", src, dst, err) + } + } + return nil +} + +// extractCachesFromCryptexes extracts disk images from any cryptexes at `cryptexesPath`, mounts them, +// and extracts any dyld shared caches to `destination`. +func (e *installAssistantExtractor) extractCachesFromCryptexes(cryptexesPath string, destination string) error { + scratchDir, err := os.MkdirTemp(e.scratchDir, "cryptex_dmg") + if err != nil { + return err + } + files, err := os.ReadDir(cryptexesPath) + if err != nil { + return err + } + for _, f := range files { + cryptexMountpoint := path.Join(scratchDir, "cryptex_"+f.Name()) + cryptex := path.Join(cryptexesPath, f.Name()) + dmgPath := path.Join(scratchDir, f.Name()+".dmg") + e.extractCryptexDMG(cryptex, dmgPath) + e.vlog("Mounting %s at %s\n", cryptex, dmgPath) + e.mountDMG(dmgPath, cryptexMountpoint) + if err := e.copySharedCaches(cryptexMountpoint, destination); err != nil { + return err + } + } + return nil +} + +// extractCryptexDMG extracts the cryptex at `cryptexPath` to `dmgPath` using libParallelCompression. +func (e *installAssistantExtractor) extractCryptexDMG(cryptexPath, dmgPath string) error { + inp := C.CString("") + defer C.free(unsafe.Pointer(inp)) + cryptex := C.CString(cryptexPath) + defer C.free(unsafe.Pointer(cryptex)) + result := C.CString(dmgPath) + defer C.free(unsafe.Pointer(result)) + + ri := C.RawImage{unknown1: 0, unknown2: 0, input: inp, output: result, patch: cryptex, not_cryptex_cache: 0, threads: 0, verbose: 1} + if exitCode := C.RawImagePatch(&ri); exitCode != 0 { + return fmt.Errorf("RawImagePatch failed with %d", exitCode) + } + return nil +} + +// pathExists returns true if `path` exists. +func pathExists(path string) bool { + _, err := os.Stat(path) + return !os.IsNotExist(err) +} + +// extractFileToPath extracts the contents of `f` to `path`. +func extractFileToPath(f *zip.File, path string) error { + w, err := os.Create(path) + if err != nil { + return err + } + defer w.Close() + reader, err := f.Open() + if err != nil { + return err + } + + if _, err := io.Copy(w, reader); err != nil { + return err + } + return nil +} + +// copyFile copies `src` to `dst`, which can be on different volumes. +func copyFile(src, dst string) error { + w, err := os.Create(dst) + if err != nil { + return err + } + defer w.Close() + + reader, err := os.Open(src) + if err != nil { + return err + } + defer reader.Close() + if _, err := io.Copy(w, reader); err != nil { + return err + } + return nil +} + +// unmountDMG unmounts the disk image at `mountpoint`. +func unmountDMG(mountpoint string) error { + return exec.Command("hdiutil", "detach", mountpoint).Run() +} 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 000000000..ff21bba9f --- /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 05a7764ab..921e83bf0 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. @@ -44,32 +43,39 @@ package main import ( "debug/macho" + "errors" "flag" "fmt" "io" - "io/ioutil" "log" "os" "os/exec" "path" + "path/filepath" "regexp" "strings" "sync" "time" + + "upload_system_symbols/arch" + "upload_system_symbols/archive" ) var ( breakpadTools = flag.String("breakpad-tools", "out/Release/", "Path to the Breakpad tools directory, containing dump_syms and symupload.") uploadOnlyPath = flag.String("upload-from", "", "Upload a directory of symbol files that has been dumped independently.") 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.") + systemRoot = flag.String("system-root", "", "Path to the root of the macOS system whose symbols will be dumped. Mutually exclusive with --installer and --ipsw.") 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.") + installer = flag.String("installer", "", "Path to macOS installer. Mutually exclusive with --system-root and --ipsw.") + ipsw = flag.String("ipsw", "", "Path to macOS IPSW. Mutually exclusive with --system-root and --installer.") + separateArch = flag.Bool("separate-arch", false, "Whether to separate symbols into architecture-specific directories when dumping.") ) 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 +85,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{ @@ -96,12 +115,18 @@ var ( regexp.MustCompile(`\.a$`), regexp.MustCompile(`\.dat$`), } + maxFileCreateTries = 10 ) 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 != "" { @@ -112,26 +137,13 @@ func main() { return } - if *systemRoot == "" { - log.Fatal("Need a -system-root to dump symbols for") - } - - if *dumpOnlyPath != "" { - // -dump-to specified, so make sure that the path is a directory. - if fi, err := os.Stat(*dumpOnlyPath); err != nil { - log.Fatalf("-dump-to location: %v", err) - } else if !fi.IsDir() { - log.Fatal("-dump-to location is not a directory") - } - } - dumpPath := *dumpOnlyPath if *dumpOnlyPath == "" { // If -dump-to was not specified, then run the upload pipeline and create // a temporary dump output directory. uq = StartUploadQueue() - if p, err := ioutil.TempDir("", "upload_system_symbols"); err != nil { + if p, err := os.MkdirTemp("", "upload_system_symbols"); err != nil { log.Fatalf("Failed to create temporary directory: %v", err) } else { dumpPath = p @@ -139,13 +151,112 @@ func main() { } } - dq := StartDumpQueue(*systemRoot, dumpPath, uq) + tempDir, err := os.MkdirTemp("", "systemRoots") + if err != nil { + log.Fatalf("Failed to create temporary directory: %v", err) + } + defer os.RemoveAll(tempDir) + roots := getSystemRoots(tempDir) + + if *dumpOnlyPath != "" { + // -dump-to specified, so make sure that the path is a directory. + if fi, err := os.Stat(*dumpOnlyPath); err != nil { + log.Fatalf("-dump-to location: %v", err) + } else if !fi.IsDir() { + log.Fatal("-dump-to location is not a directory") + } + } + + dq := StartDumpQueue(roots, dumpPath, *separateArch, uq) dq.Wait() if uq != nil { uq.Wait() } } +// getSystemRoots returns which system roots should be dumped from the parsed +// flags, extracting them if necessary. +func getSystemRoots(tempDir string) []string { + hasInstaller := len(*installer) > 0 + hasIPSW := len(*ipsw) > 0 + hasRoot := len(*systemRoot) > 0 + + if hasInstaller { + if hasIPSW || hasRoot { + log.Fatalf("--installer, --ipsw, and --system-root are mutually exclusive") + } + if rs, err := extractSystems(archive.Installer, *installer, tempDir); err != nil { + log.Fatalf("Couldn't extract installer at %s: %v", *installer, err) + } else { + return rs + } + } else if hasIPSW { + if hasRoot { + log.Fatalf("--installer, --ipsw, and --system-root are mutually exclusive") + } + if rs, err := extractSystems(archive.IPSW, *ipsw, tempDir); err != nil { + log.Fatalf("Couldn't extract IPSW at %s: %v", *ipsw, err) + } else { + return rs + } + } else if hasRoot { + return []string{*systemRoot} + } + log.Fatal("Need a --system-root, --installer, or --ipsw to dump symbols for") + return []string{} +} + +// manglePath reduces an absolute filesystem path to a string suitable as the +// base for a file name which encodes some of the original path. The result +// concatenates the leading initial from each path component except the last to +// the last path component; for example /System/Library/Frameworks/AppKit +// becomes SLFAppKit. +// Assumes ASCII. +func manglePath(path string) string { + components := strings.Split(path, "/") + n := len(components) + builder := strings.Builder{} + for i, component := range components { + if len(component) == 0 { + continue + } + if i < n-1 { + builder.WriteString(component[:1]) + } else { + builder.WriteString(component) + } + } + return builder.String() +} + +// createSymbolFile creates a writable file in `base` with a name derived from +// `original_path`. It ensures that multiple threads can't simultaneously create +// the same file for two `original_paths` that map to the same mangled name. +// Returns the filename, the file, and an error if creating the file failed. +func createSymbolFile(base string, original_path string, arch string) (filename string, f *os.File, err error) { + mangled := manglePath(original_path) + counter := 0 + filebase := path.Join(base, mangled) + for { + var symfile string + if counter == 0 { + symfile = fmt.Sprintf("%s_%s.sym", filebase, arch) + } else { + symfile = fmt.Sprintf("%s_%s_%d.sym", filebase, arch, counter) + } + f, err := os.OpenFile(symfile, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644) + if err == nil { + return symfile, f, nil + } + if os.IsExist(err) && counter < maxFileCreateTries { + counter++ + continue + } + return "", nil, err + } + +} + type WorkerPool struct { wg sync.WaitGroup } @@ -195,17 +306,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) @@ -217,9 +340,10 @@ func (uq *UploadQueue) worker() { type DumpQueue struct { *WorkerPool - dumpPath string - queue chan dumpRequest - uq *UploadQueue + dumpPath string + queue chan dumpRequest + separateArch bool + uq *UploadQueue } type dumpRequest struct { @@ -230,15 +354,16 @@ type dumpRequest struct { // StartDumpQueue creates a new worker pool to find all the Mach-O libraries in // root and dump their symbols to dumpPath. If an UploadQueue is passed, the // path to the symbol file will be enqueued there, too. -func StartDumpQueue(root, dumpPath string, uq *UploadQueue) *DumpQueue { +func StartDumpQueue(roots []string, dumpPath string, separateArch bool, uq *UploadQueue) *DumpQueue { dq := &DumpQueue{ - dumpPath: dumpPath, - queue: make(chan dumpRequest), - uq: uq, + dumpPath: dumpPath, + queue: make(chan dumpRequest), + separateArch: separateArch, + uq: uq, } dq.WorkerPool = StartWorkerPool(12, dq.worker) - findLibsInRoot(root, dq) + findLibsInRoots(roots, dq) return dq } @@ -267,9 +392,14 @@ func (dq *DumpQueue) worker() { dumpSyms := path.Join(*breakpadTools, "dump_syms") for req := range dq.queue { - filebase := path.Join(dq.dumpPath, strings.Replace(req.path, "/", "_", -1)) - symfile := fmt.Sprintf("%s_%s.sym", filebase, req.arch) - f, err := os.Create(symfile) + dumpPath := dq.dumpPath + if dq.separateArch { + dumpPath = path.Join(dumpPath, req.arch) + if err := ensureDirectory(dumpPath); err != nil { + log.Fatalf("Error creating directory %s: %v", dumpPath, err) + } + } + symfile, f, err := createSymbolFile(dumpPath, req.path, req.arch) if err != nil { log.Fatalf("Error creating symbol file: %v", err) } @@ -317,21 +447,22 @@ type findQueue struct { dq *DumpQueue } -// findLibsInRoot looks in all the pathsToScan in the root and manages the +// findLibsInRoot looks in all the pathsToScan in all roots and manages the // interaction between findQueue and DumpQueue. -func findLibsInRoot(root string, dq *DumpQueue) { +func findLibsInRoots(roots []string, dq *DumpQueue) { fq := &findQueue{ queue: make(chan string, 10), dq: dq, } fq.WorkerPool = StartWorkerPool(12, fq.worker) + for _, root := range roots { + for _, p := range pathsToScan { + fq.findLibsInPath(path.Join(root, p), true) + } - for _, p := range pathsToScan { - fq.findLibsInPath(path.Join(root, p), true) - } - - for _, p := range optionalPathsToScan { - fq.findLibsInPath(path.Join(root, p), false) + for _, p := range optionalPathsToScan { + fq.findLibsInPath(path.Join(root, p), false) + } } close(fq.queue) @@ -416,11 +547,13 @@ func (fq *findQueue) worker() { } func (fq *findQueue) dumpMachOFile(fp string, image *macho.File) { - if image.Type != MachODylib && image.Type != MachOBundle && image.Type != MachODylinker { + if image.Type != arch.MachODylib && + image.Type != arch.MachOBundle && + image.Type != arch.MachODylinker { return } - arch := getArchStringFromHeader(image.FileHeader) + arch := arch.GetArchStringFromHeader(image.FileHeader) if arch == "" { // Don't know about this architecture type. return @@ -430,3 +563,54 @@ func (fq *findQueue) dumpMachOFile(fp string, image *macho.File) { fq.dq.DumpSymbols(fp, arch) } } + +// extractSystems extracts any dyld shared caches from `archivePath`, then extracts the caches +// into macOS system libraries, returning the locations on disk of any systems extracted. +func extractSystems(format archive.ArchiveFormat, archivePath string, extractPath string) ([]string, error) { + cachesPath := path.Join(extractPath, "caches") + if err := os.MkdirAll(cachesPath, 0755); err != nil { + return nil, err + } + if err := archive.ExtractCaches(format, archivePath, cachesPath, true); err != nil { + return nil, err + } + files, err := os.ReadDir(cachesPath) + if err != nil { + return nil, err + } + cachePrefix := "dyld_shared_cache_" + extractedDirPath := path.Join(extractPath, "extracted") + roots := make([]string, 0) + for _, file := range files { + fileName := file.Name() + if filepath.Ext(fileName) == "" && strings.HasPrefix(fileName, cachePrefix) { + arch := strings.TrimPrefix(fileName, cachePrefix) + extractedSystemPath := path.Join(extractedDirPath, arch) + // XXX: Maybe this shouldn't be fatal? + if err := extractDyldSharedCache(path.Join(cachesPath, fileName), extractedSystemPath); err != nil { + return nil, err + } + roots = append(roots, extractedSystemPath) + } + } + return roots, nil +} + +// extractDyldSharedCache extracts the dyld shared cache at `cachePath` to `destination`. +func extractDyldSharedCache(cachePath string, destination string) error { + dscExtractor := path.Join(*breakpadTools, "dsc_extractor") + cmd := exec.Command(dscExtractor, cachePath, destination) + if output, err := cmd.Output(); err != nil { + return fmt.Errorf("extracting shared cache at %s: %v. dsc_extractor said %v", cachePath, err, output) + } + return nil +} + +// ensureDirectory creates a directory at `path` if one does not already exist. +func ensureDirectory(path string) error { + if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) { + return os.MkdirAll(path, 0755) + } else { + return err + } +} diff --git a/src/tools/mac/upload_system_symbols/upload_system_symbols.sh b/src/tools/mac/upload_system_symbols/upload_system_symbols.sh new file mode 100755 index 000000000..43fd98ed5 --- /dev/null +++ b/src/tools/mac/upload_system_symbols/upload_system_symbols.sh @@ -0,0 +1,114 @@ +#!/bin/bash + +# Copyright 2023 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. + +# Finds the dyld_shared_cache on a system, extracts it, and dumps the symbols +# in Breakpad format to the directory passed as the first argument +# The script must be in the same directory as `dump_syms`, +# `upload_system_symbols` and `dsc_extractor` binaries. +# Exits with 0 if all supported architectures for this OS version were found and +# dumped, and nonzero otherwise. + +set -ex + +if [[ $# -ne 1 ]]; then + echo "usage: $0 " >& 2 + exit 1 +fi + +destination_dir="$1" + +dir="$(dirname "$0")" +dir="$(cd "${dir}"; pwd)" +major_version=$(sw_vers -productVersion | cut -d . -f 1) +if [[ "${major_version}" -lt 13 ]]; then + dsc_directory="/System/Library/dyld" +else + dsc_directory="/System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld" +fi + +working_dir=$(mktemp -d) +mkdir "${destination_dir}" +trap 'rm -rf "${working_dir}" "${destination_dir}"' EXIT + +architectures=(x86_64h) +missing_architectures=() +# macOS >= 13 on arm64 still has a x86_64 cache for Rosetta. +if [[ "${major_version}" -lt 13 ]] || [[ $(uname -p) == "arm" ]]; then + architectures+=( x86_64 ) +fi +if [[ "${major_version}" -ge 11 ]]; then + architectures+=( arm64e ) +fi + +for arch in "${architectures[@]}"; do + cache="${dsc_directory}/dyld_shared_cache_${arch}" + if [[ ! -f "${cache}" ]]; then + missing_architectures+=("${arch}") + continue + fi + "${dir}/dsc_extractor" \ + "${cache}" \ + "${working_dir}/${arch}" + "${dir}/upload_system_symbols" \ + --breakpad-tools="${dir}" \ + --system-root="${working_dir}/${arch}" \ + --dump-to="${destination_dir}" +done +if [[ "${#missing_architectures[@]}" -eq "${#architectures[@]}" ]]; then + echo "Couldn't locate dyld_shared_cache for any architectures" >& 2 + echo "in ${dsc_directory}. Exiting." >& 2 + exit 1 +fi + +rm -rf "${working_dir}" +# We have results now, so let's keep `destination_dir`. +trap '' EXIT + +"${dir}/upload_system_symbols" \ + --breakpad-tools="${dir}" \ + --system-root=/ \ + --dump-to="${destination_dir}" + +set +x +echo +echo "Dumped!" +echo "To upload, run:" +echo +echo "'${dir}/upload_system_symbols'" \\ +echo " --breakpad-tools='${dir}'" \\ +echo " --api-key=" \\ +echo " --upload-from='${destination_dir}'" + +if [[ "${#missing_architectures[@]}" -gt 0 ]]; then + echo "dyld_shared_cache not found for architecture(s):" >& 2 + echo " " "${missing_architectures[@]}" >& 2 + echo "You'll need to get symbols for them elsewhere." >& 2 + exit 1 +fi diff --git a/src/tools/python/deps-to-manifest.py b/src/tools/python/deps-to-manifest.py index b45628543..b614f94fd 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. +#!/usr/bin/env python3 +# 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. # @@ -30,8 +29,6 @@ """Convert gclient's DEPS file to repo's manifest xml file.""" -from __future__ import print_function - import argparse import os import sys @@ -49,7 +46,7 @@ - @@ -77,7 +74,8 @@ def ConvertDepsToManifest(deps, manifest): """Convert the |deps| file to the |manifest|.""" # Load the DEPS file data. ctx = {} - execfile(deps, ctx) + with open(deps, 'rb') as file: + exec(compile(file.read(), deps, 'exec'), ctx) new_contents = '' @@ -100,7 +98,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 abddf7893..8537769e9 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. +#!/usr/bin/env python3 +# 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. # @@ -39,7 +38,6 @@ updating any references to the FILE records in the other record types. """ -import macpath import ntpath import optparse import os @@ -133,8 +131,8 @@ def _AdjustPath(self, path): Returns: The actual path to use when writing the FILE record. """ - return path[len(filter(path.startswith, - self.ignored_prefixes + [''])[0]):] + return path[len(next(filter(path.startswith, + self.ignored_prefixes + ['']))):] def _ParseFileRecord(self, file_record): """Parses and corrects a FILE record.""" @@ -194,7 +192,7 @@ def main(): symbol_parser = SymbolFileParser(sys.stdin, sys.stdout, options.prefixes, path_handler) symbol_parser.Process() - except BreakpadParseError, e: + except BreakpadParseError as e: print >> sys.stderr, 'Got an error while processing symbol file' print >> sys.stderr, str(e) return 1 diff --git a/src/tools/python/tests/filter_syms_unittest.py b/src/tools/python/tests/filter_syms_unittest.py index b111f3498..f6364b8b3 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. +#!/usr/bin/env python3 +# 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. # @@ -30,10 +29,9 @@ """Unit tests for filter_syms.py""" -import cStringIO +import io import ntpath import os -import StringIO import sys import unittest @@ -45,8 +43,8 @@ class FilterSysmsTest(unittest.TestCase): def assertParsed(self, input_data, ignored_prefixes, expected): - input_io = cStringIO.StringIO(input_data) - output_io = cStringIO.StringIO() + input_io = io.StringIO(input_data) + output_io = io.StringIO() parser = filter_syms.SymbolFileParser(input_io, output_io, ignored_prefixes, ntpath) parser.Process() @@ -135,4 +133,4 @@ def testIgnoredPrefixesDuplicateFiles(self): self.assertParsed(INPUT, IGNORED_PREFIXES, EXPECTED_OUTPUT) if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/src/tools/solaris/dump_syms/Makefile b/src/tools/solaris/dump_syms/Makefile index ff77105c6..c5f48240e 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 ba396e10a..8f5924ae2 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. // @@ -29,11 +28,16 @@ // Author: Alfred Peng -#include -#include +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif #include "common/solaris/dump_symbols.h" +#include + +#include + using namespace google_breakpad; int main(int argc, char** argv) { diff --git a/src/tools/solaris/dump_syms/run_regtest.sh b/src/tools/solaris/dump_syms/run_regtest.sh index ffb343306..27710d9ac 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 6824ed98b..fb6c883b5 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. // @@ -29,6 +28,10 @@ // ./dump_syms dump_syms_regtest.pdb > dump_syms_regtest.sym +#ifdef HAVE_CONFIG_H +#include +#endif + namespace google_breakpad { class C { diff --git a/src/tools/tools.gyp b/src/tools/tools.gyp deleted file mode 100644 index e6a4210fe..000000000 --- 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 102d06fd4..42878f52d 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. // @@ -34,14 +33,19 @@ // // Author: Mark Mentovai +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "tools/windows/converter/ms_symbol_server_converter.h" + #include + +#include #include #include +#include -#include -#include - -#include "tools/windows/converter/ms_symbol_server_converter.h" #include "common/windows/pdb_source_line_writer.h" #include "common/windows/pe_source_line_writer.h" #include "common/windows/string_utils-inl.h" @@ -128,11 +132,15 @@ bool GUIDOrSignatureIdentifier::InitializeFromString( #undef SSCANF MSSymbolServerConverter::MSSymbolServerConverter( - const string& local_cache, const vector& symbol_servers) + const string& local_cache, + const vector& 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 @@ -325,7 +333,7 @@ MSSymbolServerConverter::LocateFile(const string& debug_or_code_file, // Do the lookup. char path[MAX_PATH]; if (!SymFindFileInPath( - process, NULL, + process, nullptr, const_cast(debug_or_code_file.c_str()), const_cast(identifier.guid_or_signature_pointer()), identifier.age(), 0, @@ -342,6 +350,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, @@ -425,6 +437,10 @@ BOOL CALLBACK MSSymbolServerConverter::SymCallback(HANDLE process, // 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. @@ -434,29 +450,32 @@ BOOL CALLBACK MSSymbolServerConverter::SymCallback(HANDLE process, }; 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 < @@ -580,7 +599,7 @@ MSSymbolServerConverter::LocateAndConvertSymbolFile( *converted_symbol_file = pdb_file.substr(0, pdb_file.length() - 4) + ".sym"; - FILE* converted_output = NULL; + FILE* converted_output = nullptr; #if _MSC_VER >= 1400 // MSVC 2005/8 errno_t err; if ((err = fopen_s(&converted_output, converted_symbol_file->c_str(), "w")) @@ -676,7 +695,7 @@ MSSymbolServerConverter::LocateAndConvertPEFile( *converted_symbol_file = pe_file.substr(0, pe_file.length() - 4) + ".sym"; - FILE* converted_output = NULL; + FILE* converted_output = nullptr; #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 57ec79068..000000000 --- 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 40d65d52a..ffdea7c0a 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. // @@ -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,8 +141,11 @@ 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. + // If |trace_symsrv| is set then callbacks from SymSrv will be logged to + // stderr. MSSymbolServerConverter(const string& local_cache, - const vector& symbol_servers); + const vector& 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 @@ -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 06bd8ebb3..9e1df7f8b 100644 --- a/src/tools/windows/converter_exe/converter.cc +++ b/src/tools/windows/converter_exe/converter.cc @@ -1,807 +1,909 @@ -// 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 -#include -#include -#include -#include -#include -#include - -#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,& 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 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& smap, - map* wsmap) { - assert(wsmap); - wsmap->clear(); - - for (map::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* wparameters) { - assert(wparameters); - - map 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 parameters; - if (!MissingSymbolInfoToParameters(missing_info,& parameters)) { - // 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 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 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) { - } - - ~ConverterOptions() { - } - - // Names of MS Symbol Supplier Servers that are internal to Google, and may - // have symbols for any request. - vector 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 full_external_msss_servers; - - // Names of MS Symbol Supplier Servers that are external to Google, and may - // have symbols for any request. - vector 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 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 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 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,& parameters, - & missing_symbol_list, NULL)) { - return false; - } - - // Tokenize the content into a vector. - vector 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::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 MS servers to ask for all symbols\n" - " -n same, but prevent asking for EXEs\n" - " -l Temporary local storage for symbols\n" - " -s URL for uploading symbols\n" - " -m URL to fetch list of missing symbols\n" - " -mf File containing the list of missing\n" - " symbols. Fetch failures are not\n" - " reported if such file is provided.\n" - " -t URL to report symbol fetch failure\n" - " -b 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* internal_servers, - vector* 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") + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#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 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& smap, + map* wsmap) { + assert(wsmap); + wsmap->clear(); + + for (map::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* wparameters) { + assert(wparameters); + + map 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 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, + nullptr)) { + 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 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 full_external_msss_servers; + + // Names of MS Symbol Supplier Servers that are external to Google, and may + // have symbols for any request. + vector 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 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 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(const 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) != nullptr) { + 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 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, nullptr)) { + return false; + } + + // Tokenize the content into a vector. + vector 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::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 MS servers to ask for all symbols\n" + " -n same, but prevent asking for EXEs\n" + " -l Temporary local storage for symbols\n" + " -s URL for uploading symbols\n" + " -k API key to use when uploading symbols\n" + " -m URL to fetch list of missing symbols\n" + " -mf File containing the list of missing\n" + " symbols. Fetch failures are not\n" + " reported if such file is provided.\n" + " -t URL to report symbol fetch failure\n" + " -b 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* internal_servers, + vector* 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 fe443d1b4..000000000 --- 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 74a7203ab..bb7b50363 100644 --- a/src/tools/windows/converter_exe/escaping.cc +++ b/src/tools/windows/converter_exe/escaping.cc @@ -1,757 +1,765 @@ -// 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 - -#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 is like scoped_ptr, except that the caller must allocate -// with new [] and the destructor deletes objects with delete []. -// -// As with scoped_ptr, a scoped_array either points to an object -// or is NULL. A scoped_array owns the object that it points to. -// scoped_array is thread-compatible, and once you index into it, -// the returned objects have only the threadsafety guarantees of T. -// -// Size: sizeof(scoped_array) == sizeof(C*) -template -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 bool operator==(scoped_array const& p2) const; - template bool operator!=(scoped_array 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(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(src[0])] << 18) | - (unbase64[static_cast(src[1])] << 12) | - (unbase64[static_cast(src[2])] << 6) | - (unbase64[static_cast(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(src[0])] << 18) | - (unbase64[static_cast(src[1])] << 12) | - (unbase64[static_cast(src[2])] << 6) | - (unbase64[static_cast(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 - // #include - // #include - // 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(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 - // #include - // #include - // 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 buf(new char[encoded_len]); - int len = WebSafeBase64Escape(reinterpret_cast(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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "tools/windows/converter_exe/escaping.h" + +#include + +#include + +#include "common/scoped_ptr.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 is like std::unique_ptr, except that the caller must allocate +// with new [] and the destructor deletes objects with delete []. +// +// As with std::unique_ptr, a scoped_array either points to an object +// or is NULL. A scoped_array owns the object that it points to. +// scoped_array is thread-compatible, and once you index into it, +// the returned objects have only the threadsafety guarantees of T. +// +// Size: sizeof(scoped_array) == sizeof(C*) +template +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 = nullptr) : 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 = nullptr) { + 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_ != nullptr); + 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_ = nullptr; + return retVal; + } + + private: + C* array_; + + // Forbid comparison of different scoped_array types. + template bool operator==(scoped_array const& p2) const; + template bool operator!=(scoped_array 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(str->data())! See the unittest for why. + return str->empty() ? nullptr : &*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(src[0])] << 18) | + (unbase64[static_cast(src[1])] << 12) | + (unbase64[static_cast(src[2])] << 6) | + (unbase64[static_cast(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(src[0])] << 18) | + (unbase64[static_cast(src[1])] << 12) | + (unbase64[static_cast(src[2])] << 6) | + (unbase64[static_cast(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 + // #include + // #include + // 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 == nullptr) || (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(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 + // #include + // #include + // 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 == nullptr) || (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 buf(new char[encoded_len]); + int len = WebSafeBase64Escape(reinterpret_cast(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 c8aa90b7b..bc36bf57c 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 - -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 + +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 -#include -#include - -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 +#include +#include + +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 58fcbb3bf..054ffbe6f 100644 --- a/src/tools/windows/converter_exe/http_download.cc +++ b/src/tools/windows/converter_exe/http_download.cc @@ -1,326 +1,330 @@ -// 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 -#include -#include -#include - -#include - -#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::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 -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* parameters) { - for (map::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* parameters, - string *content, int *status_code) { - assert(content); - AutoPtr 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::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::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 response_buffer = vector(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(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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include +#include +#include +#include + +#include + +#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::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_(nullptr) {} + 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 +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* parameters) { + for (map::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 = nullptr; + + 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 == nullptr) { + 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 == nullptr) { + return CreateWinInetClient(url); + } + + return http_client; +} + +// static +bool HTTPDownload::Download(const wstring& url, + const map* parameters, + string *content, int *status_code) { + assert(content); + AutoPtr 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(nullptr, // user agent + HttpClient::ACCESS_TYPE_PRECONFIG, + nullptr, // proxy name + nullptr, // 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::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(), + nullptr, // version + nullptr, // 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(), nullptr, 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::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 response_buffer = vector(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(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 cbae11b5a..f58a3d0f9 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 -#include -#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* 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 +#include +#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* 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 aee398676..08480d7be 100644 --- a/src/tools/windows/converter_exe/tokenizer.cc +++ b/src/tools/windows/converter_exe/tokenizer.cc @@ -1,61 +1,65 @@ -// 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 - -#include "tools/windows/converter_exe/tokenizer.h" - -namespace crash { - -// static -void Tokenizer::Tokenize(const string& delimiters, const string& input, - vector* 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include + +#include "tools/windows/converter_exe/tokenizer.h" + +namespace crash { + +// static +void Tokenizer::Tokenize(const string& delimiters, const string& input, + vector* 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 bfdfa220a..d9829f605 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 -#include - -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* 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 +#include + +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* 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 cc70e53f4..371b32c16 100644 --- a/src/tools/windows/converter_exe/winhttp_client.cc +++ b/src/tools/windows/converter_exe/winhttp_client.cc @@ -1,307 +1,311 @@ -// 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 -#include -#include -#include -#include - -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(scheme_buffer_length); - url_comp.lpszHostName = host; - url_comp.dwHostNameLength = static_cast(host_buffer_length); - url_comp.lpszUrlPath = uri; - url_comp.dwUrlPathLength = static_cast(uri_buffer_length); - - bool result = !!::WinHttpCrackUrl(url, 0, flags, &url_comp); - if (result) { - *port = static_cast(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(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(&http_status_string), - &http_status_string_size, 0)) { - return false; - } - - *status_code = static_cast(_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(&content_length_string), - &content_length_string_size, 0)) { - *content_length = kUnknownContentLength; - } else { - *content_length = - static_cast(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(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(handle); -} - -HttpHandle WinHttpClient::FromHINTERNET(HINTERNET handle) { - return static_cast(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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "tools/windows/converter_exe/winhttp_client.h" + +#include +#include +#include +#include +#include + +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(scheme_buffer_length); + url_comp.lpszHostName = host; + url_comp.dwHostNameLength = static_cast(host_buffer_length); + url_comp.lpszUrlPath = uri; + url_comp.dwUrlPathLength = static_cast(uri_buffer_length); + + bool result = !!::WinHttpCrackUrl(url, 0, flags, &url_comp); + if (result) { + *port = static_cast(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(port), + 0)); + 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, + nullptr, + 0, + WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, + 0); +} + +bool WinHttpClient::ReceiveResponse(HttpHandle request_handle) const { + assert(request_handle); + + return !!::WinHttpReceiveResponse(ToHINTERNET(request_handle), nullptr); +} + +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(&http_status_string), + &http_status_string_size, 0)) { + return false; + } + + *status_code = static_cast(_tcstol(http_status_string, nullptr, 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(&content_length_string), + &content_length_string_size, 0)) { + *content_length = kUnknownContentLength; + } else { + *content_length = + static_cast(wcstol(content_length_string, nullptr, 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(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(handle); +} + +HttpHandle WinHttpClient::FromHINTERNET(HINTERNET handle) { + return static_cast(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 nullptr; + } + + 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 nullptr; + } + + 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 819d610f1..4ccac7e0b 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 986a66ff4..43fb43c5b 100644 --- a/src/tools/windows/converter_exe/wininet_client.cc +++ b/src/tools/windows/converter_exe/wininet_client.cc @@ -1,278 +1,282 @@ -// 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 -#include -#include -#include - -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(scheme_buffer_length); - url_comp.lpszHostName = host; - url_comp.dwHostNameLength = static_cast(host_buffer_length); - url_comp.lpszUrlPath = uri; - url_comp.dwUrlPathLength = static_cast(uri_buffer_length); - - bool result = !!::InternetCrackUrl(url, 0, flags, &url_comp); - if (result) { - *port = static_cast(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(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(&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(&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(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(handle); -} - -HttpHandle WinInetClient::FromHINTERNET(HINTERNET handle) { - return static_cast(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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include "tools/windows/converter_exe/wininet_client.h" + +#include +#include +#include +#include + +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(scheme_buffer_length); + url_comp.lpszHostName = host; + url_comp.dwHostNameLength = static_cast(host_buffer_length); + url_comp.lpszUrlPath = uri; + url_comp.dwUrlPathLength = static_cast(uri_buffer_length); + + bool result = !!::InternetCrackUrl(url, 0, flags, &url_comp); + if (result) { + *port = static_cast(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(port), + nullptr, + nullptr, + 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, + nullptr, + is_secure ? INTERNET_FLAG_SECURE : 0, + 0)); + 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, + nullptr, + 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(&http_status_string), + &http_status_string_size, + 0)) { + return false; + } + + *status_code = _tcstol(http_status_string, nullptr, 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(&content_length_string), + &content_length_string_size, + 0)) { + *content_length = kUnknownContentLength; + } else { + *content_length = wcstol(content_length_string, nullptr, 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(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(handle); +} + +HttpHandle WinInetClient::FromHINTERNET(HINTERNET handle) { + return static_cast(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 bd04b605d..8b4c61b57 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/converter_exe/winsymconv.cmd b/src/tools/windows/converter_exe/winsymconv.cmd index bea84b589..ca1847847 100644 --- a/src/tools/windows/converter_exe/winsymconv.cmd +++ b/src/tools/windows/converter_exe/winsymconv.cmd @@ -39,6 +39,7 @@ google_converter.exe ^ -n https://download.amd.com/dir/bin ^ -n https://driver-symbols.nvidia.com ^ -n https://software.intel.com/sites/downloads/symbols ^ + -n https://www.nvaccess.org/files/nvda/symbols ^ -l %SYMBOL_DIR% ^ -s https://clients2.google.com/cr/staging_symbol ^ -m https://clients2.google.com/cr/staging_symbol/missingsymbols ^ @@ -58,6 +59,7 @@ google_converter.exe ^ -n https://download.amd.com/dir/bin ^ -n https://driver-symbols.nvidia.com ^ -n https://software.intel.com/sites/downloads/symbols ^ + -n https://www.nvaccess.org/files/nvda/symbols ^ -l %SYMBOL_DIR% ^ -s https://clients2.google.com/cr/symbol ^ -m https://clients2.google.com/cr/symbol/missingsymbols ^ diff --git a/src/tools/windows/converter_exe/winsymconv_test.cmd b/src/tools/windows/converter_exe/winsymconv_test.cmd index c17770660..448244d84 100644 --- a/src/tools/windows/converter_exe/winsymconv_test.cmd +++ b/src/tools/windows/converter_exe/winsymconv_test.cmd @@ -37,6 +37,7 @@ google_converter.exe ^ -n https://download.amd.com/dir/bin ^ -n https://driver-symbols.nvidia.com ^ -n https://software.intel.com/sites/downloads/symbols ^ + -n https://www.nvaccess.org/files/nvda/symbols ^ -l %SYMBOL_DIR% ^ -s https://clients2.google.com/cr/staging_symbol ^ -mf %SCRIPT_LOCATION%missing_symbols_test.txt ^ @@ -56,6 +57,7 @@ google_converter.exe ^ -n https://download.amd.com/dir/bin ^ -n https://driver-symbols.nvidia.com ^ -n https://software.intel.com/sites/downloads/symbols ^ + -n https://www.nvaccess.org/files/nvda/symbols ^ -l %SYMBOL_DIR% ^ -s https://clients2.google.com/cr/symbol ^ -mf %SCRIPT_LOCATION%missing_symbols_test.txt ^ diff --git a/src/tools/windows/dump_syms/dump_syms.cc b/src/tools/windows/dump_syms/dump_syms.cc index 1b1797dc2..1979d4306 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. // @@ -30,38 +29,68 @@ // Windows utility to dump the line number data from a pdb file to // a text-based format that we can use from the minidump processor. +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include #include +#include #include #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] \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)) { + 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] \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 b815574b2..000000000 --- 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 accecda13..f50bd3b89 100644 --- a/src/tools/windows/dump_syms/dump_syms_unittest.cc +++ b/src/tools/windows/dump_syms/dump_syms_unittest.cc @@ -1,244 +1,248 @@ -// 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 -#include - -#include -#include - -#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 { - 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 { -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 +// 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. + +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + +#include +#include + +#include +#include + +#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 != nullptr) + component->assign(path.c_str() + len, path.c_str() + path.size()); + + while (len > 0 && path[len - 1] == '\\') + --len; + + if (trimmed != nullptr) + 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 = nullptr; + args = ::CommandLineToArgvW(command_line.c_str(), &num_args); + if (args == nullptr) + return false; + + *self_dir = args[0]; + TrimLastComponent(*self_dir, self_dir, nullptr); + + 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 = nullptr; + startup_info.hStdInput = child_stdin_read; + startup_info.hStdOutput = child_stdout_write; + startup_info.dwFlags = STARTF_USESTDHANDLES; + ASSERT_TRUE(::CreateProcessW(nullptr, (LPWSTR)command_line.c_str(), nullptr, + nullptr, TRUE, 0, nullptr, nullptr, + &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, + nullptr) && 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 != nullptr); + + 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 { + 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, nullptr); + testdata_dir += L"\\testdata"; + } + + std::wstring dump_syms_exe; + std::wstring testdata_dir; +}; + +class DumpSymsPEOnlyRegressionTest : public testing::TestWithParam { +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, nullptr); + 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 1f20f64fd..2401edd14 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 de6109fe2..90d00af2e 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. // @@ -36,6 +35,11 @@ // cl /Zi dump_syms_regtest64.cc /link /PROFILE // dump_syms dump_syms_regtest64.pdb > dump_syms_regtest64.sym +#ifdef HAVE_CONFIG_H +#include +#endif + + namespace google_breakpad { class C { diff --git a/src/tools/windows/symupload/symupload.cc b/src/tools/windows/symupload/symupload.cc index e6fa126fa..256a6f04e 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. // @@ -43,33 +42,36 @@ // cpu: the CPU that the module was built for, typically "x86". // symbol_file: the contents of the breakpad-format symbol file +#ifdef HAVE_CONFIG_H +#include // Must come first +#endif + #include + #include +#include #include -#include #include #include #include -#include "common/windows/string_utils-inl.h" - #include "common/windows/http_upload.h" #include "common/windows/pdb_source_line_writer.h" +#include "common/windows/string_utils-inl.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. @@ -85,7 +87,7 @@ static bool GetFileVersionString(const wchar_t* filename, wstring* version) { return false; } - void* file_info_buffer = NULL; + void* file_info_buffer = nullptr; unsigned int file_info_length; if (!VerQueryValue(&version_info[0], L"\\", &file_info_buffer, &file_info_length)) { @@ -116,8 +118,9 @@ static bool GetFileVersionString(const wchar_t* filename, wstring* version) { // 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; + 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 +138,7 @@ static bool DumpSymbolsToTempFile(const wchar_t* file, return false; } - FILE* temp_file = NULL; + FILE* temp_file = nullptr; #if _MSC_VER >= 1400 // MSVC 2005/8 if (_wfopen_s(&temp_file, temp_filename, L"w") != 0) #else // _MSC_VER >= 1400 @@ -159,97 +162,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" ^\n" L" [...]\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" @@ -273,6 +191,7 @@ __declspec(noreturn) void printUsageAndExit() { 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 +199,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 +234,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 +253,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(); } @@ -370,7 +292,7 @@ int wmain(int argc, wchar_t* argv[]) { while (currentarg < argc) { int response_code; if (!HTTPUpload::SendMultipartPostRequest(argv[currentarg], parameters, files, - timeout == -1 ? NULL : &timeout, + timeout == -1 ? nullptr : &timeout, nullptr, &response_code)) { success = false; fwprintf(stderr, @@ -383,12 +305,12 @@ int wmain(int argc, wchar_t* argv[]) { _wunlink(symbol_file.c_str()); - if (success) { - wprintf(L"Uploaded breakpad symbols for windows-%s/%s/%s (%s %s)\n", - pdb_info.cpu.c_str(), pdb_info.debug_file.c_str(), - pdb_info.debug_identifier.c_str(), code_file.c_str(), - file_version.c_str()); - } + fwprintf(success ? stdout : stderr, + L"%S breakpad symbols for windows-%s/%s/%s (%s %s)\n", + success ? "Uploaded" : "Failed to upload", + pdb_info.cpu.c_str(), pdb_info.debug_file.c_str(), + pdb_info.debug_identifier.c_str(), code_file.c_str(), + file_version.c_str()); return success ? 0 : 1; } diff --git a/src/tools/windows/symupload/symupload.gyp b/src/tools/windows/symupload/symupload.gyp deleted file mode 100644 index 4567a4bdf..000000000 --- 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 17b88b4a7..000000000 --- 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:*', - ], - }, - ], -}