From 89d22e5f94e2a01f168d4a60a899e1c8d22a8593 Mon Sep 17 00:00:00 2001 From: Marek Roszko Date: Wed, 15 Feb 2023 21:08:10 -0500 Subject: [PATCH] update sentry-native to 0.6.0 primarily interested in windows bug fix to stack unwinding (cherry picked from commit 041b7b196d6b7e9a2604361608a2ee86c25aebfb) --- thirdparty/sentry-native/CHANGELOG.md | 31 + thirdparty/sentry-native/CMakeLists.txt | 23 +- .../sentry-native/external/CMakeLists.txt | 6 + .../sentry-native/external/breakpad/LICENSE | 1003 +++++++++- .../external/breakpad/Makefile.am | 86 +- .../external/breakpad/Makefile.in | 664 +++++-- .../sentry-native/external/breakpad/configure | 1637 +++++++++++++++++ .../external/breakpad/configure.ac | 2 +- .../linux/minidump_writer/cpu_set_unittest.cc | 60 +- .../minidump_writer/line_reader_unittest.cc | 41 +- .../proc_cpuinfo_reader_unittest.cc | 56 +- .../breakpad/src/common/dwarf/elf_reader.cc | 36 +- .../breakpad/src/common/dwarf/elf_reader.h | 4 +- .../src/common/dwarf_cfi_to_module.cc | 7 +- .../breakpad/src/common/dwarf_cfi_to_module.h | 7 +- .../breakpad/src/common/linux/dump_symbols.cc | 39 +- .../src/common/linux/elf_symbols_to_module.cc | 7 +- .../src/common/linux/libcurl_wrapper.cc | 5 + .../src/common/linux/libcurl_wrapper.h | 4 + .../breakpad/src/common/linux/scoped_pipe.cc | 128 ++ .../breakpad/src/common/linux/scoped_pipe.h | 115 ++ .../src/common/linux/scoped_pipe_unittest.cc | 71 + .../src/common/linux/scoped_tmpfile.cc | 99 + .../src/common/linux/scoped_tmpfile.h | 85 + .../common/linux/scoped_tmpfile_unittest.cc | 46 + .../src/common/linux/tests/auto_testfile.h | 123 -- .../breakpad/src/common/mac/dump_syms.cc | 25 +- .../breakpad/src/common/mac/dump_syms.h | 11 +- .../external/breakpad/src/common/module.cc | 39 +- .../external/breakpad/src/common/module.h | 21 +- .../breakpad/src/common/module_unittest.cc | 93 +- .../breakpad/src/common/stabs_to_module.cc | 6 +- .../common/minidump_exception_mac.h | 4 + .../google_breakpad/common/minidump_format.h | 15 + .../src/google_breakpad/processor/minidump.h | 18 + .../sentry-native/external/crashpad/BUILD.gn | 2 + .../external/crashpad/CMakeLists.txt | 9 +- .../sentry-native/external/crashpad/DEPS | 2 +- .../crashpad/build/crashpad_buildconfig.gni | 6 +- .../external/crashpad/build/run_tests.py | 23 +- .../external/crashpad/client/BUILD.gn | 16 + .../external/crashpad/client/CMakeLists.txt | 2 + .../external/crashpad/client/annotation.h | 83 +- .../crashpad/client/annotation_test.cc | 102 + .../in_process_intermediate_dump_handler.cc | 48 + .../client/length_delimited_ring_buffer.h | 603 ++++++ .../length_delimited_ring_buffer_test.cc | 348 ++++ .../crashpad/client/ring_buffer_annotation.h | 136 ++ .../ring_buffer_annotation_load_test_main.cc | 474 +++++ .../client/ring_buffer_annotation_test.cc | 188 ++ .../external/crashpad/compat/mingw/dbghelp.h | 31 + .../external/crashpad/compat/mingw/werapi.h | 28 + .../external/crashpad/compat/mingw/winnt.h | 12 + .../external/crashpad/handler/CMakeLists.txt | 2 + .../crashpad/handler/win/wer/crashpad_wer.cc | 3 +- .../minidump/minidump_crashpad_info_writer.cc | 10 + .../minidump/minidump_crashpad_info_writer.h | 3 + .../minidump_crashpad_info_writer_test.cc | 53 + .../crashpad/minidump/minidump_extensions.h | 27 +- .../external/crashpad/snapshot/BUILD.gn | 19 + .../external/crashpad/snapshot/CMakeLists.txt | 11 + .../crashpad_types/image_annotation_reader.cc | 6 + .../fuchsia/system_snapshot_fuchsia.h | 2 + .../system_snapshot_ios_intermediate_dump.cc | 8 + .../system_snapshot_ios_intermediate_dump.h | 2 + .../snapshot/linux/system_snapshot_linux.h | 1 + .../mac/mach_o_image_annotations_reader.cc | 7 + .../snapshot/mac/system_snapshot_mac.cc | 14 + .../snapshot/mac/system_snapshot_mac.h | 1 + .../minidump/process_snapshot_minidump.cc | 32 +- .../process_snapshot_minidump_test.cc | 41 + .../minidump/system_snapshot_minidump.cc | 6 + .../minidump/system_snapshot_minidump.h | 1 + .../crashpad/snapshot/system_snapshot.h | 14 + .../snapshot/test/test_system_snapshot.cc | 8 +- .../snapshot/test/test_system_snapshot.h | 4 + .../snapshot/win/process_reader_win.cc | 24 +- .../snapshot/win/system_snapshot_win.h | 1 + .../external/crashpad/test/gtest_main.cc | 2 +- .../external/crashpad/test/ios/BUILD.gn | 1 + .../crashpad/test/ios/crash_type_xctest.mm | 28 + .../ios/host/cptest_application_delegate.mm | 34 +- .../external/crashpad/third_party/lss/lss.h | 2 +- .../third_party/mini_chromium/BUILD.gn | 7 +- .../crashpad/third_party/zlib/CMakeLists.txt | 6 +- .../external/crashpad/util/BUILD.gn | 8 +- .../external/crashpad/util/CMakeLists.txt | 27 +- .../util/ios/ios_intermediate_dump_format.h | 2 +- .../util/ios/ios_system_data_collector.h | 2 + .../util/ios/ios_system_data_collector.mm | 10 + .../crashpad/util/ios/scoped_vm_map.cc | 86 + .../crashpad/util/ios/scoped_vm_map.h | 125 ++ .../crashpad/util/ios/scoped_vm_map_test.cc | 94 + .../crashpad/util/ios/scoped_vm_read.cc | 44 +- .../crashpad/util/ios/scoped_vm_read.h | 14 +- .../crashpad/util/ios/scoped_vm_read_test.cc | 45 +- .../crashpad/util/mac/mac_util_test.mm | 11 - .../util/synchronization/scoped_spin_guard.h | 122 ++ .../synchronization/scoped_spin_guard_test.cc | 109 ++ .../libunwindstack-ndk/DwarfSection.cpp | 6 + .../external/libunwindstack-ndk/Elf.cpp | 11 + .../libunwindstack-ndk/GlobalDebugImpl.h | 7 + .../libunwindstack-ndk/LogAndroid.cpp | 27 + .../external/libunwindstack-ndk/LogStdout.cpp | 10 + .../external/libunwindstack-ndk/Maps.cpp | 2 +- .../external/libunwindstack-ndk/Memory.cpp | 268 +-- .../external/libunwindstack-ndk/MemoryMte.cpp | 22 + .../external/libunwindstack-ndk/Regs.cpp | 47 +- .../external/libunwindstack-ndk/RegsArm64.cpp | 12 + .../external/libunwindstack-ndk/Symbols.cpp | 59 +- .../external/libunwindstack-ndk/Symbols.h | 5 +- .../libunwindstack-ndk/ThreadEntry.cpp | 13 +- .../external/libunwindstack-ndk/ThreadEntry.h | 2 + .../libunwindstack-ndk/ThreadUnwinder.cpp | 11 +- .../external/libunwindstack-ndk/Unwinder.cpp | 8 + .../include/unwindstack/AndroidUnwinder.h | 1 + .../include/unwindstack/Arch.h | 8 + .../include/unwindstack/Elf.h | 6 + .../include/unwindstack/RegsGetLocal.h | 45 + .../include/unwindstack/SharedString.h | 7 +- thirdparty/sentry-native/include/sentry.h | 47 +- .../src/backends/sentry_backend_crashpad.cpp | 2 +- thirdparty/sentry-native/src/exports.map | 4 + thirdparty/sentry-native/src/sentry_core.c | 4 +- thirdparty/sentry-native/src/sentry_info.c | 6 +- thirdparty/sentry-native/src/sentry_scope.c | 4 +- thirdparty/sentry-native/src/sentry_scope.h | 4 +- thirdparty/sentry-native/src/sentry_session.c | 26 +- thirdparty/sentry-native/src/sentry_session.h | 7 - thirdparty/sentry-native/src/sentry_sync.c | 2 +- thirdparty/sentry-native/src/sentry_sync.h | 2 +- thirdparty/sentry-native/src/sentry_utils.c | 2 +- .../src/unwinder/sentry_unwinder_dbghelp.c | 20 +- thirdparty/sentry-native/tests/assertions.py | 4 +- thirdparty/sentry-native/tests/cmake.py | 2 +- .../tests/test_integration_http.py | 2 +- .../sentry-native/tests/unit/CMakeLists.txt | 1 + .../sentry-native/tests/unit/test_session.c | 7 +- 138 files changed, 7622 insertions(+), 910 deletions(-) create mode 100644 thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_pipe.cc create mode 100644 thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_pipe.h create mode 100644 thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_pipe_unittest.cc create mode 100644 thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_tmpfile.cc create mode 100644 thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_tmpfile.h create mode 100644 thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_tmpfile_unittest.cc delete mode 100644 thirdparty/sentry-native/external/breakpad/src/common/linux/tests/auto_testfile.h create mode 100644 thirdparty/sentry-native/external/crashpad/client/length_delimited_ring_buffer.h create mode 100644 thirdparty/sentry-native/external/crashpad/client/length_delimited_ring_buffer_test.cc create mode 100644 thirdparty/sentry-native/external/crashpad/client/ring_buffer_annotation.h create mode 100644 thirdparty/sentry-native/external/crashpad/client/ring_buffer_annotation_load_test_main.cc create mode 100644 thirdparty/sentry-native/external/crashpad/client/ring_buffer_annotation_test.cc create mode 100644 thirdparty/sentry-native/external/crashpad/compat/mingw/werapi.h create mode 100644 thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_map.cc create mode 100644 thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_map.h create mode 100644 thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_map_test.cc create mode 100644 thirdparty/sentry-native/external/crashpad/util/synchronization/scoped_spin_guard.h create mode 100644 thirdparty/sentry-native/external/crashpad/util/synchronization/scoped_spin_guard_test.cc create mode 100644 thirdparty/sentry-native/src/exports.map diff --git a/thirdparty/sentry-native/CHANGELOG.md b/thirdparty/sentry-native/CHANGELOG.md index 9ca80e7440..a1cde9759a 100644 --- a/thirdparty/sentry-native/CHANGELOG.md +++ b/thirdparty/sentry-native/CHANGELOG.md @@ -1,5 +1,36 @@ # Changelog +## 0.6.0 + +**Breaking changes**: + +- When built as a shared library for Android or Linux, the Native SDK limits the export of symbols to the `sentry_`-prefix. The option `SENTRY_EXPORT_SYMBOLS` is no longer available and the linker settings are constrained to the Native SDK and no longer `PUBLIC` to parent projects. ([#363](https://github.com/getsentry/sentry-native/pull/363)) + +**Features**: + +- A session may be ended with a different status code. ([#801](https://github.com/getsentry/sentry-native/pull/801)) + +**Fixes**: + +- Switch Crashpad transport on Linux to use libcurl ([#803](https://github.com/getsentry/sentry-native/pull/803), [crashpad#75](https://github.com/getsentry/crashpad/pull/75), [crashpad#79](https://github.com/getsentry/crashpad/pull/79)) +- Avoid accidentally mutating CONTEXT when client-side stack walking in Crashpad ([#803](https://github.com/getsentry/sentry-native/pull/803), [crashpad#77](https://github.com/getsentry/crashpad/pull/77)) +- Fix various mingw compilation issues ([#794](https://github.com/getsentry/sentry-native/pull/794), [crashpad#78](https://github.com/getsentry/crashpad/pull/78)) + +**Internal**: + +- Updated Crashpad backend to 2023-02-07. ([#803](https://github.com/getsentry/sentry-native/pull/803), [crashpad#80](https://github.com/getsentry/crashpad/pull/80)) +- CI: Updated GitHub Actions to test on LLVM-mingw. ([#797](https://github.com/getsentry/sentry-native/pull/797)) +- Updated Breakpad backend to 2023-02-08. ([#805](https://github.com/getsentry/sentry-native/pull/805), [breakpad#34](https://github.com/getsentry/breakpad/pull/34)) +- Updated libunwindstack to 2023-02-09. ([#807](https://github.com/getsentry/sentry-native/pull/807), [libunwindstack-ndk#7](https://github.com/getsentry/libunwindstack-ndk/pull/7)) + +**Thank you**: + +Features, fixes and improvements in this release have been contributed by: + +- [@BogdanLivadariu](https://github.com/BogdanLivadariu) +- [@ShawnCZek](https://github.com/ShawnCZek) +- [@past-due](https://github.com/past-due) + ## 0.5.4 **Fixes**: diff --git a/thirdparty/sentry-native/CMakeLists.txt b/thirdparty/sentry-native/CMakeLists.txt index 21adb7b1cc..67331dd4c0 100644 --- a/thirdparty/sentry-native/CMakeLists.txt +++ b/thirdparty/sentry-native/CMakeLists.txt @@ -334,16 +334,6 @@ target_include_directories(sentry "$" ) -# The modulefinder and symbolizer need these two settings, and they are exported -# as `PUBLIC`, so libraries that depend on sentry get these too: -# `-E`: To have all symbols in the dynamic symbol table. -# `--build-id`: To have a build-id in the ELF object. -# FIXME: cmake 3.13 introduced target_link_options -option(SENTRY_EXPORT_SYMBOLS "Export symbols for modulefinder and symbolizer" ON) -if(SENTRY_EXPORT_SYMBOLS) - target_link_libraries(sentry PUBLIC - "$<$,$>:-Wl,-E,--build-id=sha1>") -endif() #respect CMAKE_SYSTEM_VERSION if(WIN32) @@ -601,3 +591,16 @@ if(SENTRY_BUILD_EXAMPLES) add_test(NAME sentry_example COMMAND sentry_example) endif() + +# Limit the exported symbols when sentry is built as a shared library to those with a "sentry_" prefix: +# - we do this at the end of the file as to not affect subdirectories reading target_link_libraries from the parent. +# - we do this as PRIVATE since our version script does not make sense in any other project that adds us. +# +# Used linker parameters: +# `--build-id`: To have a build-id in the ELF object. +# `--version-script`: version script either hides "foreign" symbols or defers them as unknown ("U") to system libraries. +# FIXME: cmake 3.13 introduced target_link_options (blocked by Android) +if(SENTRY_BUILD_SHARED_LIBS) + target_link_libraries(sentry PRIVATE + "$<$,$>:-Wl,--build-id=sha1,--version-script=${PROJECT_SOURCE_DIR}/src/exports.map>") +endif() \ No newline at end of file diff --git a/thirdparty/sentry-native/external/CMakeLists.txt b/thirdparty/sentry-native/external/CMakeLists.txt index ca807f71c8..fb2917f4e9 100644 --- a/thirdparty/sentry-native/external/CMakeLists.txt +++ b/thirdparty/sentry-native/external/CMakeLists.txt @@ -20,6 +20,10 @@ set(BREAKPAD_SOURCES_COMMON_LINUX breakpad/src/common/linux/linux_libc_support.cc breakpad/src/common/linux/memory_mapped_file.cc breakpad/src/common/linux/safe_readlink.cc + breakpad/src/common/linux/scoped_pipe.cc + breakpad/src/common/linux/scoped_pipe.h + breakpad/src/common/linux/scoped_tmpfile.cc + breakpad/src/common/linux/scoped_tmpfile.h ) set(BREAKPAD_SOURCES_COMMON_LINUX_GETCONTEXT @@ -119,6 +123,8 @@ set(BREAKPAD_SOURCES_CLIENT_IOS ) add_library(breakpad_client STATIC) +set_property(TARGET breakpad_client PROPERTY CXX_STANDARD 17) +set_property(TARGET breakpad_client PROPERTY CXX_STANDARD_REQUIRED On) target_sources(breakpad_client PRIVATE ${BREAKPAD_SOURCES_COMMON}) if(LINUX OR ANDROID) diff --git a/thirdparty/sentry-native/external/breakpad/LICENSE b/thirdparty/sentry-native/external/breakpad/LICENSE index 832b4efb52..42af8c10cb 100644 --- a/thirdparty/sentry-native/external/breakpad/LICENSE +++ b/thirdparty/sentry-native/external/breakpad/LICENSE @@ -27,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. +Copyright © 1991-2015 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in +http://www.unicode.org/copyright.html. -Disclaimer +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. -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. +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. -Limitations on Rights to Redistribute This Code - -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 @@ -75,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. + +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. + +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. - -@APPLE_LICENSE_HEADER_END@ +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. @@ -129,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/thirdparty/sentry-native/external/breakpad/Makefile.am b/thirdparty/sentry-native/external/breakpad/Makefile.am index 9e66a6852a..1d45f8e561 100644 --- a/thirdparty/sentry-native/external/breakpad/Makefile.am +++ b/thirdparty/sentry-native/external/breakpad/Makefile.am @@ -151,7 +151,6 @@ CLEANFILES = # if !SYSTEM_TEST_LIBS check_LIBRARIES += src/testing/libtesting.a -endif src_testing_libtesting_a_SOURCES = \ src/breakpad_googletest_includes.h \ src/testing/googletest/src/gtest-all.cc \ @@ -159,6 +158,7 @@ src_testing_libtesting_a_SOURCES = \ src/testing/googlemock/src/gmock-all.cc src_testing_libtesting_a_CPPFLAGS = \ $(AM_CPPFLAGS) $(TEST_CFLAGS) +endif # # General @@ -193,7 +193,6 @@ check_PROGRAMS += \ src/processor/basic_source_line_resolver_unittest \ src/processor/cfi_frame_info_unittest \ src/processor/contained_range_map_unittest \ - src/processor/disassembler_objdump_unittest \ src/processor/disassembler_x86_unittest \ src/processor/exploitability_unittest \ src/processor/fast_source_line_resolver_unittest \ @@ -221,6 +220,12 @@ check_PROGRAMS += \ 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 @@ -366,8 +371,6 @@ src_libbreakpad_a_SOURCES = \ src/processor/contained_range_map.h \ src/processor/convert_old_arm64_context.cc \ src/processor/convert_old_arm64_context.h \ - src/processor/disassembler_objdump.h \ - src/processor/disassembler_objdump.cc \ src/processor/disassembler_x86.h \ src/processor/disassembler_x86.cc \ src/processor/dump_context.cc \ @@ -449,6 +452,15 @@ 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 = \ @@ -523,7 +535,6 @@ src_client_linux_libbreakpad_client_a_SOURCES += \ endif # 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) @@ -552,7 +563,10 @@ src_client_linux_linux_client_unittest_shlib_SOURCES = \ 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 \ @@ -911,7 +925,6 @@ 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_objdump.o \ src/processor/disassembler_x86.o \ src/processor/exploitability.o \ src/processor/exploitability_linux.o \ @@ -947,12 +960,38 @@ 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 \ @@ -1033,6 +1072,12 @@ src_processor_microdump_processor_unittest_LDADD = \ 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 @@ -1044,7 +1089,6 @@ src_processor_minidump_processor_unittest_LDADD = \ src/processor/call_stack.o \ src/processor/cfi_frame_info.o \ src/processor/convert_old_arm64_context.o \ - src/processor/disassembler_objdump.o \ src/processor/disassembler_x86.o \ src/processor/dump_context.o \ src/processor/dump_object.o \ @@ -1077,6 +1121,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 \ @@ -1194,7 +1244,6 @@ 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_objdump.o \ src/processor/disassembler_x86.o \ src/processor/exploitability.o \ src/processor/exploitability_linux.o \ @@ -1220,6 +1269,12 @@ src_processor_stackwalker_selftest_LDADD = \ 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 \ @@ -1406,6 +1461,12 @@ src_processor_microdump_stackwalk_LDADD = \ 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 @@ -1416,7 +1477,6 @@ src_processor_minidump_stackwalk_LDADD = \ src/processor/call_stack.o \ src/processor/cfi_frame_info.o \ src/processor/convert_old_arm64_context.o \ - src/processor/disassembler_objdump.o \ src/processor/disassembler_x86.o \ src/processor/dump_context.o \ src/processor/dump_object.o \ @@ -1449,6 +1509,12 @@ src_processor_minidump_stackwalk_LDADD = \ src/processor/symbolic_constants_win.o \ src/processor/tokenize.o \ src/third_party/libdisasm/libdisasm.a +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 ## diff --git a/thirdparty/sentry-native/external/breakpad/Makefile.in b/thirdparty/sentry-native/external/breakpad/Makefile.in index 17a453517e..d790cac43c 100644 --- a/thirdparty/sentry-native/external/breakpad/Makefile.in +++ b/thirdparty/sentry-native/external/breakpad/Makefile.in @@ -131,11 +131,11 @@ 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 = src/common/safe_math_unittest$(EXEEXT) \ $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) \ - $(am__EXEEXT_8) $(am__EXEEXT_9) + $(am__EXEEXT_8) $(am__EXEEXT_9) $(am__EXEEXT_10) noinst_PROGRAMS = EXTRA_PROGRAMS = $(am__EXEEXT_1) @@ -164,7 +164,6 @@ EXTRA_PROGRAMS = $(am__EXEEXT_1) @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver_unittest \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info_unittest \ @DISABLE_PROCESSOR_FALSE@ src/processor/contained_range_map_unittest \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_objdump_unittest \ @DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86_unittest \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_unittest \ @DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver_unittest \ @@ -193,7 +192,12 @@ EXTRA_PROGRAMS = $(am__EXEEXT_1) @DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86_unittest \ @DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump_unittest -@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@am__append_10 = \ +@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 @@ -203,17 +207,17 @@ EXTRA_PROGRAMS = $(am__EXEEXT_1) # Currently Linux only, the macOS client # is built using an Xcode project instead. # -@LINUX_HOST_TRUE@am__append_11 = src/client/linux/libbreakpad_client.a -@LINUX_HOST_TRUE@am__append_12 = breakpad-client.pc -@LINUX_HOST_TRUE@am__append_13 = \ +@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 -@LINUX_HOST_TRUE@am__append_14 = \ +@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_15 = \ +@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 @@ -222,7 +226,7 @@ EXTRA_PROGRAMS = $(am__EXEEXT_1) # Various Breakpad tools # This includes symbol dumpers and uploaders # -@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__append_16 = \ +@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 \ @@ -230,31 +234,69 @@ EXTRA_PROGRAMS = $(am__EXEEXT_1) @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_17 = \ +@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_18 = \ +@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_19 = \ +@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_20 = \ +@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 -@HAVE_GETCONTEXT_FALSE@am__append_21 = \ +@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_22 = \ +@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_23 = \ +@ANDROID_HOST_TRUE@am__append_25 = \ @ANDROID_HOST_TRUE@ -llog -lm -@ANDROID_HOST_TRUE@am__append_24 = \ +@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 + subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_compile_flags.m4 \ @@ -306,7 +348,6 @@ am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver_unittest$(EXEEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info_unittest$(EXEEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/contained_range_map_unittest$(EXEEXT) \ -@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_objdump_unittest$(EXEEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86_unittest$(EXEEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_unittest$(EXEEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver_unittest$(EXEEXT) \ @@ -334,13 +375,16 @@ am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" \ @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) -@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@am__EXEEXT_6 = src/processor/stackwalker_selftest$(EXEEXT) -@LINUX_HOST_TRUE@am__EXEEXT_7 = 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_8 = 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_9 = src/common/mac/macho_reader_unittest$(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 \ @@ -436,13 +480,132 @@ src_client_linux_libbreakpad_client_a_OBJECTS = \ $(am_src_client_linux_libbreakpad_client_a_OBJECTS) src_libbreakpad_a_AR = $(AR) $(ARFLAGS) src_libbreakpad_a_LIBADD = +am__src_libbreakpad_a_SOURCES_DIST = \ + 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 \ + 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_objdump.$(OBJEXT) \ src/processor/disassembler_x86.$(OBJEXT) \ src/processor/dump_context.$(OBJEXT) \ src/processor/dump_object.$(OBJEXT) \ @@ -478,14 +641,18 @@ am_src_libbreakpad_a_OBJECTS = \ src/processor/stackwalker_sparc.$(OBJEXT) \ src/processor/stackwalker_x86.$(OBJEXT) \ src/processor/symbolic_constants_win.$(OBJEXT) \ - src/processor/tokenize.$(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 = -am_src_testing_libtesting_a_OBJECTS = \ - src/testing/googletest/src/libtesting_a-gtest-all.$(OBJEXT) \ - src/testing/googletest/src/libtesting_a-gtest_main.$(OBJEXT) \ - src/testing/googlemock/src/libtesting_a-gmock-all.$(OBJEXT) +am__src_testing_libtesting_a_SOURCES_DIST = \ + src/breakpad_googletest_includes.h \ + src/testing/googletest/src/gtest-all.cc \ + src/testing/googletest/src/gtest_main.cc \ + src/testing/googlemock/src/gmock-all.cc +@SYSTEM_TEST_LIBS_FALSE@am_src_testing_libtesting_a_OBJECTS = src/testing/googletest/src/libtesting_a-gtest-all.$(OBJEXT) \ +@SYSTEM_TEST_LIBS_FALSE@ src/testing/googletest/src/libtesting_a-gtest_main.$(OBJEXT) \ +@SYSTEM_TEST_LIBS_FALSE@ src/testing/googlemock/src/libtesting_a-gmock-all.$(OBJEXT) src_testing_libtesting_a_OBJECTS = \ $(am_src_testing_libtesting_a_OBJECTS) src_third_party_libdisasm_libdisasm_a_AR = $(AR) $(ARFLAGS) @@ -536,7 +703,9 @@ am__src_client_linux_linux_client_unittest_shlib_SOURCES_DIST = \ 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 \ @@ -549,13 +718,13 @@ 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 -am__objects_2 = src/testing/googletest/src/client_linux_linux_client_unittest_shlib-gtest-all.$(OBJEXT) \ - src/testing/googletest/src/client_linux_linux_client_unittest_shlib-gtest_main.$(OBJEXT) \ - src/testing/googlemock/src/client_linux_linux_client_unittest_shlib-gmock-all.$(OBJEXT) -@HAVE_GETCONTEXT_FALSE@am__objects_3 = src/common/linux/client_linux_linux_client_unittest_shlib-breakpad_getcontext.$(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@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_2) \ + $(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) \ @@ -570,6 +739,8 @@ am_src_client_linux_linux_client_unittest_shlib_OBJECTS = \ 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) \ @@ -581,7 +752,7 @@ am_src_client_linux_linux_client_unittest_shlib_OBJECTS = \ 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_3) + $(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) \ @@ -673,6 +844,18 @@ src_common_linux_google_crashdump_uploader_test_OBJECTS = \ 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) \ @@ -747,6 +930,8 @@ am_src_processor_disassembler_objdump_unittest_OBJECTS = src/processor/disassemb 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 \ @@ -765,9 +950,7 @@ src_processor_exploitability_unittest_OBJECTS = \ 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_objdump.o \ - src/processor/disassembler_x86.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 \ @@ -797,7 +980,7 @@ src_processor_exploitability_unittest_DEPENDENCIES = \ 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__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) src_processor_fast_source_line_resolver_unittest_DEPENDENCIES = \ @@ -845,7 +1028,7 @@ src_processor_microdump_processor_unittest_DEPENDENCIES = \ src/processor/stackwalker_sparc.o \ src/processor/stackwalker_x86.o src/processor/tokenize.o \ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ - $(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 = \ @@ -877,7 +1060,7 @@ src_processor_microdump_stackwalk_DEPENDENCIES = \ 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 + 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 = \ @@ -897,7 +1080,6 @@ src_processor_minidump_processor_unittest_DEPENDENCIES = \ 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_objdump.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 \ @@ -923,7 +1105,7 @@ src_processor_minidump_processor_unittest_DEPENDENCIES = \ 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__DEPENDENCIES_1) $(am__append_29) am_src_processor_minidump_stackwalk_OBJECTS = \ src/processor/minidump_stackwalk.$(OBJEXT) src_processor_minidump_stackwalk_OBJECTS = \ @@ -933,7 +1115,6 @@ src_processor_minidump_stackwalk_DEPENDENCIES = \ 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_objdump.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 \ @@ -958,7 +1139,8 @@ src_processor_minidump_stackwalk_DEPENDENCIES = \ 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 + 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) @@ -1078,9 +1260,7 @@ src_processor_stackwalker_selftest_OBJECTS = \ 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_objdump.o \ - src/processor/disassembler_x86.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 \ @@ -1101,7 +1281,7 @@ src_processor_stackwalker_selftest_DEPENDENCIES = \ 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__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 = \ @@ -1390,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 \ @@ -1419,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 \ @@ -1613,6 +1799,8 @@ 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) \ @@ -1663,8 +1851,8 @@ SOURCES = $(src_client_linux_libbreakpad_client_a_SOURCES) \ $(src_tools_mac_dump_syms_dump_syms_mac_SOURCES) DIST_SOURCES = \ $(am__src_client_linux_libbreakpad_client_a_SOURCES_DIST) \ - $(src_libbreakpad_a_SOURCES) \ - $(src_testing_libtesting_a_SOURCES) \ + $(am__src_libbreakpad_a_SOURCES_DIST) \ + $(am__src_testing_libtesting_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) \ @@ -1673,6 +1861,8 @@ DIST_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) \ @@ -2128,7 +2318,7 @@ 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_12) +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 \ @@ -2152,17 +2342,17 @@ pkgconfig_DATA = $(am__append_6) $(am__append_12) @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_11) +lib_LIBRARIES = $(am__append_5) $(am__append_12) noinst_SCRIPTS = $(check_SCRIPTS) -CLEANFILES = $(am__append_15) -src_testing_libtesting_a_SOURCES = \ - src/breakpad_googletest_includes.h \ - src/testing/googletest/src/gtest-all.cc \ - src/testing/googletest/src/gtest_main.cc \ - src/testing/googlemock/src/gmock-all.cc +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 -src_testing_libtesting_a_CPPFLAGS = \ - $(AM_CPPFLAGS) $(TEST_CFLAGS) +@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 \ @@ -2192,7 +2382,7 @@ src_common_safe_math_unittest_LDADD = \ # Breakpad processor library -src_libbreakpad_a_SOURCES = \ +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 \ @@ -2220,26 +2410,21 @@ src_libbreakpad_a_SOURCES = \ 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/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/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_objdump.h \ - src/processor/disassembler_objdump.cc \ src/processor/disassembler_x86.h \ src/processor/disassembler_x86.cc \ - src/processor/dump_context.cc \ - src/processor/dump_object.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 \ @@ -2247,18 +2432,13 @@ src_libbreakpad_a_SOURCES = \ 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/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_comparer.h src/processor/module_factory.h \ src/processor/module_serializer.cc \ src/processor/module_serializer.h \ src/processor/pathname_stripper.cc \ @@ -2266,8 +2446,7 @@ src_libbreakpad_a_SOURCES = \ 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/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 \ @@ -2279,8 +2458,7 @@ src_libbreakpad_a_SOURCES = \ 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/stackwalk_common.h src/processor/stackwalker.cc \ src/processor/stackwalker_amd64.cc \ src/processor/stackwalker_amd64.h \ src/processor/stackwalker_arm.cc \ @@ -2309,15 +2487,13 @@ src_libbreakpad_a_SOURCES = \ 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_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 - + src/processor/tokenize.cc src/processor/tokenize.h \ + $(am__append_22) # libdisasm 3rd party library src_third_party_libdisasm_libdisasm_a_SOURCES = \ @@ -2378,7 +2554,7 @@ src_client_linux_libbreakpad_client_a_SOURCES = \ 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_21) + src/common/linux/safe_readlink.cc $(am__append_23) # Client tests src_client_linux_linux_dumper_unittest_helper_SOURCES = \ @@ -2406,7 +2582,9 @@ src_client_linux_linux_client_unittest_shlib_SOURCES = \ 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 \ @@ -2416,12 +2594,12 @@ src_client_linux_linux_client_unittest_shlib_SOURCES = \ 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_22) + 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_23) + -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 \ @@ -2457,7 +2635,7 @@ src_client_linux_linux_client_unittest_SOURCES = src_client_linux_linux_client_unittest_LDFLAGS = \ -Wl,-rpath,'$$ORIGIN' \ -Wl,--build-id=0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \ - $(am__append_24) + $(am__append_26) src_client_linux_linux_client_unittest_LDADD = \ src/client/linux/linux_client_unittest_shlib \ $(TEST_LIBS) @@ -2761,23 +2939,18 @@ src_processor_exploitability_unittest_SOURCES = \ src_processor_exploitability_unittest_CPPFLAGS = \ $(AM_CPPFLAGS) $(TEST_CFLAGS) -src_processor_exploitability_unittest_LDADD = \ +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_objdump.o \ - src/processor/disassembler_x86.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/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 \ @@ -2797,8 +2970,28 @@ src_processor_exploitability_unittest_LDADD = \ 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 \ + 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) @@ -2809,6 +3002,8 @@ 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 \ @@ -2866,17 +3061,14 @@ src_processor_microdump_processor_unittest_SOURCES = \ src_processor_microdump_processor_unittest_CPPFLAGS = \ $(AM_CPPFLAGS) $(TEST_CFLAGS) -src_processor_microdump_processor_unittest_LDADD = \ +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/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 \ @@ -2893,36 +3085,27 @@ src_processor_microdump_processor_unittest_LDADD = \ 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) - + 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_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/call_stack.o src/processor/cfi_frame_info.o \ src/processor/convert_old_arm64_context.o \ - src/processor/disassembler_objdump.o \ - src/processor/disassembler_x86.o \ - src/processor/dump_context.o \ - src/processor/dump_object.o \ - src/processor/exploitability.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/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/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 \ @@ -2939,11 +3122,9 @@ src_processor_minidump_processor_unittest_LDADD = \ 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) - + 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 \ @@ -3076,18 +3257,14 @@ src_processor_range_map_unittest_LDADD = \ src_processor_stackwalker_selftest_SOURCES = \ src/processor/stackwalker_selftest.cc -src_processor_stackwalker_selftest_LDADD = \ +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_objdump.o \ - src/processor/disassembler_x86.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/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 \ @@ -3103,10 +3280,8 @@ src_processor_stackwalker_selftest_LDADD = \ 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) - + 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 @@ -3286,27 +3461,22 @@ src_processor_minidump_dump_LDADD = \ src_processor_microdump_stackwalk_SOURCES = \ src/processor/microdump_stackwalk.cc -src_processor_microdump_stackwalk_LDADD = \ - src/common/path_helper.o \ +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/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/stackwalk_common.o src/processor/stackwalker.o \ src/processor/stackwalker_address_list.o \ src/processor/stackwalker_amd64.o \ src/processor/stackwalker_arm.o \ @@ -3317,39 +3487,28 @@ src_processor_microdump_stackwalk_LDADD = \ 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 - + 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_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/call_stack.o src/processor/cfi_frame_info.o \ src/processor/convert_old_arm64_context.o \ - src/processor/disassembler_objdump.o \ - src/processor/disassembler_x86.o \ - src/processor/dump_context.o \ - src/processor/dump_object.o \ - src/processor/exploitability.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/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/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/stackwalk_common.o src/processor/stackwalker.o \ src/processor/stackwalker_address_list.o \ src/processor/stackwalker_amd64.o \ src/processor/stackwalker_arm.o \ @@ -3362,9 +3521,8 @@ src_processor_minidump_stackwalk_LDADD = \ 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 - + src/processor/tokenize.o src/third_party/libdisasm/libdisasm.a \ + $(am__append_32) EXTRA_DIST = \ $(SCRIPTS) \ src/client/linux/data/linux-gate-amd.sym \ @@ -3961,9 +4119,6 @@ src/processor/cfi_frame_info.$(OBJEXT): src/processor/$(am__dirstamp) \ src/processor/convert_old_arm64_context.$(OBJEXT): \ src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) -src/processor/disassembler_objdump.$(OBJEXT): \ - src/processor/$(am__dirstamp) \ - src/processor/$(DEPDIR)/$(am__dirstamp) src/processor/disassembler_x86.$(OBJEXT): \ src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) @@ -4063,6 +4218,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) @@ -4208,6 +4372,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) @@ -4454,6 +4624,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) @@ -5244,6 +5428,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 @@ -5273,6 +5459,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 @@ -5769,6 +5959,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 @@ -6707,6 +6925,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 @@ -8762,13 +9008,6 @@ src/processor/contained_range_map_unittest.log: src/processor/contained_range_ma --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/processor/disassembler_x86_unittest.log: src/processor/disassembler_x86_unittest$(EXEEXT) @p='src/processor/disassembler_x86_unittest$(EXEEXT)'; \ b='src/processor/disassembler_x86_unittest'; \ @@ -8958,6 +9197,27 @@ 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'; \ @@ -9450,6 +9710,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 @@ -9479,6 +9741,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 @@ -9804,6 +10070,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 @@ -9833,6 +10101,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 diff --git a/thirdparty/sentry-native/external/breakpad/configure b/thirdparty/sentry-native/external/breakpad/configure index d131f5a91a..76d4a9f61e 100644 --- a/thirdparty/sentry-native/external/breakpad/configure +++ b/thirdparty/sentry-native/external/breakpad/configure @@ -7748,10 +7748,1647 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_success=no + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++17 features by default" >&5 +printf %s "checking whether $CXX supports C++17 features by default... " >&6; } +if test ${ax_cv_cxx_compile_cxx17+y} +then : + printf %s "(cached) " >&6 +else $as_nop + 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 + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO" +then : + ax_cv_cxx_compile_cxx17=yes +else $as_nop + ax_cv_cxx_compile_cxx17=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_cxx17" >&5 +printf "%s\n" "$ax_cv_cxx_compile_cxx17" >&6; } + if test x$ax_cv_cxx_compile_cxx17 = 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_cxx17_$switch" | $as_tr_sh` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++17 features with $switch" >&5 +printf %s "checking whether $CXX supports C++17 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 + + + +_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 diff --git a/thirdparty/sentry-native/external/breakpad/configure.ac b/thirdparty/sentry-native/external/breakpad/configure.ac index 69e23545f9..ca2936695c 100644 --- a/thirdparty/sentry-native/external/breakpad/configure.ac +++ b/thirdparty/sentry-native/external/breakpad/configure.ac @@ -75,7 +75,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(17, noext, mandatory) +AX_CXX_COMPILE_STDCXX(17, , mandatory) dnl Test supported warning flags. WARN_CXXFLAGS= diff --git a/thirdparty/sentry-native/external/breakpad/src/client/linux/minidump_writer/cpu_set_unittest.cc b/thirdparty/sentry-native/external/breakpad/src/client/linux/minidump_writer/cpu_set_unittest.cc index 1db74410d0..e9d4e87ac8 100644 --- a/thirdparty/sentry-native/external/breakpad/src/client/linux/minidump_writer/cpu_set_unittest.cc +++ b/thirdparty/sentry-native/external/breakpad/src/client/linux/minidump_writer/cpu_set_unittest.cc @@ -35,7 +35,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; @@ -43,15 +43,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) { @@ -60,8 +51,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())); @@ -69,8 +60,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())); @@ -78,8 +69,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())); @@ -87,8 +78,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())); @@ -96,8 +87,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())); @@ -105,8 +96,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())); @@ -114,14 +105,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()); @@ -132,8 +125,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()); @@ -143,14 +137,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/thirdparty/sentry-native/external/breakpad/src/client/linux/minidump_writer/line_reader_unittest.cc b/thirdparty/sentry-native/external/breakpad/src/client/linux/minidump_writer/line_reader_unittest.cc index 3062c39f78..b96ebf9d0b 100644 --- a/thirdparty/sentry-native/external/breakpad/src/client/linux/minidump_writer/line_reader_unittest.cc +++ b/thirdparty/sentry-native/external/breakpad/src/client/linux/minidump_writer/line_reader_unittest.cc @@ -32,7 +32,7 @@ #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; @@ -40,22 +40,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; @@ -64,8 +53,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; @@ -80,8 +69,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; @@ -96,8 +85,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; @@ -118,8 +107,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; @@ -142,8 +131,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; @@ -158,8 +147,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/thirdparty/sentry-native/external/breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc b/thirdparty/sentry-native/external/breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc index f6d3e28590..cbdc5fbcef 100644 --- a/thirdparty/sentry-native/external/breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc +++ b/thirdparty/sentry-native/external/breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc @@ -35,33 +35,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; @@ -69,8 +55,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; @@ -82,8 +68,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; @@ -97,8 +83,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; @@ -114,8 +100,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; @@ -127,8 +113,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; @@ -140,8 +126,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; @@ -153,8 +139,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; @@ -170,8 +156,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; @@ -183,8 +169,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/thirdparty/sentry-native/external/breakpad/src/common/dwarf/elf_reader.cc b/thirdparty/sentry-native/external/breakpad/src/common/dwarf/elf_reader.cc index 5fd1cfb966..7664377cb9 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/dwarf/elf_reader.cc +++ b/thirdparty/sentry-native/external/breakpad/src/common/dwarf/elf_reader.cc @@ -39,9 +39,9 @@ #include #include -#include #include #include +#include #include // TODO(saugustine): Add support for compressed debug. // Also need to add configure tests for zlib. @@ -107,6 +107,12 @@ 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 google_breakpad { @@ -215,7 +221,7 @@ class ElfSectionReader { (header_.sh_offset - offset_aligned); // Check for and handle any compressed contents. - //if (name == ".zdebug_") + //if (StringViewStartsWith(name, ".zdebug_")) // DecompressZlibContents(); // TODO(saugustine): Add support for proposed elf-section flag // "SHF_COMPRESS". @@ -359,8 +365,8 @@ class ElfReaderImpl { // "opd_section_" must always be checked for NULL before use. opd_section_ = GetSectionInfoByName(".opd", &opd_info_); for (unsigned int k = 0u; k < GetNumSections(); ++k) { - const char* name = GetSectionName(section_headers_[k].sh_name); - if (strncmp(name, ".text", strlen(".text")) == 0) { + std::string_view name{GetSectionName(section_headers_[k].sh_name)}; + if (StringViewStartsWith(name, ".text")) { base_for_text_ = section_headers_[k].sh_addr - section_headers_[k].sh_offset; break; @@ -809,9 +815,11 @@ class ElfReaderImpl { // Debug sections are likely to be near the end, so reverse the // direction of iteration. for (int k = GetNumSections() - 1; k >= 0; --k) { - const char* name = GetSectionName(section_headers_[k].sh_name); - if (strncmp(name, ".debug", strlen(".debug")) == 0) return true; - if (strncmp(name, ".zdebug", strlen(".zdebug")) == 0) return true; + std::string_view name{GetSectionName(section_headers_[k].sh_name)}; + if (StringViewStartsWith(name, ".debug") || + StringViewStartsWith(name, ".zdebug")) { + return true; + } } return false; } @@ -1213,11 +1221,15 @@ const char* ElfReader::GetSectionInfoByName(const string& section_name, } } -bool ElfReader::SectionNamesMatch(const string& name, const string& sh_name) { - if ((name.find(".debug_", 0) == 0) && (sh_name.find(".zdebug_", 0) == 0)) { - const string name_suffix(name, strlen(".debug_")); - const string sh_name_suffix(sh_name, strlen(".zdebug_")); - return name_suffix == sh_name_suffix; +bool ElfReader::SectionNamesMatch(std::string_view name, + std::string_view sh_name) { + std::string_view debug_prefix{".debug_"}; + std::string_view zdebug_prefix{".zdebug_"}; + if (StringViewStartsWith(name, debug_prefix) && + StringViewStartsWith(sh_name, zdebug_prefix)) { + name.remove_prefix(debug_prefix.length()); + sh_name.remove_prefix(zdebug_prefix.length()); + return name == sh_name; } return name == sh_name; } diff --git a/thirdparty/sentry-native/external/breakpad/src/common/dwarf/elf_reader.h b/thirdparty/sentry-native/external/breakpad/src/common/dwarf/elf_reader.h index 672969d81c..a6dec75556 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/dwarf/elf_reader.h +++ b/thirdparty/sentry-native/external/breakpad/src/common/dwarf/elf_reader.h @@ -16,6 +16,7 @@ #define COMMON_DWARF_ELF_READER_H__ #include +#include #include #include "common/dwarf/types.h" @@ -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. diff --git a/thirdparty/sentry-native/external/breakpad/src/common/dwarf_cfi_to_module.cc b/thirdparty/sentry-native/external/breakpad/src/common/dwarf_cfi_to_module.cc index e7e595e76e..7da8507d7e 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/dwarf_cfi_to_module.cc +++ b/thirdparty/sentry-native/external/breakpad/src/common/dwarf_cfi_to_module.cc @@ -33,7 +33,9 @@ // Implementation of google_breakpad::DwarfCFIToModule. // See dwarf_cfi_to_module.h for details. +#include #include +#include #include "common/dwarf_cfi_to_module.h" @@ -151,7 +153,7 @@ bool DwarfCFIToModule::Entry(size_t offset, uint64_t address, uint64_t length, // 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; @@ -258,8 +260,7 @@ bool DwarfCFIToModule::ValExpressionRule(uint64_t address, int reg, } bool DwarfCFIToModule::End() { - module_->AddStackFrameEntry(entry_); - entry_ = NULL; + module_->AddStackFrameEntry(std::move(entry_)); return true; } diff --git a/thirdparty/sentry-native/external/breakpad/src/common/dwarf_cfi_to_module.h b/thirdparty/sentry-native/external/breakpad/src/common/dwarf_cfi_to_module.h index 3b092654df..42b618d5bd 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/dwarf_cfi_to_module.h +++ b/thirdparty/sentry-native/external/breakpad/src/common/dwarf_cfi_to_module.h @@ -43,6 +43,7 @@ #include #include +#include #include #include "common/module.h" @@ -131,9 +132,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, @@ -170,7 +171,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/thirdparty/sentry-native/external/breakpad/src/common/linux/dump_symbols.cc b/thirdparty/sentry-native/external/breakpad/src/common/linux/dump_symbols.cc index 4915e6ffc8..b436f76530 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/linux/dump_symbols.cc +++ b/thirdparty/sentry-native/external/breakpad/src/common/linux/dump_symbols.cc @@ -495,9 +495,42 @@ bool LoadDwarfCFI(const string& dwarf_filename, google_breakpad::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename, section_name); - google_breakpad::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(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; } diff --git a/thirdparty/sentry-native/external/breakpad/src/common/linux/elf_symbols_to_module.cc b/thirdparty/sentry-native/external/breakpad/src/common/linux/elf_symbols_to_module.cc index 4aee38d6a8..3c33be99a5 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/linux/elf_symbols_to_module.cc +++ b/thirdparty/sentry-native/external/breakpad/src/common/linux/elf_symbols_to_module.cc @@ -36,6 +36,9 @@ #include #include +#include +#include + #include "common/byte_cursor.h" #include "common/module.h" @@ -156,7 +159,7 @@ bool ELFSymbolsToModule(const uint8_t* symtab_section, while(!iterator->at_end) { if (ELF32_ST_TYPE(iterator->info) == STT_FUNC && iterator->shndx != SHN_UNDEF) { - Module::Extern* ext = new Module::Extern(iterator->value); + auto ext = std::make_unique(iterator->value); ext->name = SymbolString(iterator->name_offset, strings); #if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle. int status = 0; @@ -168,7 +171,7 @@ bool ELFSymbolsToModule(const uint8_t* symtab_section, free(demangled); } #endif - module->AddExtern(ext); + module->AddExtern(std::move(ext)); } ++iterator; } diff --git a/thirdparty/sentry-native/external/breakpad/src/common/linux/libcurl_wrapper.cc b/thirdparty/sentry-native/external/breakpad/src/common/linux/libcurl_wrapper.cc index 096681614d..a53087d9c3 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/linux/libcurl_wrapper.cc +++ b/thirdparty/sentry-native/external/breakpad/src/common/linux/libcurl_wrapper.cc @@ -47,6 +47,7 @@ LibcurlWrapper::LibcurlWrapper() LibcurlWrapper::~LibcurlWrapper() { if (init_ok_) { (*easy_cleanup_)(curl_); + (*global_cleanup_)(); dlclose(curl_lib_); } } @@ -262,6 +263,10 @@ bool LibcurlWrapper::SetFunctionPointers() { SET_AND_CHECK_FUNCTION_POINTER(formfree_, "curl_formfree", void(*)(curl_httppost*)); + + SET_AND_CHECK_FUNCTION_POINTER(global_cleanup_, + "curl_global_cleanup", + void(*)(void)); return true; } diff --git a/thirdparty/sentry-native/external/breakpad/src/common/linux/libcurl_wrapper.h b/thirdparty/sentry-native/external/breakpad/src/common/linux/libcurl_wrapper.h index f4a4dca40c..f8f961c1bf 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/linux/libcurl_wrapper.h +++ b/thirdparty/sentry-native/external/breakpad/src/common/linux/libcurl_wrapper.h @@ -39,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(); @@ -111,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/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_pipe.cc b/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_pipe.cc new file mode 100644 index 0000000000..b13f8d459c --- /dev/null +++ b/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_pipe.cc @@ -0,0 +1,128 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "common/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/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_pipe.h b/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_pipe.h new file mode 100644 index 0000000000..25394c2aba --- /dev/null +++ b/thirdparty/sentry-native/external/breakpad/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/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_pipe_unittest.cc b/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_pipe_unittest.cc new file mode 100644 index 0000000000..a7d6272cff --- /dev/null +++ b/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_pipe_unittest.cc @@ -0,0 +1,71 @@ +// 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. + +#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/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_tmpfile.cc b/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_tmpfile.cc new file mode 100644 index 0000000000..229e8d42cd --- /dev/null +++ b/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_tmpfile.cc @@ -0,0 +1,99 @@ +// 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. + +#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/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_tmpfile.h b/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_tmpfile.h new file mode 100644 index 0000000000..dffec182fb --- /dev/null +++ b/thirdparty/sentry-native/external/breakpad/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/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_tmpfile_unittest.cc b/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_tmpfile_unittest.cc new file mode 100644 index 0000000000..f82c5998b1 --- /dev/null +++ b/thirdparty/sentry-native/external/breakpad/src/common/linux/scoped_tmpfile_unittest.cc @@ -0,0 +1,46 @@ +// 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. + +#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/thirdparty/sentry-native/external/breakpad/src/common/linux/tests/auto_testfile.h b/thirdparty/sentry-native/external/breakpad/src/common/linux/tests/auto_testfile.h deleted file mode 100644 index e2d2ff23bc..0000000000 --- a/thirdparty/sentry-native/external/breakpad/src/common/linux/tests/auto_testfile.h +++ /dev/null @@ -1,123 +0,0 @@ -// 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. - -// 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/thirdparty/sentry-native/external/breakpad/src/common/mac/dump_syms.cc b/thirdparty/sentry-native/external/breakpad/src/common/mac/dump_syms.cc index 1f83031282..9658b2c6dc 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/mac/dump_syms.cc +++ b/thirdparty/sentry-native/external/breakpad/src/common/mac/dump_syms.cc @@ -268,7 +268,8 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( return &object_files_[i]; } assert(best_match == NULL); - return NULL; + // Fall through since NXFindBestFatArch can't find arm slices on x86_64 + // macOS 13. See FB11955188. } // Check for an exact match with cpu_type and cpu_subtype. @@ -276,7 +277,8 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( it != object_files_.end(); ++it) { if (static_cast(it->cputype) == cpu_type && - static_cast(it->cpusubtype) == cpu_subtype) + (static_cast(it->cpusubtype) & ~CPU_SUBTYPE_MASK) == + (cpu_subtype & ~CPU_SUBTYPE_MASK)) return &*it; } @@ -285,8 +287,11 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( // NXFindBestFatArch, located at // http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c. fprintf(stderr, "Failed to find an exact match for an object file with cpu " - "type: %d and cpu subtype: %d. Furthermore, at least one object file is " - "larger than 2**32.\n", cpu_type, cpu_subtype); + "type: %d and cpu subtype: %d.\n", cpu_type, cpu_subtype); + if (!can_convert_to_fat_arch) { + fprintf(stderr, "Furthermore, at least one object file is larger " + "than 2**32.\n"); + } return NULL; } @@ -678,18 +683,6 @@ 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. diff --git a/thirdparty/sentry-native/external/breakpad/src/common/mac/dump_syms.h b/thirdparty/sentry-native/external/breakpad/src/common/mac/dump_syms.h index 97632ce02f..c2e1b40b91 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/mac/dump_syms.h +++ b/thirdparty/sentry-native/external/breakpad/src/common/mac/dump_syms.h @@ -117,19 +117,14 @@ class DumpSymbols { return NULL; } - // Read the selected object file's debugging information, and write it out to - // |stream|. Return true on success; if an error occurs, report it and - // return false. - bool WriteSymbolFile(std::ostream& stream); - // Read the selected object file's debugging information, and write out the // header only to |stream|. Return true on success; if an error occurs, report // it and return false. bool WriteSymbolFileHeader(std::ostream& stream); - // 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. diff --git a/thirdparty/sentry-native/external/breakpad/src/common/module.cc b/thirdparty/sentry-native/external/breakpad/src/common/module.cc index 442b910dc3..75782ab163 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/module.cc +++ b/thirdparty/sentry-native/external/breakpad/src/common/module.cc @@ -117,12 +117,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) { @@ -155,12 +149,11 @@ bool Module::AddFunction(Function* function) { } if (it_ext != externs_.end()) { if (enable_multiple_field_) { - Extern* found_ext = *it_ext; + Extern* found_ext = it_ext->get(); // If the PUBLIC is for the same symbol as the FUNC, don't mark multiple. function->is_multiple |= found_ext->name != function->name || found_ext->is_multiple; } - delete *it_ext; externs_.erase(it_ext); } #if _DEBUG @@ -194,25 +187,22 @@ bool Module::AddFunction(Function* function) { return true; } -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); + std::pair ret = externs_.emplace(std::move(ext)); if (!ret.second && enable_multiple_field_) { (*ret.first)->is_multiple = true; - // Free the duplicate that was not inserted because this Module - // now owns it. - delete ext; } } @@ -223,7 +213,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) { @@ -265,7 +259,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( @@ -441,7 +439,7 @@ 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; + Extern* ext = extern_it->get(); stream << "PUBLIC " << (ext->is_multiple ? "m " : "") << hex << (ext->address - load_address_) << " 0 " << ext->name << dec << "\n"; @@ -450,10 +448,9 @@ bool Module::Write(std::ostream& stream, SymbolData symbol_data) { 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->size << " " << dec; diff --git a/thirdparty/sentry-native/external/breakpad/src/common/module.h b/thirdparty/sentry-native/external/breakpad/src/common/module.h index a8fcc81e0c..c1fd9f59ca 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/module.h +++ b/thirdparty/sentry-native/external/breakpad/src/common/module.h @@ -292,7 +292,18 @@ class Module { }; 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; } }; @@ -340,12 +351,12 @@ class Module { // 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 @@ -465,7 +476,7 @@ 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 @@ -477,7 +488,7 @@ class Module { // 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. diff --git a/thirdparty/sentry-native/external/breakpad/src/common/module_unittest.cc b/thirdparty/sentry-native/external/breakpad/src/common/module_unittest.cc index 220add0307..39727554fc 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/module_unittest.cc +++ b/thirdparty/sentry-native/external/breakpad/src/common/module_unittest.cc @@ -36,8 +36,10 @@ #include #include +#include #include #include +#include #include "breakpad_googletest_includes.h" #include "common/module.h" @@ -137,7 +139,7 @@ TEST(Module, WriteRelativeLoadAddress) { 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 +147,7 @@ TEST(Module, WriteRelativeLoadAddress) { 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. @@ -242,7 +244,7 @@ TEST(Module, WriteNoCFI) { 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"; @@ -250,7 +252,7 @@ TEST(Module, WriteNoCFI) { 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. @@ -321,18 +323,18 @@ TEST(Module, WriteOutOfRangeAddresses) { // 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(); + auto entry1 = std::make_unique(); entry1->address = 0x1000ULL; entry1->size = 0x100ULL; - m.AddStackFrameEntry(entry1); - Module::StackFrameEntry* entry2 = new Module::StackFrameEntry(); + m.AddStackFrameEntry(std::move(entry1)); + auto entry2 = std::make_unique(); entry2->address = 0x2000ULL; entry2->size = 0x100ULL; - m.AddStackFrameEntry(entry2); - Module::StackFrameEntry* entry3 = new Module::StackFrameEntry(); + m.AddStackFrameEntry(std::move(entry2)); + auto entry3 = std::make_unique(); entry3->address = 0x3000ULL; entry3->size = 0x100ULL; - m.AddStackFrameEntry(entry3); + m.AddStackFrameEntry(std::move(entry3)); // Add a function outside the allowed range. Module::File* file = m.FindFile("file_name.cc"); @@ -346,9 +348,9 @@ TEST(Module, WriteOutOfRangeAddresses) { m.AddFunction(function); // Add an extern outside the allowed range. - Module::Extern* extern1 = new Module::Extern(0x5000ULL); + auto extern1 = std::make_unique(0x5000ULL); extern1->name = "_xyz"; - m.AddExtern(extern1); + m.AddExtern(std::move(extern1)); m.Write(s, ALL_SYMBOL_DATA); @@ -357,10 +359,7 @@ TEST(Module, WriteOutOfRangeAddresses) { s.str().c_str()); // Cleanup - Prevent Memory Leak errors. - delete (extern1); delete (function); - delete (entry3); - delete (entry1); } TEST(Module, ConstructAddFrames) { @@ -368,22 +367,22 @@ TEST(Module, ConstructAddFrames) { 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"; @@ -395,7 +394,7 @@ TEST(Module, ConstructAddFrames) { "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); @@ -541,13 +540,13 @@ TEST(Module, ConstructExterns) { 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(); @@ -566,13 +565,13 @@ TEST(Module, ConstructDuplicateExterns) { 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(); @@ -589,13 +588,13 @@ TEST(Module, ConstructDuplicateExternsMultiple) { Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", true); // 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(); @@ -613,13 +612,13 @@ TEST(Module, ConstructFunctionsAndExternsWithSameAddress) { 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); @@ -644,13 +643,13 @@ TEST(Module, ConstructFunctionsAndExternsWithSameAddressMultiple) { Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", true); // 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); @@ -676,17 +675,17 @@ TEST(Module, ConstructFunctionsAndThumbExternsWithSameAddress) { 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. diff --git a/thirdparty/sentry-native/external/breakpad/src/common/stabs_to_module.cc b/thirdparty/sentry-native/external/breakpad/src/common/stabs_to_module.cc index 6cdb96a27b..3d026c22c3 100644 --- a/thirdparty/sentry-native/external/breakpad/src/common/stabs_to_module.cc +++ b/thirdparty/sentry-native/external/breakpad/src/common/stabs_to_module.cc @@ -36,6 +36,8 @@ #include #include +#include +#include #include "common/stabs_to_module.h" #include "common/using_std_string.h" @@ -132,7 +134,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 +144,7 @@ bool StabsToModule::Extern(const string& name, uint64_t address) { } else { ext->name = name; } - module_->AddExtern(ext); + module_->AddExtern(std::move(ext)); return true; } diff --git a/thirdparty/sentry-native/external/breakpad/src/google_breakpad/common/minidump_exception_mac.h b/thirdparty/sentry-native/external/breakpad/src/google_breakpad/common/minidump_exception_mac.h index feb47079f5..acfafaa0f8 100644 --- a/thirdparty/sentry-native/external/breakpad/src/google_breakpad/common/minidump_exception_mac.h +++ b/thirdparty/sentry-native/external/breakpad/src/google_breakpad/common/minidump_exception_mac.h @@ -65,6 +65,10 @@ 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, /* Fake exception code used by Crashpad's SimulateCrash ('CPsx'). */ diff --git a/thirdparty/sentry-native/external/breakpad/src/google_breakpad/common/minidump_format.h b/thirdparty/sentry-native/external/breakpad/src/google_breakpad/common/minidump_format.h index 9edead9343..1526afcea3 100644 --- a/thirdparty/sentry-native/external/breakpad/src/google_breakpad/common/minidump_format.h +++ b/thirdparty/sentry-native/external/breakpad/src/google_breakpad/common/minidump_format.h @@ -1096,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; + MDLocationDescriptor objects[0]; /* MDRawCrashpadAnnotation */ +} MDRawCrashpadAnnotationList; + typedef struct { uint32_t version; MDLocationDescriptor list_annotations; MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */ + MDLocationDescriptor annotation_objects; /* MDRawCrashpadAnnotationList */ } MDRawModuleCrashpadInfo; typedef struct { @@ -1118,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/thirdparty/sentry-native/external/breakpad/src/google_breakpad/processor/minidump.h b/thirdparty/sentry-native/external/breakpad/src/google_breakpad/processor/minidump.h index 54d2881762..934a0e3ef1 100644 --- a/thirdparty/sentry-native/external/breakpad/src/google_breakpad/processor/minidump.h +++ b/thirdparty/sentry-native/external/breakpad/src/google_breakpad/processor/minidump.h @@ -1189,10 +1189,21 @@ class MinidumpLinuxMapsList : public MinidumpStream { // at the time the minidump was generated. class MinidumpCrashpadInfo : public MinidumpStream { public: + struct AnnotationObject { + uint16_t type; + std::string name; + std::vector value; + }; + const MDRawCrashpadInfo* crashpad_info() const { return valid_ ? &crashpad_info_ : NULL; } + const std::vector>* + GetModuleCrashpadInfoAnnotationObjects() const { + return valid_ ? &module_crashpad_info_annotation_objects_ : NULL; + } + // Print a human-readable representation of the object to stdout. void Print(); @@ -1211,6 +1222,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_; }; @@ -1320,6 +1334,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 diff --git a/thirdparty/sentry-native/external/crashpad/BUILD.gn b/thirdparty/sentry-native/external/crashpad/BUILD.gn index a2d92e62a5..db65cffc49 100644 --- a/thirdparty/sentry-native/external/crashpad/BUILD.gn +++ b/thirdparty/sentry-native/external/crashpad/BUILD.gn @@ -39,6 +39,8 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { if (crashpad_is_in_fuchsia) { # TODO(fuchsia:46559): Fix the leaks and remove this. deps += [ "//build/config/sanitizers:suppress-lsan.DO-NOT-USE-THIS" ] + # TODO(fxbug.dev/108368): Remove this once the underlying issue is addressed. + exclude_toolchain_tags = [ "hwasan" ] } if (crashpad_is_android) { use_raw_android_executable = true diff --git a/thirdparty/sentry-native/external/crashpad/CMakeLists.txt b/thirdparty/sentry-native/external/crashpad/CMakeLists.txt index f83ee5903d..cbb998436a 100644 --- a/thirdparty/sentry-native/external/crashpad/CMakeLists.txt +++ b/thirdparty/sentry-native/external/crashpad/CMakeLists.txt @@ -99,7 +99,7 @@ target_compile_definitions(crashpad_interface INTERFACE CRASHPAD_LSS_SOURCE_EMBEDDED ) -if(MSVC) +if(WIN32) target_compile_definitions(crashpad_interface INTERFACE NOMINMAX UNICODE @@ -108,6 +108,8 @@ if(MSVC) _HAS_EXCEPTIONS=0 _UNICODE ) +endif() +if(MSVC) string(REGEX REPLACE "/[Ww][0123]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") string(REGEX REPLACE "/[Ww][0123]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") target_compile_options(crashpad_interface INTERFACE @@ -135,6 +137,11 @@ elseif(MINGW) # redirect to wmain # FIXME: cmake 3.13 added target_link_options set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -municode") + if(CRASHPAD_WER_ENABLED) + message(STATUS "WER support enabled") + else() + message(STATUS "WER support disabled. Define CRASHPAD_WER_ENABLED = TRUE to enable.") + endif() endif() add_library(crashpad::interface ALIAS crashpad_interface) diff --git a/thirdparty/sentry-native/external/crashpad/DEPS b/thirdparty/sentry-native/external/crashpad/DEPS index 5580650b65..0ef3c1f4be 100644 --- a/thirdparty/sentry-native/external/crashpad/DEPS +++ b/thirdparty/sentry-native/external/crashpad/DEPS @@ -14,7 +14,7 @@ vars = { 'chromium_git': 'https://chromium.googlesource.com', - 'gn_version': 'git_revision:2ecd43a10266bd091c98e6dcde507c64f6a0dad3', + 'gn_version': 'git_revision:5e19d2fb166fbd4f6f32147fbb2f497091a54ad8', # ninja CIPD package version. # https://chrome-infra-packages.appspot.com/p/infra/3pp/tools/ninja 'ninja_version': 'version:2@1.8.2.chromium.3', diff --git a/thirdparty/sentry-native/external/crashpad/build/crashpad_buildconfig.gni b/thirdparty/sentry-native/external/crashpad/build/crashpad_buildconfig.gni index de5cba48f6..3de3f8db4e 100644 --- a/thirdparty/sentry-native/external/crashpad/build/crashpad_buildconfig.gni +++ b/thirdparty/sentry-native/external/crashpad/build/crashpad_buildconfig.gni @@ -37,7 +37,9 @@ crashpad_is_standalone = crashpad_dependencies == "standalone" # This is the parent directory that contains the mini_chromium source dir. # This variable is not used when crashpad_is_in_chromium. if (crashpad_is_in_fuchsia) { - mini_chromium_source_parent = "//third_party/crashpad/third_party/mini_chromium" + import("//third_party/crashpad/fuchsia_buildconfig.gni") + mini_chromium_source_parent = + fuchsia_crashpad_root + "/third_party/mini_chromium" } else { mini_chromium_source_parent = "../third_party/mini_chromium" } @@ -49,7 +51,7 @@ _mini_chromium_source_root = "$mini_chromium_source_parent/mini_chromium" if (crashpad_is_external || crashpad_is_in_dart) { mini_chromium_import_root = "../../../$_mini_chromium_source_root" } else if (crashpad_is_in_fuchsia) { - mini_chromium_import_root = "//third_party/mini_chromium" + mini_chromium_import_root = fuchsia_mini_chromium_root } else { mini_chromium_import_root = _mini_chromium_source_root } diff --git a/thirdparty/sentry-native/external/crashpad/build/run_tests.py b/thirdparty/sentry-native/external/crashpad/build/run_tests.py index 8ad19e346c..e03e06e78d 100644 --- a/thirdparty/sentry-native/external/crashpad/build/run_tests.py +++ b/thirdparty/sentry-native/external/crashpad/build/run_tests.py @@ -312,10 +312,10 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): _adb_shell(['rm', '-rf', device_temp_dir]) -def _RunOnIOSTarget(binary_dir, test, is_xcuitest=False): +def _RunOnIOSTarget(binary_dir, test, is_xcuitest=False, gtest_filter=None): """Runs the given iOS |test| app on iPhone 8 with the default OS version.""" - def xctest(binary_dir, test): + def xctest(binary_dir, test, gtest_filter=None): """Returns a dict containing the xctestrun data needed to run an XCTest-based test app.""" test_path = os.path.join(CRASHPAD_DIR, binary_dir) @@ -332,6 +332,8 @@ def _RunOnIOSTarget(binary_dir, test, is_xcuitest=False): 'XCInjectBundleInto': '__TESTHOST__/' + test, } } + if gtest_filter: + module_data['CommandLineArguments'] = ['--gtest_filter='+gtest_filter] return {test: module_data} def xcuitest(binary_dir, test): @@ -368,16 +370,18 @@ def _RunOnIOSTarget(binary_dir, test, is_xcuitest=False): xctestrun_path = f.name print(xctestrun_path) + command = [ + 'xcodebuild', 'test-without-building', '-xctestrun', xctestrun_path, + '-destination', 'platform=iOS Simulator,name=iPhone 8', + ] with open(xctestrun_path, 'wb') as fp: if is_xcuitest: plistlib.dump(xcuitest(binary_dir, test), fp) + if gtest_filter: + command.append('-only-testing:' + test + '/' + gtest_filter) else: - plistlib.dump(xctest(binary_dir, test), fp) - - subprocess.check_call([ - 'xcodebuild', 'test-without-building', '-xctestrun', xctestrun_path, - '-destination', 'platform=iOS Simulator,name=iPhone 8' - ]) + plistlib.dump(xctest(binary_dir, test, gtest_filter), fp) + subprocess.check_call(command) # This script is primarily used from the waterfall so that the list of tests @@ -468,7 +472,8 @@ def main(args): elif is_ios: _RunOnIOSTarget(args.binary_dir, test, - is_xcuitest=test.startswith('ios')) + is_xcuitest=test.startswith('ios'), + gtest_filter=args.gtest_filter) else: subprocess.check_call([os.path.join(args.binary_dir, test)] + extra_command_line) diff --git a/thirdparty/sentry-native/external/crashpad/client/BUILD.gn b/thirdparty/sentry-native/external/crashpad/client/BUILD.gn index 001a719cca..5c71dcc91a 100644 --- a/thirdparty/sentry-native/external/crashpad/client/BUILD.gn +++ b/thirdparty/sentry-native/external/crashpad/client/BUILD.gn @@ -119,6 +119,8 @@ static_library("common") { "crash_report_database.h", "crashpad_info.cc", "crashpad_info.h", + "length_delimited_ring_buffer.h", + "ring_buffer_annotation.h", "settings.cc", "settings.h", "simple_address_range_bag.h", @@ -147,6 +149,18 @@ static_library("common") { configs += [ "../build:flock_always_supported_defines" ] } +crashpad_executable("ring_buffer_annotation_load_test") { + testonly = true + sources = [ + "ring_buffer_annotation_load_test_main.cc", + ] + deps = [ + ":client", + "../tools:tool_support", + "$mini_chromium_source_parent:base", + ] +} + source_set("client_test") { testonly = true @@ -154,7 +168,9 @@ source_set("client_test") { "annotation_list_test.cc", "annotation_test.cc", "crash_report_database_test.cc", + "length_delimited_ring_buffer_test.cc", "prune_crash_reports_test.cc", + "ring_buffer_annotation_test.cc", "settings_test.cc", "simple_address_range_bag_test.cc", "simple_string_dictionary_test.cc", diff --git a/thirdparty/sentry-native/external/crashpad/client/CMakeLists.txt b/thirdparty/sentry-native/external/crashpad/client/CMakeLists.txt index 4b35a0f187..1ed52149c6 100644 --- a/thirdparty/sentry-native/external/crashpad/client/CMakeLists.txt +++ b/thirdparty/sentry-native/external/crashpad/client/CMakeLists.txt @@ -8,6 +8,8 @@ add_library(crashpad_client STATIC crashpad_client.h crashpad_info.cc crashpad_info.h + length_delimited_ring_buffer.h + ring_buffer_annotation.h prune_crash_reports.cc prune_crash_reports.h settings.cc diff --git a/thirdparty/sentry-native/external/crashpad/client/annotation.h b/thirdparty/sentry-native/external/crashpad/client/annotation.h index c4ab074d67..e80e76647a 100644 --- a/thirdparty/sentry-native/external/crashpad/client/annotation.h +++ b/thirdparty/sentry-native/external/crashpad/client/annotation.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -26,6 +27,7 @@ #include "base/numerics/safe_conversions.h" #include "base/strings/string_piece.h" #include "build/build_config.h" +#include "util/synchronization/scoped_spin_guard.h" namespace crashpad { #if BUILDFLAG(IS_IOS) @@ -94,6 +96,20 @@ class Annotation { kUserDefinedStart = 0x8000, }; + //! \brief Mode used to guard concurrent reads from writes. + enum class ConcurrentAccessGuardMode : bool { + //! \!brief Annotation does not guard reads from concurrent + //! writes. Annotation values can be corrupted if the process crashes + //! mid-write and the handler tries to read from the Annotation while + //! being written to. + kUnguarded = false, + + //! \!brief Annotation guards reads from concurrent writes using + //! ScopedSpinGuard. Clients must use TryCreateScopedSpinGuard() + //! before reading or writing the data in this Annotation. + kScopedSpinGuard = true, + }; + //! \brief Creates a user-defined Annotation::Type. //! //! This exists to remove the casting overhead of `enum class`. @@ -132,12 +148,11 @@ class Annotation { //! \param[in] value_ptr A pointer to the value for the annotation. The //! pointer may not be changed once associated with an annotation, but //! the data may be mutated. - constexpr Annotation(Type type, const char name[], void* const value_ptr) - : link_node_(nullptr), - name_(name), - value_ptr_(value_ptr), - size_(0), - type_(type) {} + constexpr Annotation(Type type, const char name[], void* value_ptr) + : Annotation(type, + name, + value_ptr, + ConcurrentAccessGuardMode::kUnguarded) {} Annotation(const Annotation&) = delete; Annotation& operator=(const Annotation&) = delete; @@ -172,7 +187,58 @@ class Annotation { const char* name() const { return name_; } const void* value() const { return value_ptr_; } + ConcurrentAccessGuardMode concurrent_access_guard_mode() const { + return concurrent_access_guard_mode_; + } + + //! \brief If this Annotation guards concurrent access using ScopedSpinGuard, + //! tries to obtain the spin guard and returns the result. + //! + //! \param[in] timeout_ns The timeout in nanoseconds after which to give up + //! trying to obtain the spin guard. + //! \return std::nullopt if the spin guard could not be obtained within + //! timeout_ns, or the obtained spin guard otherwise. + std::optional TryCreateScopedSpinGuard(uint64_t timeout_ns) { + // This can't use DCHECK_EQ() because ostream doesn't support + // operator<<(bool). + DCHECK(concurrent_access_guard_mode_ == + ConcurrentAccessGuardMode::kScopedSpinGuard); + if (concurrent_access_guard_mode_ == + ConcurrentAccessGuardMode::kUnguarded) { + return std::nullopt; + } + return ScopedSpinGuard::TryCreateScopedSpinGuard(timeout_ns, + spin_guard_state_); + } + protected: + //! \brief Constructs a new annotation. + //! + //! Upon construction, the annotation will not be included in any crash + //! reports until \sa SetSize() is called with a value greater than `0`. + //! + //! \param[in] type The data type of the value of the annotation. + //! \param[in] name A `NUL`-terminated C-string name for the annotation. Names + //! do not have to be unique, though not all crash processors may handle + //! Annotations with the same name. Names should be constexpr data with + //! static storage duration. + //! \param[in] value_ptr A pointer to the value for the annotation. The + //! pointer may not be changed once associated with an annotation, but + //! the data may be mutated. + //! \param[in] concurrent_access_guard_mode Mode used to guard concurrent + //! reads from writes. + constexpr Annotation(Type type, + const char name[], + void* value_ptr, + ConcurrentAccessGuardMode concurrent_access_guard_mode) + : link_node_(nullptr), + name_(name), + value_ptr_(value_ptr), + size_(0), + type_(type), + concurrent_access_guard_mode_(concurrent_access_guard_mode), + spin_guard_state_() {} + friend class AnnotationList; #if BUILDFLAG(IS_IOS) friend class internal::InProcessIntermediateDumpHandler; @@ -192,6 +258,11 @@ class Annotation { void* const value_ptr_; ValueSizeType size_; const Type type_; + + //! \brief Mode used to guard concurrent reads from writes. + const ConcurrentAccessGuardMode concurrent_access_guard_mode_; + + SpinGuardState spin_guard_state_; }; //! \brief An \sa Annotation that stores a `NUL`-terminated C-string value. diff --git a/thirdparty/sentry-native/external/crashpad/client/annotation_test.cc b/thirdparty/sentry-native/external/crashpad/client/annotation_test.cc index 5512e3fb48..f1a4aa7d10 100644 --- a/thirdparty/sentry-native/external/crashpad/client/annotation_test.cc +++ b/thirdparty/sentry-native/external/crashpad/client/annotation_test.cc @@ -21,11 +21,58 @@ #include "client/crashpad_info.h" #include "gtest/gtest.h" #include "test/gtest_death.h" +#include "util/misc/clock.h" +#include "util/synchronization/scoped_spin_guard.h" +#include "util/thread/thread.h" namespace crashpad { namespace test { namespace { +class SpinGuardAnnotation final : public Annotation { + public: + SpinGuardAnnotation(Annotation::Type type, const char name[]) + : Annotation(type, + name, + &value_, + ConcurrentAccessGuardMode::kScopedSpinGuard) {} + + bool Set(bool value, uint64_t spin_guard_timeout_ns) { + auto guard = TryCreateScopedSpinGuard(spin_guard_timeout_ns); + if (!guard) { + return false; + } + value_ = value; + SetSize(sizeof(value_)); + return true; + } + + private: + bool value_; +}; + +class ScopedSpinGuardUnlockThread final : public Thread { + public: + ScopedSpinGuardUnlockThread(ScopedSpinGuard scoped_spin_guard, + uint64_t sleep_time_ns) + : scoped_spin_guard_(std::move(scoped_spin_guard)), + sleep_time_ns_(sleep_time_ns) {} + + private: + void ThreadMain() override { + SleepNanoseconds(sleep_time_ns_); + + // Move the ScopedSpinGuard member into a local variable which is + // destroyed when ThreadMain() returns. + ScopedSpinGuard local_scoped_spin_guard(std::move(scoped_spin_guard_)); + + // After this point, local_scoped_spin_guard will be destroyed and unlocked. + } + + ScopedSpinGuard scoped_spin_guard_; + const uint64_t sleep_time_ns_; +}; + class Annotation : public testing::Test { public: void SetUp() override { @@ -108,6 +155,61 @@ TEST_F(Annotation, StringType) { EXPECT_EQ("loooo", annotation.value()); } +TEST_F(Annotation, BaseAnnotationShouldNotSupportSpinGuard) { + char buffer[1024]; + crashpad::Annotation annotation( + crashpad::Annotation::Type::kString, "no-spin-guard", buffer); + EXPECT_EQ(annotation.concurrent_access_guard_mode(), + crashpad::Annotation::ConcurrentAccessGuardMode::kUnguarded); +#ifdef NDEBUG + // This fails a DCHECK() in debug builds, so only test it for NDEBUG builds. + EXPECT_EQ(std::nullopt, annotation.TryCreateScopedSpinGuard(0)); +#endif +} + +TEST_F(Annotation, CustomAnnotationShouldSupportSpinGuardAndSet) { + constexpr crashpad::Annotation::Type kType = + crashpad::Annotation::UserDefinedType(1); + SpinGuardAnnotation spin_guard_annotation(kType, "spin-guard"); + EXPECT_EQ(spin_guard_annotation.concurrent_access_guard_mode(), + crashpad::Annotation::ConcurrentAccessGuardMode::kScopedSpinGuard); + EXPECT_TRUE(spin_guard_annotation.Set(true, 0)); + EXPECT_EQ(1U, spin_guard_annotation.size()); +} + +TEST_F(Annotation, CustomAnnotationSetShouldFailIfRunConcurrently) { + constexpr crashpad::Annotation::Type kType = + crashpad::Annotation::UserDefinedType(1); + SpinGuardAnnotation spin_guard_annotation(kType, "spin-guard"); + auto guard = spin_guard_annotation.TryCreateScopedSpinGuard(0); + EXPECT_NE(std::nullopt, guard); + // This should fail, since the guard is already held and the timeout is 0. + EXPECT_FALSE(spin_guard_annotation.Set(true, 0)); +} + +TEST_F(Annotation, + CustomAnnotationSetShouldSucceedIfSpinGuardUnlockedAsynchronously) { + constexpr crashpad::Annotation::Type kType = + crashpad::Annotation::UserDefinedType(1); + SpinGuardAnnotation spin_guard_annotation(kType, "spin-guard"); + auto guard = spin_guard_annotation.TryCreateScopedSpinGuard(0); + EXPECT_NE(std::nullopt, guard); + // Pass the guard off to a background thread which unlocks it after 1 ms. + constexpr uint64_t kSleepTimeNs = 1000000; // 1 ms + ScopedSpinGuardUnlockThread unlock_thread(std::move(guard.value()), + kSleepTimeNs); + unlock_thread.Start(); + + // Try to set the annotation with a 100 ms timeout. + constexpr uint64_t kSpinGuardTimeoutNanos = 100000000; // 100 ms + + // This should succeed after 1 ms, since the timeout is much larger than the + // time the background thread holds the guard. + EXPECT_TRUE(spin_guard_annotation.Set(true, kSpinGuardTimeoutNanos)); + + unlock_thread.Join(); +} + TEST(StringAnnotation, ArrayOfString) { static crashpad::StringAnnotation<4> annotations[] = { {"test-1", crashpad::StringAnnotation<4>::Tag::kArray}, diff --git a/thirdparty/sentry-native/external/crashpad/client/ios_handler/in_process_intermediate_dump_handler.cc b/thirdparty/sentry-native/external/crashpad/client/ios_handler/in_process_intermediate_dump_handler.cc index b2a1b27347..06eacceed8 100644 --- a/thirdparty/sentry-native/external/crashpad/client/ios_handler/in_process_intermediate_dump_handler.cc +++ b/thirdparty/sentry-native/external/crashpad/client/ios_handler/in_process_intermediate_dump_handler.cc @@ -22,12 +22,15 @@ #include #include +#include #include "build/build_config.h" #include "snapshot/snapshot_constants.h" #include "util/ios/ios_intermediate_dump_writer.h" #include "util/ios/raw_logging.h" +#include "util/ios/scoped_vm_map.h" #include "util/ios/scoped_vm_read.h" +#include "util/synchronization/scoped_spin_guard.h" namespace crashpad { namespace internal { @@ -672,6 +675,8 @@ void InProcessIntermediateDumpHandler::WriteSystemInfo( IntermediateDumpKey::kDaylightName, daylight_name.c_str(), daylight_name.length()); + uint64_t address_mask = system_data.AddressMask(); + WriteProperty(writer, IntermediateDumpKey::kAddressMask, &address_mask); vm_size_t page_size; host_page_size(mach_host_self(), &page_size); @@ -1161,6 +1166,13 @@ void InProcessIntermediateDumpHandler::WriteCrashpadAnnotationsList( IOSIntermediateDumpWriter::ScopedArray annotations_array( writer, IntermediateDumpKey::kAnnotationObjects); ScopedVMRead current; + + // Use vm_read() to ensure that the linked-list AnnotationList head (which is + // a dummy node of type kInvalid) is valid and copy its memory into a + // newly-allocated buffer. + // + // In the case where the pointer has been clobbered or the memory range is not + // readable, skip reading all the Annotations. if (!current.Read(annotation_list->head())) { CRASHPAD_RAW_LOG("Unable to read annotation"); return; @@ -1171,6 +1183,12 @@ void InProcessIntermediateDumpHandler::WriteCrashpadAnnotationsList( index < kMaxNumberOfAnnotations; ++index) { ScopedVMRead node; + + // Like above, use vm_read() to ensure that the node in the linked list is + // valid and copy its memory into a newly-allocated buffer. + // + // In the case where the pointer has been clobbered or the memory range is + // not readable, skip reading this and all further Annotations. if (!node.Read(current->link_node())) { CRASHPAD_RAW_LOG("Unable to read annotation"); return; @@ -1185,6 +1203,36 @@ void InProcessIntermediateDumpHandler::WriteCrashpadAnnotationsList( continue; } + // For Annotations which support guarding reads from concurrent writes, map + // their memory read-write using vm_remap(), then declare a ScopedSpinGuard + // which lives for the duration of the read. + ScopedVMMap mapped_node; + std::optional annotation_guard; + if (node->concurrent_access_guard_mode() == + Annotation::ConcurrentAccessGuardMode::kScopedSpinGuard) { + constexpr vm_prot_t kDesiredProtection = VM_PROT_WRITE | VM_PROT_READ; + if (!mapped_node.Map(node.get()) || + (mapped_node.CurrentProtection() & kDesiredProtection) != + kDesiredProtection) { + CRASHPAD_RAW_LOG("Unable to map annotation"); + + // Skip this annotation rather than giving up entirely, since the linked + // node should still be valid. + continue; + } + + // TODO(https://crbug.com/crashpad/438): Pass down a `params` object into + // this method to optionally enable a timeout here. + constexpr uint64_t kTimeoutNanoseconds = 0; + annotation_guard = + mapped_node->TryCreateScopedSpinGuard(kTimeoutNanoseconds); + if (!annotation_guard) { + // This is expected if the process is writing to the Annotation, so + // don't log here and skip the annotation. + continue; + } + } + IOSIntermediateDumpWriter::ScopedArrayMap annotation_map(writer); WritePropertyCString(writer, IntermediateDumpKey::kAnnotationName, diff --git a/thirdparty/sentry-native/external/crashpad/client/length_delimited_ring_buffer.h b/thirdparty/sentry-native/external/crashpad/client/length_delimited_ring_buffer.h new file mode 100644 index 0000000000..20a0bf149e --- /dev/null +++ b/thirdparty/sentry-native/external/crashpad/client/length_delimited_ring_buffer.h @@ -0,0 +1,603 @@ +// Copyright 2023 The Crashpad Authors +// +// 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 of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_CLIENT_LENGTH_DELIMITED_RING_BUFFER_H_ +#define CRASHPAD_CLIENT_LENGTH_DELIMITED_RING_BUFFER_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "base/numerics/safe_math.h" + +namespace crashpad { + +//! \brief Capacity of a `RingBufferData`, in bytes. +using RingBufferCapacity = uint32_t; + +namespace internal { + +//! \brief Default capacity of `RingBufferData`, in bytes. +inline constexpr RingBufferCapacity kDefaultRingBufferDataCapacity = 8192; + +//! \brief A tuple holding the current range of bytes which can be read from or +//! have been written to. +struct Range final { + //! \brief The offset into a `RingBufferData` at which a `Range` begins. + using Offset = uint32_t; + + //! \brief The length inside a `RingBufferData` of a `Range` of data. + using Length = uint32_t; + + Offset offset; + Length length; +}; + +// This struct is persisted to disk, so its size must not change. +static_assert(sizeof(Range) == 8, + "struct Range is not packed on this platform"); + +//! \brief The number of bits encoded in each byte of a Base 128-encoded varint. +inline constexpr int kBase128ByteValueBits = 7; + +//! \!brief Calculates the length in bytes of `value` encoded using +//! little-endian Base 128 varint encoding. +//! \sa https://developers.google.com/protocol-buffers/docs/encoding#varints +//! +//! `LengthDelimitedRingBufferWriter` uses varint-encoded delimiters to enable +//! zero-copy deserialization of the ringbuffer's contents when storing +//! protobufs inside the ringbuffer, e.g. via +//! `google::protobuf::util::ParseDelimitedFromZeroCopyStream()` or similar. +//! +//! \sa +//! https://github.com/protocolbuffers/protobuf/blob/3202b9da88ceb75b65bbabaf4033c95e872f828d/src/google/protobuf/util/delimited_message_util.h#L85 +//! \sa +//! https://github.com/protocolbuffers/protobuf/blob/8bd49dea5e167a389d94b71d24c981d8f9fa0c99/src/google/protobuf/io/zero_copy_stream_impl_lite.h#L68 +//! \sa +//! https://github.com/protocolbuffers/protobuf/blob/8bd49dea5e167a389d94b71d24c981d8f9fa0c99/src/google/protobuf/io/coded_stream.h#L171 +//! +//! \!param[in] value Value to be encoded in Base 128 varint encoding. +//! \!return The length in bytes of `value` in Base 128 varint encoding. +template +constexpr Range::Length Base128VarintEncodedLength(IntegerType value) { + static_assert(std::is_unsigned::value); + + Range::Length size = 1; + while (value >= 0x80) { + value >>= kBase128ByteValueBits; + size++; + } + return size; +} + +// Note that std::array capacity is a size_t, not a RingBufferCapacity. +template +using RingBufferArray = std::array; + +//! \return The size of the `RingBufferArray` as a `Range::Length`. +template +constexpr Range::Length RingBufferArraySize( + const RingBufferArray& ring_buffer_data) { + static_assert(ArrayCapacity <= std::numeric_limits::max()); + return static_cast(ring_buffer_data.size()); +} + +//! \brief Reads data from the ring buffer into a target buffer. +//! \param[in] ring_buffer_data The ring buffer to read. +//! \param[in,out] ring_buffer_read_range The range of the data available +//! to read. Upon return, set to the remaining range of data available +//! to read, if any. +//! \param[in] target_buffer Buffer into which data will be written. +//! \param[in] target_buffer_length Number of bytes to write into +//! `target_buffer`. +//! +//! \return `true` if the read succeeded, `false` otherwise. On success, updates +//! `ring_buffer_read_range` to reflect the bytes consumed. +//! +//! The bytes can wrap around the end of the ring buffer, in which case the read +//! continues at the beginning of the ring buffer (if the ring buffer is long +//! enough). +template +bool ReadBytesFromRingBuffer(const RingBufferArrayType& ring_buffer_data, + internal::Range& ring_buffer_read_range, + uint8_t* target_buffer, + Range::Length target_buffer_length) { + if (target_buffer_length > ring_buffer_read_range.length) { + return false; + } + if (target_buffer_length == 0) { + return true; + } + const Range::Length initial_read_length = std::min( + target_buffer_length, + RingBufferArraySize(ring_buffer_data) - ring_buffer_read_range.offset); + memcpy(target_buffer, + &ring_buffer_data[ring_buffer_read_range.offset], + initial_read_length); + if (initial_read_length < target_buffer_length) { + const Range::Length remaining_read_length = + target_buffer_length - initial_read_length; + memcpy(target_buffer + initial_read_length, + &ring_buffer_data[0], + remaining_read_length); + } + ring_buffer_read_range.offset = + (ring_buffer_read_range.offset + target_buffer_length) % + RingBufferArraySize(ring_buffer_data); + ring_buffer_read_range.length -= target_buffer_length; + return true; +} + +//! \brief Reads a single little-endian Base 128 varint-encoded integer from +//! the ring buffer. +//! \param[in] ring_buffer_data The ring buffer to read. +//! \param[in,out] ring_buffer_read_range The range of the data available +//! to read. Upon return, set to the remaining range of data available +//! to read, if any. +//! \param[out] result Upon success, set to the decoded value read from the +//! buffer. +//! +//! \return The length in bytes of the varint if the read succeeded, +//! `std::nullopt` otherwise. On success, updates `ring_buffer_read_range` +//! to reflect the bytes available to read. +//! +//! The varint can wrap around the end of the ring buffer, in which case the +//! read continues at the beginning of the ring buffer (if the ring buffer is +//! long enough). +template +std::optional ReadBase128VarintFromRingBuffer( + const RingBufferArrayType& ring_buffer_data, + internal::Range& ring_buffer_read_range, + IntegerType& result) { + static_assert(std::is_unsigned::value); + + result = 0; + uint8_t cur_varint_byte = 0; + constexpr uint8_t kValueMask = 0x7f; + constexpr uint8_t kContinuationMask = 0x80; + Range::Length length = 0; + do { + if (!ReadBytesFromRingBuffer( + ring_buffer_data, ring_buffer_read_range, &cur_varint_byte, 1)) { + // No capacity remaining in `ring_buffer_read_range` to read the varint. + return std::nullopt; + } + IntegerType cur_varint_value = + static_cast(cur_varint_byte & kValueMask); + + // This is equivalent to: + // + // result |= (cur_varint_value << (length * kBase128ByteValueBits)); + // + // but checks the result at each step for overflow, which handles two types + // of invalid input: + // + // 1) Too many bytes with kContinuationMask set (e.g., trying to encode 6 + // bytes worth of data in a 32-bit value) + // 2) Too many bits in the final byte (e.g., the 5th byte for a 32-bit value + // has bits 33 and 34 set) + IntegerType next_result_bits; + if (!base::CheckLsh(cur_varint_value, length * kBase128ByteValueBits) + .AssignIfValid(&next_result_bits)) { + return std::nullopt; + } + result |= next_result_bits; + ++length; + } while ((cur_varint_byte & kContinuationMask) == kContinuationMask); + return length; +} + +//! \brief Writes data from the source buffer into the ring buffer. +//! \param[in] source_buffer Buffer from which data will be read. +//! \param[in] source_buffer_length The length in bytes of `source_buffer`. +//! \param[in] ring_buffer_data The ring buffer into which data will be read. +//! \param[in,out] ring_buffer_write_range The range of the data available +//! to write. Upon return, set to the remaining range of data available +//! to write, if any. +//! +//! \return `true` if write read succeeded, `false` otherwise. On success, +//! updates +//! `ring_buffer_write_range` to reflect the bytes written. +//! +//! The bytes can wrap around the end of the ring buffer, in which case the +//! write continues at the beginning of the ring buffer (if the ring buffer is +//! long enough). +template +bool WriteBytesToRingBuffer(const uint8_t* const source_buffer, + Range::Length source_buffer_length, + RingBufferArrayType& ring_buffer_data, + internal::Range& ring_buffer_write_range) { + const Range::Length ring_buffer_bytes_remaining = + RingBufferArraySize(ring_buffer_data) - ring_buffer_write_range.length; + if (source_buffer_length > ring_buffer_bytes_remaining) { + return false; + } + const Range::Length initial_write_length = std::min( + source_buffer_length, + RingBufferArraySize(ring_buffer_data) - ring_buffer_write_range.offset); + memcpy(&ring_buffer_data[ring_buffer_write_range.offset], + source_buffer, + initial_write_length); + if (initial_write_length < source_buffer_length) { + const Range::Length remaining_write_length = + source_buffer_length - initial_write_length; + memcpy(&ring_buffer_data[0], + source_buffer + initial_write_length, + remaining_write_length); + } + ring_buffer_write_range.offset = + (ring_buffer_write_range.offset + source_buffer_length) % + RingBufferArraySize(ring_buffer_data); + ring_buffer_write_range.length -= source_buffer_length; + return true; +} + +//! \brief Writes a single Base 128 varint-encoded little-endian unsigned +//! integer into the ring buffer. +//! \param[in] value The value to encode and write into the ring buffer. +//! \param[in] ring_buffer_data The ring buffer into which to write. +//! \param[in,out] ring_buffer_write_range The range of the data available +//! to write. Upon return, set to the remaining range of data available +//! to write, if any. +//! +//! \return The length in bytes of the varint if the write succeeded, +//! `std::nullopt` otherwise. On success, updates `write_buffer_read_range` +//! to reflect the range available to write, if any. +//! +//! The varint can wrap around the end of the ring buffer, in which case the +//! write continues at the beginning of the ring buffer (if the ring buffer is +//! long enough). +template +std::optional WriteBase128VarintToRingBuffer( + IntegerType value, + RingBufferArrayType& ring_buffer_data, + internal::Range& ring_buffer_write_range) { + static_assert(std::is_unsigned::value); + + uint8_t cur_varint_byte; + constexpr uint8_t kValueMask = 0x7f; + constexpr uint8_t kContinuationMask = 0x80; + + // Every varint encodes to at least 1 byte of data. + int length = 1; + + while (value > kValueMask) { + cur_varint_byte = + (static_cast(value) & kValueMask) | kContinuationMask; + if (!WriteBytesToRingBuffer( + &cur_varint_byte, 1, ring_buffer_data, ring_buffer_write_range)) { + return std::nullopt; + } + value >>= kBase128ByteValueBits; + ++length; + } + cur_varint_byte = static_cast(value); + if (!WriteBytesToRingBuffer( + &cur_varint_byte, 1, ring_buffer_data, ring_buffer_write_range)) { + return std::nullopt; + } + return length; +} + +} // namespace internal + +//! \brief Storage for a ring buffer which can hold up to +//! `RingBufferCapacity` +//! bytes of Base 128-varint delimited variable-length items. +//! +//! This struct contains a header immediately followed by the ring buffer +//! data. The current read offset and length are stored in `header.data_range`. +//! +//! The structure of this object is: +//! +//! `|magic|version|data_offset|data_length|ring_buffer_data|` +//! +//! To write data to this object, see `LengthDelimitedRingBufferWriter`. +//! To read data from this object, see `LengthDelimitedRingBufferReader`. +//! +//! The bytes of this structure are suitable for direct serialization from +//! memory to disk, e.g. as a crashpad::Annotation. +template +struct RingBufferData final { + RingBufferData() = default; + RingBufferData(RingBufferData&) = delete; + RingBufferData& operator=(RingBufferData&) = delete; + + //! \brief The type of the array holding the data in this object. + using RingBufferArrayType = internal::RingBufferArray; + + //! \brief The type of the size in bytes of operations on this object. + using SizeType = internal::Range::Length; + + //! \brief Attempts to overwrite the contents of this object by deserializing + //! the buffer into this object. + //! \param[in] buffer The bytes to deserialize into this object. + //! \param[in] length The length in bytes of `buffer`. + //! + //! \return `true` if the buffer was a valid RingBufferData and this object + //! has enough capacity to store its bytes, `false` otherwise. + bool DeserializeFromBuffer(const void* buffer, SizeType length) { + if (length < sizeof(header) || length > sizeof(header) + sizeof(data)) { + return false; + } + const Header* other_header = reinterpret_cast(buffer); + if (other_header->magic != kMagic || other_header->version != kVersion) { + return false; + } + header.data_range = other_header->data_range; + const uint8_t* other_ring_buffer_bytes = + reinterpret_cast(buffer) + sizeof(*other_header); + const SizeType other_ring_buffer_len = length - sizeof(*other_header); + memcpy(&data[0], other_ring_buffer_bytes, other_ring_buffer_len); + return true; + } + + //! \return The current length in bytes of the data written to the ring + //! buffer. + SizeType GetRingBufferLength() const { + internal::Range data_range = header.data_range; + return sizeof(header) + std::min(internal::RingBufferArraySize(data), + data_range.offset + data_range.length); + } + + //! \brief Resets the state of the ring buffer (e.g., for testing). + void ResetForTesting() { header.data_range = {0, 0}; } + + //! \brief The magic signature of the ring buffer. + static constexpr uint32_t kMagic = 0xcab00d1e; + //! \brief The version of the ring buffer. + static constexpr uint32_t kVersion = 1; + + //! \brief A header containing metadata preceding the ring buffer data. + struct Header final { + Header() : magic(kMagic), version(kVersion), data_range({0, 0}) {} + + //! \brief The fixed magic value identifying this as a ring buffer. + const uint32_t magic; + + //! \brief The version of this ring buffer data. + const uint32_t version; + + //! \brief The range of readable data in the ring buffer. + internal::Range data_range; + }; + + //! \brief The header containing ring buffer metadata. + Header header; + + //! \brief The bytes of the ring buffer data. + RingBufferArrayType data; + + // This struct is persisted to disk, so its size must not change. + static_assert(sizeof(Header) == 16); + static_assert(Capacity <= std::numeric_limits::max()); +}; + +// Ensure the ring buffer is packed correctly at its default capacity. +static_assert( + sizeof(RingBufferData) == + 16 + internal::kDefaultRingBufferDataCapacity); + +// Allow just `RingBufferData foo;` to be declared without template arguments +// using C++17 class template argument deduction. +template < + RingBufferCapacity Capacity = internal::kDefaultRingBufferDataCapacity> +RingBufferData() -> RingBufferData; + +//! \brief Reads variable-length data buffers from a `RingBufferData`, +//! delimited by Base128 varint-encoded length delimiters. +//! +//! Holds a reference to a `RingBufferData` with the capacity to hold +//! `RingBufferDataType::size()` bytes of variable-length buffers each +//! preceded by its length (encoded as a Base128 length varint). +//! +//! Provides reading capabilities via `Pop()`. +template +class LengthDelimitedRingBufferReader final { + public: + //! \brief Constructs a reader which holds a reference to `ring_buffer`. + //! \param[in] ring_buffer The ring buffer from which data will be read. + //! This object must outlive the lifetime of `ring_buffer`. + constexpr explicit LengthDelimitedRingBufferReader( + RingBufferDataType& ring_buffer) + : ring_buffer_(ring_buffer), + data_range_(ring_buffer_.header.data_range) {} + + LengthDelimitedRingBufferReader(const LengthDelimitedRingBufferReader&) = + delete; + LengthDelimitedRingBufferReader& operator=( + const LengthDelimitedRingBufferReader&) = delete; + + //! \brief Pops off the next buffer from the front of the ring buffer. + //! + //! \param[in] target_buffer On success, the buffer into which data will + //! be read. + //! \return On success, returns `true` and advances `ring_buffer.data_range` + //! past the end of the buffer read. Otherwise, returns `false`. + bool Pop(std::vector& target_buffer) { + return PopWithRange(target_buffer, data_range_); + } + + //! \brief Resets the state of the reader (e.g., for testing). + void ResetForTesting() { data_range_ = {0, 0}; } + + private: + //! \brief Pops off the next buffer from the front of the ring buffer. + //! \param[in] target_buffer On success, the buffer into which data will + //! be read. + //! \param[in,out] data_range The range of data available to read. + //! On success, updated to the remaining range avilable to read. + //! \return On success, returns `true` and advances `ring_buffer.data_range` + //! past the end of the buffer read. Otherwise, returns `false`. + bool PopWithRange(std::vector& target_buffer, + internal::Range& data_range) { + internal::Range::Length buffer_length; + if (!ReadBase128VarintFromRingBuffer( + ring_buffer_.data, data_range, buffer_length)) { + return false; + } + if (buffer_length == 0) { + // A zero-length buffer means the buffer was truncated in the middle of a + // Push(). + return false; + } + const auto previous_target_buffer_size = target_buffer.size(); + target_buffer.resize(previous_target_buffer_size + buffer_length); + if (!ReadBytesFromRingBuffer(ring_buffer_.data, + data_range, + &target_buffer[previous_target_buffer_size], + buffer_length)) { + return false; + } + return true; + } + + //! \brief Reference to the ring buffer from which data is read. + const RingBufferDataType& ring_buffer_; + //! \brief Range of data currently available to read. + internal::Range data_range_; +}; + +// Allow just `LengthDelimitedRingBufferReader reader(foo);` to be declared +// without template arguments using C++17 class template argument deduction. +template +LengthDelimitedRingBufferReader(RingBufferDataType&) + -> LengthDelimitedRingBufferReader; + +//! \brief Writes variable-length data buffers to a `RingBufferData`, +//! delimited by Base128 varint-encoded length delimiters. +//! +//! Holds a reference to a `RingBufferData` with the capacity to hold +//! `RingBufferDataType::size()` bytes of variable-length buffers each +//! preceded by its length (encoded as a Base128 length varint). +//! +//! Provides writing capabilities via `Push()`. +template +class LengthDelimitedRingBufferWriter final { + public: + //! \brief Constructs a writer which holds a reference to `ring_buffer`. + //! \param[in] ring_buffer The ring buffer into which data will be written. + //! This object must outlive the lifetime of `ring_buffer`. + constexpr explicit LengthDelimitedRingBufferWriter( + RingBufferDataType& ring_buffer) + : ring_buffer_(ring_buffer), ring_buffer_write_offset_(0) {} + + LengthDelimitedRingBufferWriter(const LengthDelimitedRingBufferWriter&) = + delete; + LengthDelimitedRingBufferWriter& operator=( + const LengthDelimitedRingBufferWriter&) = delete; + + //! \brief Writes data to the ring buffer. + //! + //! If there is not enough room remaining in the ring buffer to store the new + //! data, old data will be removed from the ring buffer in FIFO order until + //! there is room for the new data. + //! + //! \param[in] buffer The data to be written. + //! \param[in] buffer_length The lengh of `buffer`, in bytes. + //! \return On success, returns `true`, updates `ring_buffer.data_range` + //! to reflect the remaining data available to read, and updates + //! `ring_buffer_write_offset_` to reflec the current write positionl. + //! Otherwise, returns `false`. + bool Push(const void* const buffer, + typename RingBufferDataType::SizeType buffer_length) { + if (buffer_length == 0) { + // Pushing a zero-length buffer is not allowed + // (`LengthDelimitedRingBufferWriter` reserves that to represent a + // temporarily truncated item below). + return false; + } + const internal::Range::Length buffer_varint_encoded_length = + internal::Base128VarintEncodedLength(buffer_length); + const internal::Range::Length bytes_needed = + buffer_varint_encoded_length + buffer_length; + if (bytes_needed > ring_buffer_.data.size()) { + return false; + } + // If needed, move the readable region forward one buffer at a time to make + // room for `buffer_length` bytes of new data. + auto readable_data_range = ring_buffer_.header.data_range; + internal::Range::Length bytes_available = + internal::RingBufferArraySize(ring_buffer_.data) - + readable_data_range.length; + while (bytes_available < bytes_needed) { + internal::Range::Length bytes_to_skip; + auto varint_length = ReadBase128VarintFromRingBuffer( + ring_buffer_.data, readable_data_range, bytes_to_skip); + if (!varint_length.has_value()) { + return false; + } + // Skip past the next entry including its prepended varint length. + readable_data_range.offset = + (readable_data_range.offset + bytes_to_skip) % + internal::RingBufferArraySize(ring_buffer_.data); + readable_data_range.length -= bytes_to_skip; + bytes_available += varint_length.value() + bytes_to_skip; + } + // Write the varint containing `buffer_length` to the current write + // position. + internal::Range write_range = { + ring_buffer_write_offset_, + bytes_needed, + }; + + internal::WriteBase128VarintToRingBuffer( + buffer_length, ring_buffer_.data, write_range); + // Next, write the bytes from `buffer`. + internal::WriteBytesToRingBuffer( + reinterpret_cast(buffer), + buffer_length, + ring_buffer_.data, + write_range); + // Finally, update the write position and read data range taking into + // account any items skipped to make room plus the new buffer's varint + // length and the new buffer's length. + ring_buffer_write_offset_ = write_range.offset; + const internal::Range final_data_range = { + readable_data_range.offset, + readable_data_range.length + bytes_needed, + }; + ring_buffer_.header.data_range = final_data_range; + return true; + } + + //! \brief Resets the state of the ring buffer and writer (e.g., for testing). + void ResetForTesting() { + ring_buffer_.ResetForTesting(); + ring_buffer_write_offset_ = 0; + } + + private: + //! \brief Reference to the ring buffer from which data is written. + RingBufferDataType& ring_buffer_; + + // \brief Current write position next time `Push()` is invoked. + internal::Range::Offset ring_buffer_write_offset_; +}; + +// Allow just `LengthDelimitedRingBufferWriter writer(foo);` to be declared +// without template arguments using C++17 class template argument deduction. +template +LengthDelimitedRingBufferWriter(RingBufferDataType&) + -> LengthDelimitedRingBufferWriter; + +} // namespace crashpad + +#endif // CRASHPAD_CLIENT_LENGTH_DELIMITED_RING_BUFFER_H_ diff --git a/thirdparty/sentry-native/external/crashpad/client/length_delimited_ring_buffer_test.cc b/thirdparty/sentry-native/external/crashpad/client/length_delimited_ring_buffer_test.cc new file mode 100644 index 0000000000..6ead898107 --- /dev/null +++ b/thirdparty/sentry-native/external/crashpad/client/length_delimited_ring_buffer_test.cc @@ -0,0 +1,348 @@ +// Copyright 2023 The Crashpad Authors +// +// 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 of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "client/length_delimited_ring_buffer.h" + +#include + +#include +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace crashpad { +namespace test { +namespace { + +using testing::Eq; +using testing::IsFalse; +using testing::IsTrue; + +// Buffer with magic 0xcab00d1e, version 1, read_pos 0, length 3, and 3 bytes of +// data (1 varint length, 2 bytes data) +constexpr char kValidBufferSize3[] = + "\x1e\x0d\xb0\xca\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x02\x42" + "\x23"; +constexpr size_t kValidBufferSize3Len = + sizeof(kValidBufferSize3) - 1; // Remove trailing NUL. + +// Buffer with magic 0xcab00d1e, version 8, read_pos 0, length 3, and 3 bytes of +// data (1 varint length, 2 bytes data). +constexpr char kInvalidVersionBuffer[] = + "\x1e\x0d\xb0\xca\x08\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x02\xab" + "\xcd"; +constexpr size_t kInvalidVersionBufferLen = + sizeof(kInvalidVersionBuffer) - 1; // Remove trailing NUL. + +// Buffer representing process which crashed while in the middle of a Push() +// operation, with a previously-Push()ed buffer whose length was zeroed out at +// the start. +constexpr char kMidCrashBuffer[] = + "\x1e\x0d\xb0\xca\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x42" + "\x23"; +constexpr size_t kMidCrashBufferLen = + sizeof(kMidCrashBuffer) - 1; // Remove trailing NUL. + +constexpr uint8_t kHello[] = {0x68, 0x65, 0x6c, 0x6c, 0x6f}; + +// Invalid buffer containing malformed varint in data payload (Base 128 varint +// with length 6, which would represent a data length > 32 bits). +constexpr char kInvalidBase128VarintBuffer[] = + "\x1e\x0d\xb0\xca\x01\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x80\x80" + "\x80\x80\x80\x01"; +constexpr size_t kInvalidBase128VarintBufferLen = + sizeof(kInvalidBase128VarintBuffer) - 1; // Remove trailing NUL. + +// Invalid buffer containing malformed varint in data payload (Base 128 varint +// with length 5 but bits 33 and 34 set, which would represent a data length > +// 32 bits). +constexpr char kInvalidBase128VarintBits33And34SetBuffer[] = + "\x1e\x0d\xb0\xca\x01\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x80\x80" + "\x80\x80\x60"; +constexpr size_t kInvalidBase128VarintBits33And34SetBufferLen = + sizeof(kInvalidBase128VarintBits33And34SetBuffer) - + 1; // Remove trailing NUL. + +// Invalid buffer containing too-short data payload (varint length indicates +// payload length is 4 but payload only contains 3 bytes). +constexpr char kInvalidPayloadBufferTooShort[] = + "\x1e\x0d\xb0\xca\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04" + "\x42\x42\x42"; +constexpr size_t kInvalidPayloadBufferTooShortLen = + sizeof(kInvalidPayloadBufferTooShort) - 1; // Remove trailing NUL. + +TEST(LengthDelimitedRingBufferTest, + RingBufferDataShouldStartWithMagicAndVersion) { + RingBufferData ring_buffer; + const void* ring_buffer_bytes = static_cast(&ring_buffer); + EXPECT_THAT(memcmp(ring_buffer_bytes, "\x1e\x0d\xb0\xca\x01\x00\x00\x00", 8), + Eq(0)); +} + +TEST(LengthDelimitedRingBufferTest, + EmptyBufferSizeShouldIncludeHeaderInRingBufferLength) { + RingBufferData ring_buffer; + EXPECT_THAT(ring_buffer.GetRingBufferLength(), + Eq(16U)); // 4 for uint32 magic, 4 for uint32 version, 4 for + // uint32 read_pos, 4 for uint32 length +} + +TEST(LengthDelimitedRingBufferTest, + NonEmptyBufferSizeShouldIncludeHeaderAndData) { + RingBufferData ring_buffer; + LengthDelimitedRingBufferWriter writer(ring_buffer); + ASSERT_THAT(writer.Push(kHello, sizeof(kHello)), IsTrue()); + EXPECT_THAT(ring_buffer.GetRingBufferLength(), + Eq(22U)); // 16 for header, 1 for varint length, 5 for data +} + +TEST(LengthDelimitedRingBufferTest, PopOnEmptyBufferShouldFail) { + RingBufferData ring_buffer; + LengthDelimitedRingBufferReader reader(ring_buffer); + std::vector result; + EXPECT_THAT(reader.Pop(result), IsFalse()); +} + +TEST(LengthDelimitedRingBufferTest, PushZeroLengthShouldFail) { + RingBufferData ring_buffer; + LengthDelimitedRingBufferWriter writer(ring_buffer); + ASSERT_THAT(writer.Push(nullptr, 0), IsFalse()); +} + +TEST(LengthDelimitedRingBufferTest, PushExactlyBufferSizeThenPopShouldSucceed) { + RingBufferData ring_buffer; + LengthDelimitedRingBufferWriter writer(ring_buffer); + ASSERT_THAT(writer.Push(kHello, sizeof(kHello)), IsTrue()); + + LengthDelimitedRingBufferReader reader(ring_buffer); + std::vector result; + EXPECT_THAT(reader.Pop(result), IsTrue()); + const std::vector expected_first = {0x68, 0x65, 0x6c, 0x6c, 0x6f}; + EXPECT_THAT(result, Eq(expected_first)); +} + +TEST(LengthDelimitedRingBufferTest, PushLargerThanBufferSizeShouldFail) { + RingBufferData<4> ring_buffer; + LengthDelimitedRingBufferWriter writer(ring_buffer); + EXPECT_THAT(writer.Push(kHello, sizeof(kHello)), IsFalse()); +} + +TEST(LengthDelimitedRingBufferTest, + PushUntilFullThenPopUntilEmptyShouldReturnInFIFOOrder) { + RingBufferData<4> ring_buffer; + LengthDelimitedRingBufferWriter writer(ring_buffer); + constexpr uint8_t a = 0x41; + EXPECT_THAT(writer.Push(&a, sizeof(a)), + IsTrue()); // Writes 2 bytes (1 for length) + constexpr uint8_t b = 0x42; + EXPECT_THAT(writer.Push(&b, sizeof(b)), + IsTrue()); // Writes 2 bytes (1 for length) + + LengthDelimitedRingBufferReader reader(ring_buffer); + std::vector first; + EXPECT_THAT(reader.Pop(first), IsTrue()); + const std::vector expected_first = {0x41}; + EXPECT_THAT(first, Eq(expected_first)); + + std::vector second; + EXPECT_THAT(reader.Pop(second), IsTrue()); + const std::vector expected_second = {0x42}; + EXPECT_THAT(second, Eq(expected_second)); + + std::vector empty; + EXPECT_THAT(reader.Pop(empty), IsFalse()); +} + +TEST(LengthDelimitedRingBufferTest, + PushThenPopBuffersOfDifferingLengthsShouldReturnBuffers) { + RingBufferData<5> ring_buffer; + LengthDelimitedRingBufferWriter writer(ring_buffer); + constexpr uint8_t ab[2] = {0x41, 0x42}; + EXPECT_THAT(writer.Push(ab, sizeof(ab)), + IsTrue()); // Writes 3 bytes (1 for length) + constexpr uint8_t c = 0x43; + EXPECT_THAT(writer.Push(&c, sizeof(c)), + IsTrue()); // Writes 2 bytes (1 for length) + + LengthDelimitedRingBufferReader reader(ring_buffer); + std::vector first; + EXPECT_THAT(reader.Pop(first), IsTrue()); + const std::vector expected_first = {0x41, 0x42}; + EXPECT_THAT(first, Eq(expected_first)); + + std::vector second; + EXPECT_THAT(reader.Pop(second), IsTrue()); + const std::vector expected_second = {0x43}; + EXPECT_THAT(second, Eq(expected_second)); + + std::vector empty; + EXPECT_THAT(reader.Pop(empty), IsFalse()); +} + +TEST(LengthDelimitedRingBufferDataTest, PushOnFullBufferShouldOverwriteOldest) { + RingBufferData<4> ring_buffer; + LengthDelimitedRingBufferWriter writer(ring_buffer); + constexpr uint8_t a = 0x41; + EXPECT_THAT(writer.Push(&a, sizeof(a)), + IsTrue()); // Writes 2 bytes (1 for length) + constexpr uint8_t b = 0x42; + EXPECT_THAT(writer.Push(&b, sizeof(b)), + IsTrue()); // Writes 2 bytes (1 for length) + constexpr uint8_t c = 0x43; + EXPECT_THAT(writer.Push(&c, sizeof(c)), IsTrue()); // Should overwrite "A" + + LengthDelimitedRingBufferReader reader(ring_buffer); + std::vector first; + EXPECT_THAT(reader.Pop(first), IsTrue()); + const std::vector expected_first = {uint8_t{0x42}}; + EXPECT_THAT(first, Eq(expected_first)); + + std::vector second; + EXPECT_THAT(reader.Pop(second), IsTrue()); + const std::vector expected_second = {uint8_t{0x43}}; + EXPECT_THAT(second, Eq(expected_second)); +} + +TEST(LengthDelimitedRingBufferDataTest, + PushOnFullBufferShouldOverwriteMultipleOldest) { + RingBufferData<4> ring_buffer; + LengthDelimitedRingBufferWriter writer(ring_buffer); + constexpr uint8_t a = 0x41; + EXPECT_THAT(writer.Push(&a, sizeof(a)), + IsTrue()); // Writes 2 bytes (1 for length) + constexpr uint8_t b = 0x42; + EXPECT_THAT(writer.Push(&b, sizeof(b)), + IsTrue()); // Writes 2 bytes (1 for length) + constexpr uint8_t cd[] = {0x43, 0x44}; + EXPECT_THAT(writer.Push(cd, sizeof(cd)), + IsTrue()); // Needs 3 bytes; should overwrite "A" and "B" + + LengthDelimitedRingBufferReader reader(ring_buffer); + std::vector first; + EXPECT_THAT(reader.Pop(first), IsTrue()); + const std::vector expected_first = {0x43, 0x44}; + EXPECT_THAT(first, Eq(expected_first)); + + std::vector empty; + EXPECT_THAT(reader.Pop(empty), IsFalse()); +} + +TEST(LengthDelimitedRingBufferDataTest, PushThenPopWithLengthVarintTwoBytes) { + RingBufferData ring_buffer; + decltype(ring_buffer)::SizeType size = 150; + std::string s(size, 'X'); + LengthDelimitedRingBufferWriter writer(ring_buffer); + ASSERT_THAT(writer.Push(reinterpret_cast(s.c_str()), size), + IsTrue()); + + LengthDelimitedRingBufferReader reader(ring_buffer); + std::vector first; + EXPECT_THAT(reader.Pop(first), IsTrue()); + std::string result(reinterpret_cast(first.data()), first.size()); + EXPECT_THAT(result, Eq(s)); +} + +TEST(LengthDelimitedRingBufferDataTest, DeserializeFromTooShortShouldFail) { + RingBufferData<1> ring_buffer; + EXPECT_THAT(ring_buffer.DeserializeFromBuffer(nullptr, 0), IsFalse()); +} + +TEST(LengthDelimitedRingBufferDataTest, DeserializeFromTooLongShouldFail) { + RingBufferData<1> ring_buffer; + // This buffer is size 3; it won't fit in the template arg (size 1). + EXPECT_THAT(ring_buffer.DeserializeFromBuffer( + reinterpret_cast(kValidBufferSize3), + kValidBufferSize3Len), + IsFalse()); +} + +TEST(LengthDelimitedRingBufferDataTest, + DeserializeFromInvalidVersionShouldFail) { + RingBufferData<3> ring_buffer; + EXPECT_THAT(ring_buffer.DeserializeFromBuffer( + reinterpret_cast(kInvalidVersionBuffer), + kInvalidVersionBufferLen), + IsFalse()); +} + +TEST(LengthDelimitedRingBufferDataTest, + DeserializeFromInvalidVarintLengthShouldSucceedButPopShouldFail) { + RingBufferData ring_buffer; + EXPECT_THAT(ring_buffer.DeserializeFromBuffer( + reinterpret_cast(kInvalidBase128VarintBuffer), + kInvalidBase128VarintBufferLen), + IsTrue()); + LengthDelimitedRingBufferReader reader(ring_buffer); + std::vector data; + EXPECT_THAT(reader.Pop(data), IsFalse()); +} + +TEST(LengthDelimitedRingBufferDataTest, + DeserializeFromInvalidVarintBitsShouldSucceedButPopShouldFail) { + RingBufferData ring_buffer; + EXPECT_THAT(ring_buffer.DeserializeFromBuffer( + reinterpret_cast( + kInvalidBase128VarintBits33And34SetBuffer), + kInvalidBase128VarintBits33And34SetBufferLen), + IsTrue()); + LengthDelimitedRingBufferReader reader(ring_buffer); + std::vector data; + EXPECT_THAT(reader.Pop(data), IsFalse()); +} + +TEST(LengthDelimitedRingBufferDataTest, + DeserializeFromInvalidPayloadBufferTooShortShouldSucceedButPopShouldFail) { + RingBufferData ring_buffer; + EXPECT_THAT( + ring_buffer.DeserializeFromBuffer( + reinterpret_cast(kInvalidPayloadBufferTooShort), + kInvalidPayloadBufferTooShortLen), + IsTrue()); + LengthDelimitedRingBufferReader reader(ring_buffer); + std::vector data; + EXPECT_THAT(reader.Pop(data), IsFalse()); +} + +TEST(LengthDelimitedRingBufferDataTest, + DeserializeFromFullBufferShouldSucceed) { + RingBufferData<3> ring_buffer; + EXPECT_THAT(ring_buffer.DeserializeFromBuffer( + reinterpret_cast(kValidBufferSize3), + kValidBufferSize3Len), + IsTrue()); + LengthDelimitedRingBufferReader reader(ring_buffer); + std::vector data; + EXPECT_THAT(reader.Pop(data), IsTrue()); + const std::vector expected = {0x42, 0x23}; + EXPECT_THAT(data, Eq(expected)); +} + +TEST(LengthDelimitedRingBufferDataTest, + DeserializeFromMidCrashBufferShouldSucceedButSubsequentPopShouldFail) { + RingBufferData ring_buffer; + EXPECT_THAT(ring_buffer.DeserializeFromBuffer( + reinterpret_cast(kMidCrashBuffer), + kMidCrashBufferLen), + IsTrue()); + LengthDelimitedRingBufferReader reader(ring_buffer); + // Pop should fail since the length was written to be 0. + std::vector data; + EXPECT_THAT(reader.Pop(data), IsFalse()); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/thirdparty/sentry-native/external/crashpad/client/ring_buffer_annotation.h b/thirdparty/sentry-native/external/crashpad/client/ring_buffer_annotation.h new file mode 100644 index 0000000000..fc0482ea29 --- /dev/null +++ b/thirdparty/sentry-native/external/crashpad/client/ring_buffer_annotation.h @@ -0,0 +1,136 @@ +// Copyright 2023 The Crashpad Authors +// +// 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 of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_CLIENT_RING_BUFFER_ANNOTATION_H_ +#define CRASHPAD_CLIENT_RING_BUFFER_ANNOTATION_H_ + +#include + +#include "client/annotation.h" +#include "client/length_delimited_ring_buffer.h" + +namespace crashpad { + +//! \brief Capacity of `RingBufferAnnotation`, in bytes. +using RingBufferAnnotationCapacity = RingBufferCapacity; + +namespace internal { + +//! \brief Default capacity of `RingBufferAnnotation`, in bytes. +inline constexpr RingBufferAnnotationCapacity + kDefaultRingBufferAnnotationCapacity = 8192; + +} // namespace internal + +//! \brief An `Annotation` which wraps a `LengthDelimitedRingBuffer` +//! of up to `Capacity` bytes in length. +//! +//! Supports writing variable-length data via `Push()`. When the ring buffer is +//! full, it will drop old data items in FIFO order until enough space is +//! available for the write. +//! +//! Supports guarding concurrent reads from writes via `ScopedSpinGuard`, so +//! writing to this object is thread-safe. +//! +//! Clients which read this `Annotation`'s memory can optionally invoke +//! `TryCreateScopedSpinGuard()` on this object to ensure any pending write +//! finishes before the memory is read. +//! +//! Each item in this ring buffer is delimited by its length encoded in +//! little-endian Base 128 varint encoding. +//! +//! `RingBufferAnnotation` uses varint-encoded delimiters to enable +//! zero-copy deserialization of the ringbuffer's contents when storing +//! protobufs inside the ringbuffer, e.g. via +//! `google::protobuf::util::ParseDelimitedFromZeroCopyStream()` or similar. +//! +//! \sa +//! https://github.com/protocolbuffers/protobuf/blob/3202b9da88ceb75b65bbabaf4033c95e872f828d/src/google/protobuf/util/delimited_message_util.h#L85 +//! \sa +//! https://github.com/protocolbuffers/protobuf/blob/8bd49dea5e167a389d94b71d24c981d8f9fa0c99/src/google/protobuf/io/zero_copy_stream_impl_lite.h#L68 +//! \sa +//! https://github.com/protocolbuffers/protobuf/blob/8bd49dea5e167a389d94b71d24c981d8f9fa0c99/src/google/protobuf/io/coded_stream.h#L171 +//! +//! To deserialize the items stored in this annotation, use +//! `LengthDelimitedRingBufferReader`. +template +class RingBufferAnnotation final : public Annotation { + public: + //! \brief Constructs a `RingBufferAnnotation`. + //! \param[in] type A unique identifier for the type of data in the ring + //! buffer. + //! \param[in] name The name of the annotation. + constexpr RingBufferAnnotation(Annotation::Type type, const char name[]) + : Annotation(type, + name, + reinterpret_cast(&ring_buffer_data_), + ConcurrentAccessGuardMode::kScopedSpinGuard), + ring_buffer_data_(), + ring_buffer_writer_(ring_buffer_data_) {} + RingBufferAnnotation(const RingBufferAnnotation&) = delete; + RingBufferAnnotation& operator=(const RingBufferAnnotation&) = delete; + RingBufferAnnotation(RingBufferAnnotation&&) = default; + RingBufferAnnotation& operator=(RingBufferAnnotation&&) = default; + + //! \brief Pushes data onto this annotation's ring buffer. + //! + //! If the ring buffer does not have enough space to store `buffer_length` + //! bytes of data, old data items are dropped in FIFO order until + //! enough space is available to store the new data. + bool Push(const void* const buffer, + RingBufferAnnotationCapacity buffer_length) { + // Use a zero timeout so the operation immediately fails if another thread + // or process is currently reading this Annotation. + constexpr uint64_t kSpinGuardTimeoutNanoseconds = 0; + + auto spin_guard = TryCreateScopedSpinGuard(kSpinGuardTimeoutNanoseconds); + if (!spin_guard) { + return false; + } + bool success = ring_buffer_writer_.Push(buffer, buffer_length); + if (success) { + SetSize(ring_buffer_data_.GetRingBufferLength()); + } + return success; + } + + //! \brief Reset the annotation (e.g., for testing). + //! This method is not thread-safe. + void ResetForTesting() { + ring_buffer_data_.ResetForTesting(); + ring_buffer_writer_.ResetForTesting(); + } + + private: + using RingBufferWriter = + LengthDelimitedRingBufferWriter>; + + //! \brief The ring buffer data stored in this Anotation. + RingBufferData ring_buffer_data_; + + //! \brief The writer which wraps `ring_buffer_data_`. + RingBufferWriter ring_buffer_writer_; +}; + +// Allow just `RingBufferAnnotation foo;` to be declared without template +// arguments using C++17 class template argument deduction. +template +RingBufferAnnotation(Annotation::Type type, const char name[]) + -> RingBufferAnnotation; + +} // namespace crashpad + +#endif // CRASHPAD_CLIENT_RING_BUFFER_ANNOTATION_H_ diff --git a/thirdparty/sentry-native/external/crashpad/client/ring_buffer_annotation_load_test_main.cc b/thirdparty/sentry-native/external/crashpad/client/ring_buffer_annotation_load_test_main.cc new file mode 100644 index 0000000000..12355f4b1b --- /dev/null +++ b/thirdparty/sentry-native/external/crashpad/client/ring_buffer_annotation_load_test_main.cc @@ -0,0 +1,474 @@ +// Copyright 2023 The Crashpad Authors +// +// 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 of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "base/notreached.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" +#include "base/strings/stringprintf.h" +#include "build/build_config.h" +#include "client/annotation.h" +#include "client/length_delimited_ring_buffer.h" +#include "client/ring_buffer_annotation.h" +#include "tools/tool_support.h" +#include "util/stdlib/string_number_conversion.h" +#include "util/synchronization/scoped_spin_guard.h" +#include "util/thread/thread.h" + +#if BUILDFLAG(IS_WIN) +#include +#else +#include +#endif // BUILDFLAG(IS_WIN) + +namespace crashpad { + +namespace test { + +namespace { + +constexpr Annotation::Type kRingBufferLoadTestType = + Annotation::UserDefinedType(0x0042); +std::atomic g_should_exit = false; + +struct RingBufferAnnotationSnapshotParams final { + enum class Mode { + kUseScopedSpinGuard = 1, + kDoNotUseSpinGuard = 2, + }; + Mode mode = Mode::kUseScopedSpinGuard; + using Duration = std::chrono::duration; + Duration producer_thread_min_run_duration = std::chrono::milliseconds(1); + Duration producer_thread_max_run_duration = std::chrono::milliseconds(10); + Duration producer_thread_sleep_duration = std::chrono::nanoseconds(10); + Duration consumer_thread_min_run_duration = std::chrono::milliseconds(5); + Duration consumer_thread_max_run_duration = std::chrono::milliseconds(100); + Duration quiesce_timeout = std::chrono::microseconds(500); + uint64_t num_loops = std::numeric_limits::max(); + std::optional main_thread_run_duration = std::nullopt; +}; + +template +class RingBufferAnnotationSnapshot final { + using RingBufferAnnotationType = RingBufferAnnotation; + + struct State final { + State() + : ring_buffer_annotation(kRingBufferLoadTestType, + "ring-buffer-load-test"), + ring_buffer_ready(false), + producer_thread_running(false), + producer_thread_finished(false), + consumer_thread_finished(false), + should_exit(false) {} + + State(const State&) = delete; + State& operator=(const State&) = delete; + + RingBufferAnnotationType ring_buffer_annotation; + bool ring_buffer_ready; + bool producer_thread_running; + bool producer_thread_finished; + bool consumer_thread_finished; + bool should_exit; + }; + + class Thread final : public crashpad::Thread { + public: + Thread(std::function thread_main) + : thread_main_(std::move(thread_main)) {} + + private: + void ThreadMain() override { thread_main_(); } + + const std::function thread_main_; + }; + + public: + RingBufferAnnotationSnapshot(const RingBufferAnnotationSnapshotParams& params) + : params_(params), + main_loop_thread_([this]() { MainLoopThreadMain(); }), + producer_thread_([this]() { ProducerThreadMain(); }), + consumer_thread_([this]() { ConsumerThreadMain(); }), + mutex_(), + state_changed_condition_(), + state_() {} + + RingBufferAnnotationSnapshot(const RingBufferAnnotationSnapshot&) = delete; + RingBufferAnnotationSnapshot& operator=(const RingBufferAnnotationSnapshot&) = + delete; + + void Start() { + main_loop_thread_.Start(); + producer_thread_.Start(); + consumer_thread_.Start(); + } + + void Stop() { + consumer_thread_.Join(); + producer_thread_.Join(); + main_loop_thread_.Join(); + } + + private: + void MainLoopThreadMain() { + std::chrono::steady_clock::time_point main_thread_end_time; + if (params_.main_thread_run_duration) { + main_thread_end_time = + std::chrono::steady_clock::now() + *params_.main_thread_run_duration; + } else { + main_thread_end_time = std::chrono::steady_clock::time_point::max(); + } + for (uint64_t i = 0; + i < params_.num_loops && + std::chrono::steady_clock::now() < main_thread_end_time; + i++) { + { + std::unique_lock start_lock(mutex_); + state_.ring_buffer_annotation.ResetForTesting(); + state_.ring_buffer_ready = true; + state_changed_condition_.notify_all(); + } + + { + std::unique_lock lock(mutex_); + state_changed_condition_.wait(lock, [this] { + return state_.producer_thread_finished && + state_.consumer_thread_finished; + }); + state_.ring_buffer_ready = false; + if (g_should_exit) { + printf("Exiting on Control-C.\n"); + break; + } + printf("."); + fflush(stdout); + state_changed_condition_.notify_all(); + } + } + state_.should_exit = true; + state_changed_condition_.notify_all(); + } + + void ProducerThreadMain() { + while (true) { + { + std::unique_lock lock(mutex_); + state_changed_condition_.wait(lock, [this] { + return state_.should_exit || state_.ring_buffer_ready; + }); + if (state_.should_exit) { + return; + } + state_.producer_thread_running = true; + state_.producer_thread_finished = false; + state_changed_condition_.notify_all(); + } + + auto min_run_duration_micros = + std::chrono::duration_cast( + params_.producer_thread_min_run_duration); + auto max_run_duration_micros = + std::chrono::duration_cast( + params_.producer_thread_max_run_duration); + std::uniform_int_distribution + run_duration_distribution(min_run_duration_micros.count(), + max_run_duration_micros.count()); + static thread_local std::mt19937 random_number_generator; + auto run_duration = std::chrono::microseconds( + run_duration_distribution(random_number_generator)); + auto end_time = std::chrono::steady_clock::now() + run_duration; + uint64_t next_value = 0; + while (std::chrono::steady_clock::now() < end_time) { + if (!Produce(next_value++)) { + // The consumer thread interrupted this. + break; + } + } + { + std::unique_lock lock(mutex_); + state_changed_condition_.wait( + lock, [this] { return state_.consumer_thread_finished; }); + state_.producer_thread_running = false; + state_.producer_thread_finished = true; + state_changed_condition_.notify_all(); + } + } + } + + bool Produce(uint64_t value) { + std::string hex_value = base::StringPrintf("0x%08" PRIx64, value); + if (!state_.ring_buffer_annotation.Push( + hex_value.data(), static_cast(hex_value.size()))) { + fprintf(stderr, + "Ignoring failed call to Push(0x%" PRIx64 + ") (ScopedSpinGuard was held by snapshot thread)\n", + value); + return false; + } + return true; + } + + void ConsumerThreadMain() { + while (true) { + { + std::unique_lock lock(mutex_); + state_changed_condition_.wait(lock, [this] { + return state_.should_exit || + (state_.ring_buffer_ready && state_.producer_thread_running); + }); + if (state_.should_exit) { + return; + } + state_.consumer_thread_finished = false; + state_changed_condition_.notify_all(); + } + auto min_run_duration_micros = + std::chrono::duration_cast( + params_.consumer_thread_min_run_duration); + auto max_run_duration_micros = + std::chrono::duration_cast( + params_.consumer_thread_max_run_duration); + std::uniform_int_distribution + run_duration_distribution(min_run_duration_micros.count(), + max_run_duration_micros.count()); + static thread_local std::mt19937 random_number_generator; + auto run_duration = std::chrono::microseconds( + run_duration_distribution(random_number_generator)); + auto end_time = std::chrono::steady_clock::now() + run_duration; + while (std::chrono::steady_clock::now() < end_time) { + constexpr uint64_t kSleepTimeNs = 10000; // 10 us + SleepNanoseconds(kSleepTimeNs); + } + Snapshot(); + { + std::unique_lock lock(mutex_); + state_.consumer_thread_finished = true; + state_.ring_buffer_ready = false; + state_changed_condition_.notify_all(); + } + } + } + + void Snapshot() { + int64_t timeout_ns = static_cast( + std::chrono::duration_cast( + params_.quiesce_timeout) + .count()); + uint8_t serialized_ring_buffer[sizeof(state_.ring_buffer_annotation)]; + Annotation::ValueSizeType ring_buffer_size; + { + std::optional scoped_spin_guard; + if (params_.mode == + RingBufferAnnotationSnapshotParams::Mode::kUseScopedSpinGuard) { + scoped_spin_guard = + state_.ring_buffer_annotation.TryCreateScopedSpinGuard(timeout_ns); + } + if (params_.mode == + RingBufferAnnotationSnapshotParams::Mode::kUseScopedSpinGuard && + !scoped_spin_guard) { + fprintf(stderr, + "Could not quiesce writes within %" PRIi64 " ns\n", + timeout_ns); + abort(); + } + ring_buffer_size = state_.ring_buffer_annotation.size(); + memcpy(&serialized_ring_buffer[0], + state_.ring_buffer_annotation.value(), + ring_buffer_size); + } + RingBufferData ring_buffer; + if (!ring_buffer.DeserializeFromBuffer(serialized_ring_buffer, + ring_buffer_size)) { + fprintf(stderr, "Could not deserialize ring buffer\n"); + abort(); + } + LengthDelimitedRingBufferReader ring_buffer_reader(ring_buffer); + int value = std::numeric_limits::max(); + std::vector bytes; + while (ring_buffer_reader.Pop(bytes)) { + int next_value; + base::StringPiece str(reinterpret_cast(&bytes[0]), + bytes.size()); + if (!HexStringToInt(str, &next_value)) { + fprintf( + stderr, "Couldn't parse value: [%s]\n", str.as_string().c_str()); + abort(); + } + if (value == std::numeric_limits::max()) { + // First value in buffer. + } else if (value + 1 != next_value) { + fprintf(stderr, + "Expected value 0x%08x, got 0x%08x\n", + value + 1, + next_value); + abort(); + } + value = next_value; + bytes.clear(); + } + } + + const RingBufferAnnotationSnapshotParams params_; + Thread main_loop_thread_; + Thread producer_thread_; + Thread consumer_thread_; + std::mutex mutex_; + + // Fired whenever `state_` changes. + std::condition_variable state_changed_condition_; + + // Protected by `mutex_`. + State state_; +}; + +void Usage(const base::FilePath& me) { + // clang-format off + fprintf(stderr, +"Usage: %" PRFilePath " [OPTION]...\n" +"Runs a load test for concurrent I/O to RingBufferAnnotation.\n" +"\n" +"By default, enables the annotation spin guard and runs indefinitely\n" +"until interrupted (e.g., with Control-C or SIGINT).\n" +"\n" +" -d,--disable-spin-guard Disables the annotation spin guard\n" +" (the test is expected to crash in this case)\n" +" -n,--num-loops=N Runs the test for N iterations, not indefinitely\n" +" -s,--duration-secs=SECS Runs the test for SECS seconds, not indefinitely\n", + me.value().c_str()); + // clang-format on + ToolSupport::UsageTail(me); +} + +int TestMain(int argc, char** argv) { + const base::FilePath argv0( + ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); + const base::FilePath me(argv0.BaseName()); + +#if BUILDFLAG(IS_WIN) + auto handler_routine = [](DWORD type) -> BOOL { + if (type == CTRL_C_EVENT) { + g_should_exit = true; + return TRUE; + } + return FALSE; + }; + if (!SetConsoleCtrlHandler(handler_routine, /*Add=*/TRUE)) { + fprintf(stderr, "Couldn't set Control-C handler\n"); + return EXIT_FAILURE; + } +#else + signal(SIGINT, [](int signal) { g_should_exit = true; }); +#endif // BUILDFLAG(IS_WIN) + RingBufferAnnotationSnapshotParams params; + enum OptionFlags { + // "Short" (single-character) options. + kOptionDisableSpinGuard = 'd', + kOptionNumLoops = 'n', + kOptionDurationSecs = 's', + + // Standard options. + kOptionHelp = -2, + kOptionVersion = -3, + }; + static constexpr option long_options[] = { + {"disable-spin-guard", no_argument, nullptr, kOptionDisableSpinGuard}, + {"num-loops", required_argument, nullptr, kOptionNumLoops}, + {"duration-secs", required_argument, nullptr, kOptionDurationSecs}, + {"help", no_argument, nullptr, kOptionHelp}, + {"version", no_argument, nullptr, kOptionVersion}, + {nullptr, 0, nullptr, 0}, + }; + + int opt; + while ((opt = getopt_long(argc, argv, "dn:s:", long_options, nullptr)) != + -1) { + switch (opt) { + case kOptionDisableSpinGuard: + printf("Disabling spin guard logic (this test will fail!)\n"); + params.mode = + RingBufferAnnotationSnapshotParams::Mode::kDoNotUseSpinGuard; + break; + case kOptionNumLoops: { + std::string num_loops(optarg); + uint64_t num_loops_value; + if (!StringToNumber(num_loops, &num_loops_value)) { + ToolSupport::UsageHint(me, "--num-loops requires integer value"); + return EXIT_FAILURE; + } + params.num_loops = num_loops_value; + break; + } + case kOptionDurationSecs: { + std::string duration_secs(optarg); + uint64_t duration_secs_value; + if (!StringToNumber(duration_secs, &duration_secs_value)) { + ToolSupport::UsageHint(me, "--duration-secs requires integer value"); + return EXIT_FAILURE; + } + params.main_thread_run_duration = + std::chrono::seconds(duration_secs_value); + break; + } + case kOptionHelp: + Usage(me); + return EXIT_SUCCESS; + case kOptionVersion: + ToolSupport::Version(me); + return EXIT_SUCCESS; + default: + ToolSupport::UsageHint(me, nullptr); + return EXIT_FAILURE; + } + } + + RingBufferAnnotationSnapshot<8192> test_producer_snapshot(params); + printf("Starting test (Control-C to exit)...\n"); + test_producer_snapshot.Start(); + test_producer_snapshot.Stop(); + printf("Test finished.\n"); + return EXIT_SUCCESS; +} + +} // namespace +} // namespace test +} // namespace crashpad + +#if BUILDFLAG(IS_POSIX) + +int main(int argc, char** argv) { + return crashpad::test::TestMain(argc, argv); +} + +#elif BUILDFLAG(IS_WIN) + +int wmain(int argc, wchar_t* argv[]) { + return crashpad::ToolSupport::Wmain(argc, argv, crashpad::test::TestMain); +} + +#endif diff --git a/thirdparty/sentry-native/external/crashpad/client/ring_buffer_annotation_test.cc b/thirdparty/sentry-native/external/crashpad/client/ring_buffer_annotation_test.cc new file mode 100644 index 0000000000..0893470ee0 --- /dev/null +++ b/thirdparty/sentry-native/external/crashpad/client/ring_buffer_annotation_test.cc @@ -0,0 +1,188 @@ +// Copyright 2023 The Crashpad Authors +// +// 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 of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "client/ring_buffer_annotation.h" +#include "client/length_delimited_ring_buffer.h" + +#include +#include + +#include "client/annotation_list.h" +#include "client/crashpad_info.h" +#include "gtest/gtest.h" +#include "test/gtest_death.h" + +namespace crashpad { +namespace test { +namespace { + +constexpr uint32_t kRingBufferHeaderSize = 16; +constexpr uint32_t kLengthDelimiter1ByteSize = 1; + +class RingBufferAnnotationTest : public testing::Test { + public: + void SetUp() override { + CrashpadInfo::GetCrashpadInfo()->set_annotations_list(&annotations_); + } + + void TearDown() override { + CrashpadInfo::GetCrashpadInfo()->set_annotations_list(nullptr); + } + + size_t AnnotationsCount() { + size_t result = 0; + for (auto* annotation : annotations_) { + if (annotation->is_set()) + ++result; + } + return result; + } + + protected: + AnnotationList annotations_; +}; + +TEST_F(RingBufferAnnotationTest, Basics) { + constexpr Annotation::Type kType = Annotation::UserDefinedType(1); + + constexpr char kName[] = "annotation 1"; + RingBufferAnnotation annotation(kType, kName); + + EXPECT_FALSE(annotation.is_set()); + EXPECT_EQ(0u, AnnotationsCount()); + + EXPECT_EQ(kType, annotation.type()); + EXPECT_EQ(0u, annotation.size()); + EXPECT_EQ(std::string(kName), annotation.name()); + + EXPECT_TRUE( + annotation.Push(reinterpret_cast("0123456789"), 10)); + + EXPECT_TRUE(annotation.is_set()); + EXPECT_EQ(1u, AnnotationsCount()); + + constexpr Annotation::ValueSizeType kExpectedSize = + kRingBufferHeaderSize + kLengthDelimiter1ByteSize + 10u; + EXPECT_EQ(kExpectedSize, annotation.size()); + EXPECT_EQ(&annotation, *annotations_.begin()); + + RingBufferData data; + EXPECT_TRUE( + data.DeserializeFromBuffer(annotation.value(), annotation.size())); + EXPECT_EQ(kExpectedSize, data.GetRingBufferLength()); + + std::vector popped_value; + LengthDelimitedRingBufferReader reader(data); + EXPECT_TRUE(reader.Pop(popped_value)); + + const std::vector expected = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + EXPECT_EQ(expected, popped_value); + + annotation.Clear(); + + EXPECT_FALSE(annotation.is_set()); + EXPECT_EQ(0u, AnnotationsCount()); + + EXPECT_EQ(0u, annotation.size()); +} + +TEST_F(RingBufferAnnotationTest, MultiplePushesWithoutWrapping) { + constexpr Annotation::Type kType = Annotation::UserDefinedType(1); + + constexpr char kName[] = "annotation 1"; + RingBufferAnnotation annotation(kType, kName); + + EXPECT_TRUE( + annotation.Push(reinterpret_cast("0123456789"), 10)); + EXPECT_TRUE(annotation.Push(reinterpret_cast("ABCDEF"), 6)); + + EXPECT_TRUE(annotation.is_set()); + EXPECT_EQ(1u, AnnotationsCount()); + + constexpr Annotation::ValueSizeType kExpectedSize = + kRingBufferHeaderSize + kLengthDelimiter1ByteSize + 10u + + kLengthDelimiter1ByteSize + 6u; + EXPECT_EQ(kExpectedSize, annotation.size()); + EXPECT_EQ(&annotation, *annotations_.begin()); + + RingBufferData data; + EXPECT_TRUE( + data.DeserializeFromBuffer(annotation.value(), annotation.size())); + EXPECT_EQ(kExpectedSize, data.GetRingBufferLength()); + + std::vector popped_value; + LengthDelimitedRingBufferReader reader(data); + EXPECT_TRUE(reader.Pop(popped_value)); + + const std::vector expected1 = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + EXPECT_EQ(expected1, popped_value); + + popped_value.clear(); + EXPECT_TRUE(reader.Pop(popped_value)); + + const std::vector expected2 = {'A', 'B', 'C', 'D', 'E', 'F'}; + EXPECT_EQ(expected2, popped_value); +} + +TEST_F(RingBufferAnnotationTest, + MultiplePushCallsWithWrappingShouldOverwriteInFIFOOrder) { + constexpr Annotation::Type kType = Annotation::UserDefinedType(1); + + constexpr char kName[] = "annotation 1"; + RingBufferAnnotation<10> annotation(kType, kName); + + // Each Push() call will push 1 byte for the varint 128-encoded length, + // then the number of bytes specified. + constexpr char kFirst[] = "AAA"; + constexpr char kSecond[] = "BBB"; + constexpr char kThird[] = "CCC"; + + // This takes up bytes 0-3 of the 10-byte RingBufferAnnotation. + ASSERT_TRUE(annotation.Push(reinterpret_cast(kFirst), 3)); + + // This takes up bytes 4-7 of the 10-byte RingBufferAnnotation. + ASSERT_TRUE(annotation.Push(reinterpret_cast(kSecond), 3)); + + // This should wrap around the end of the array and overwrite kFirst since it + // needs 4 bytes but there are only 2 left. + ASSERT_TRUE(annotation.Push(reinterpret_cast(kThird), 3)); + + // The size of the annotation should include the header and the full 10 bytes + // of the ring buffer, since the third write wrapped around the end. + ASSERT_EQ(kRingBufferHeaderSize + 10u, annotation.size()); + + // This data size needs to match the size in the RingBufferAnnotation above. + RingBufferData<10> data; + ASSERT_TRUE( + data.DeserializeFromBuffer(annotation.value(), annotation.size())); + + std::vector popped_value; + LengthDelimitedRingBufferReader reader(data); + ASSERT_TRUE(reader.Pop(popped_value)); + + // "AAA" has been overwritten, so the first thing popped should be "BBB". + const std::vector expected_b = {'B', 'B', 'B'}; + EXPECT_EQ(expected_b, popped_value); + + popped_value.clear(); + ASSERT_TRUE(reader.Pop(popped_value)); + const std::vector expected_c = {'C', 'C', 'C'}; + EXPECT_EQ(expected_c, popped_value); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/thirdparty/sentry-native/external/crashpad/compat/mingw/dbghelp.h b/thirdparty/sentry-native/external/crashpad/compat/mingw/dbghelp.h index b492198485..a7fdb4ef4e 100644 --- a/thirdparty/sentry-native/external/crashpad/compat/mingw/dbghelp.h +++ b/thirdparty/sentry-native/external/crashpad/compat/mingw/dbghelp.h @@ -17,6 +17,7 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgnu-include-next" +#pragma clang diagnostic ignored "-Wzero-length-array" #include_next #include @@ -329,6 +330,36 @@ typedef struct MINIDUMP_MISC_INFO_5 MINIDUMP_MISC_INFO_N; #endif +#ifdef __cplusplus +extern "C" { +#endif + +//! \brief Contains the name of the thread with the given thread ID. +struct __attribute__((packed, aligned(4))) MINIDUMP_THREAD_NAME { + //! \brief The identifier of the thread. + uint32_t ThreadId; + + //! \brief RVA64 of a MINIDUMP_STRING containing the name of the thread. + RVA64 RvaOfThreadName; +}; + +//! \brief Variable-sized struct which contains a list of MINIDUMP_THREAD_NAME +//! structs. +struct __attribute__((packed, aligned(4))) MINIDUMP_THREAD_NAME_LIST { + //! \brief The number of MINIDUMP_THREAD_NAME structs following this field. + uint32_t NumberOfThreadNames; + + //! \brief A variably-sized array containing zero of more + //! MINIDUMP_THREAD_NAME. + //! The length of the array is indicated by the NumberOfThreadNames field + //! in this struct. + struct MINIDUMP_THREAD_NAME ThreadNames[0]; +}; + +#ifdef __cplusplus +} +#endif + #pragma clang diagnostic pop #endif // CRASHPAD_COMPAT_MINGW_DBGHELP_H_ diff --git a/thirdparty/sentry-native/external/crashpad/compat/mingw/werapi.h b/thirdparty/sentry-native/external/crashpad/compat/mingw/werapi.h new file mode 100644 index 0000000000..2007a05384 --- /dev/null +++ b/thirdparty/sentry-native/external/crashpad/compat/mingw/werapi.h @@ -0,0 +1,28 @@ +// Copyright 2015 The Crashpad Authors. All rights reserved. +// +// 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 of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_COMPAT_MINGW_WERAPI_H_ +#define CRASHPAD_COMPAT_MINGW_WERAPI_H_ + +typedef HANDLE HREPORT; + +#ifndef WER_MAX_PREFERRED_MODULES_BUFFER +#define WER_MAX_PREFERRED_MODULES_BUFFER 256 +#endif + +#define PWER_SUBMIT_RESULT WER_SUBMIT_RESULT* + +#include_next + +#endif // CRASHPAD_COMPAT_MINGW_WERAPI_H_ diff --git a/thirdparty/sentry-native/external/crashpad/compat/mingw/winnt.h b/thirdparty/sentry-native/external/crashpad/compat/mingw/winnt.h index 268af1b3bc..44216d7851 100644 --- a/thirdparty/sentry-native/external/crashpad/compat/mingw/winnt.h +++ b/thirdparty/sentry-native/external/crashpad/compat/mingw/winnt.h @@ -57,4 +57,16 @@ struct PROCESSOR_POWER_INFORMATION { #define PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64 13 #endif +#include + +#ifdef __cplusplus +extern "C" { +#endif + +WINBASEAPI HRESULT WINAPI GetThreadDescription(HANDLE,PWSTR *); + +#ifdef __cplusplus +} +#endif + #endif // CRASHPAD_COMPAT_MINGW_WINNT_H_ diff --git a/thirdparty/sentry-native/external/crashpad/handler/CMakeLists.txt b/thirdparty/sentry-native/external/crashpad/handler/CMakeLists.txt index 8fe882ac89..0e5851c099 100644 --- a/thirdparty/sentry-native/external/crashpad/handler/CMakeLists.txt +++ b/thirdparty/sentry-native/external/crashpad/handler/CMakeLists.txt @@ -137,9 +137,11 @@ if(CRASHPAD_WER_ENABLED) target_link_libraries(crashpad_wer PRIVATE $ + $ ) set_property(TARGET crashpad_wer PROPERTY EXPORT_NAME crashpad_wer) + set_property(TARGET crashpad_wer PROPERTY PREFIX "") # ensure MINGW doesn't prefix "lib" to dll name add_library(crashpad::wer ALIAS crashpad_wer) install(TARGETS crashpad_wer EXPORT crashpad_export diff --git a/thirdparty/sentry-native/external/crashpad/handler/win/wer/crashpad_wer.cc b/thirdparty/sentry-native/external/crashpad/handler/win/wer/crashpad_wer.cc index 3379d00d2d..1394e203a0 100644 --- a/thirdparty/sentry-native/external/crashpad/handler/win/wer/crashpad_wer.cc +++ b/thirdparty/sentry-native/external/crashpad/handler/win/wer/crashpad_wer.cc @@ -102,7 +102,8 @@ bool ProcessException(const DWORD* handled_exceptions, break; } } - if (!found) + // If num_handled_exceptions == 0, all exceptions should be passed on. + if (!found && num_handled_exceptions != 0) return false; // Grab out the handles to the crashpad server. diff --git a/thirdparty/sentry-native/external/crashpad/minidump/minidump_crashpad_info_writer.cc b/thirdparty/sentry-native/external/crashpad/minidump/minidump_crashpad_info_writer.cc index 63e64453ae..76206a812a 100644 --- a/thirdparty/sentry-native/external/crashpad/minidump/minidump_crashpad_info_writer.cc +++ b/thirdparty/sentry-native/external/crashpad/minidump/minidump_crashpad_info_writer.cc @@ -20,6 +20,7 @@ #include "minidump/minidump_module_crashpad_info_writer.h" #include "minidump/minidump_simple_string_dictionary_writer.h" #include "snapshot/process_snapshot.h" +#include "snapshot/system_snapshot.h" #include "util/file/file_writer.h" namespace crashpad { @@ -30,6 +31,7 @@ MinidumpCrashpadInfoWriter::MinidumpCrashpadInfoWriter() simple_annotations_(nullptr), module_list_(nullptr) { crashpad_info_.version = MinidumpCrashpadInfo::kVersion; + crashpad_info_.reserved = 0; } MinidumpCrashpadInfoWriter::~MinidumpCrashpadInfoWriter() { @@ -56,6 +58,10 @@ void MinidumpCrashpadInfoWriter::InitializeFromSnapshot( SetSimpleAnnotations(std::move(simple_annotations)); } + if (process_snapshot->System()) { + SetAddressMask(process_snapshot->System()->AddressMask()); + } + auto modules = std::make_unique(); modules->InitializeFromSnapshot(process_snapshot->Modules()); @@ -90,6 +96,10 @@ void MinidumpCrashpadInfoWriter::SetModuleList( module_list_ = std::move(module_list); } +void MinidumpCrashpadInfoWriter::SetAddressMask(uint64_t mask) { + crashpad_info_.address_mask = mask; +} + bool MinidumpCrashpadInfoWriter::Freeze() { DCHECK_EQ(state(), kStateMutable); diff --git a/thirdparty/sentry-native/external/crashpad/minidump/minidump_crashpad_info_writer.h b/thirdparty/sentry-native/external/crashpad/minidump/minidump_crashpad_info_writer.h index ac69e4544a..02907cc844 100644 --- a/thirdparty/sentry-native/external/crashpad/minidump/minidump_crashpad_info_writer.h +++ b/thirdparty/sentry-native/external/crashpad/minidump/minidump_crashpad_info_writer.h @@ -86,6 +86,9 @@ class MinidumpCrashpadInfoWriter final : public internal::MinidumpStreamWriter { void SetModuleList( std::unique_ptr module_list); + //! \brief Sets MinidumpCrashpadInfo::address_mask. + void SetAddressMask(uint64_t mask); + //! \brief Determines whether the object is useful. //! //! A useful object is one that carries data that makes a meaningful diff --git a/thirdparty/sentry-native/external/crashpad/minidump/minidump_crashpad_info_writer_test.cc b/thirdparty/sentry-native/external/crashpad/minidump/minidump_crashpad_info_writer_test.cc index d784deaf54..39c791c2ef 100644 --- a/thirdparty/sentry-native/external/crashpad/minidump/minidump_crashpad_info_writer_test.cc +++ b/thirdparty/sentry-native/external/crashpad/minidump/minidump_crashpad_info_writer_test.cc @@ -122,6 +122,59 @@ TEST(MinidumpCrashpadInfoWriter, ReportAndClientID) { EXPECT_FALSE(module_list); } +TEST(MinidumpCrashpadInfoWriter, AddressMask) { + MinidumpFileWriter minidump_file_writer; + auto crashpad_info_writer = std::make_unique(); + + constexpr uint64_t mask = 0xFFFFFF8000000000; + crashpad_info_writer->SetAddressMask(mask); + + ASSERT_TRUE(minidump_file_writer.AddStream(std::move(crashpad_info_writer))); + + StringFile string_file; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); + + const MinidumpCrashpadInfo* crashpad_info = nullptr; + const MinidumpSimpleStringDictionary* simple_annotations = nullptr; + const MinidumpModuleCrashpadInfoList* module_list = nullptr; + + ASSERT_NO_FATAL_FAILURE(GetCrashpadInfoStream( + string_file.string(), &crashpad_info, &simple_annotations, &module_list)); + + UUID empty_report_id; + ASSERT_TRUE(empty_report_id.InitializeFromString( + "00000000-0000-0000-0000-000000000000")); + UUID empty_client_id; + ASSERT_TRUE(empty_client_id.InitializeFromString( + "00000000-0000-0000-0000-000000000000")); + + EXPECT_EQ(crashpad_info->version, MinidumpCrashpadInfo::kVersion); + EXPECT_EQ(crashpad_info->address_mask, mask); + EXPECT_EQ(crashpad_info->report_id, empty_report_id); + EXPECT_EQ(crashpad_info->client_id, empty_client_id); + EXPECT_FALSE(simple_annotations); + EXPECT_FALSE(module_list); +} + +TEST(MinidumpCrashpadInfoWriter, EmptyAddressMask) { + MinidumpFileWriter minidump_file_writer; + auto crashpad_info_writer = std::make_unique(); + + ASSERT_TRUE(minidump_file_writer.AddStream(std::move(crashpad_info_writer))); + + StringFile string_file; + ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); + + const MinidumpCrashpadInfo* crashpad_info = nullptr; + const MinidumpSimpleStringDictionary* simple_annotations = nullptr; + const MinidumpModuleCrashpadInfoList* module_list = nullptr; + + ASSERT_NO_FATAL_FAILURE(GetCrashpadInfoStream( + string_file.string(), &crashpad_info, &simple_annotations, &module_list)); + + EXPECT_EQ(crashpad_info->address_mask, 0UL); +} + TEST(MinidumpCrashpadInfoWriter, SimpleAnnotations) { MinidumpFileWriter minidump_file_writer; auto crashpad_info_writer = std::make_unique(); diff --git a/thirdparty/sentry-native/external/crashpad/minidump/minidump_extensions.h b/thirdparty/sentry-native/external/crashpad/minidump/minidump_extensions.h index 588eb89d81..951ada3952 100644 --- a/thirdparty/sentry-native/external/crashpad/minidump/minidump_extensions.h +++ b/thirdparty/sentry-native/external/crashpad/minidump/minidump_extensions.h @@ -452,8 +452,9 @@ struct ALIGNAS(4) PACKED MinidumpCrashpadInfo { report_id(), client_id(), simple_annotations(), - module_list() { - } + module_list(), + reserved(), + address_mask() {} //! \brief The structure’s currently-defined version number. //! @@ -507,6 +508,28 @@ struct ALIGNAS(4) PACKED MinidumpCrashpadInfo { //! //! This field is present when #version is at least `1`. MINIDUMP_LOCATION_DESCRIPTOR module_list; + + //! \brief This field is always `0`. + uint32_t reserved; + + //! \brief A mask indicating the range of valid addresses for a pointer. + //! + //! ARM64 supports MTE, TBI and PAC masking, generally in the upper bits of + //! a pointer. This mask can be used by LLDB to mimic ptrauth_strip and strip + //! the pointer authentication codes. To recover `pointer` in userland on + //! Darwin, `pointer & (~mask)`. In the case of code running in high memory, + //! where bit 55 is set (indicating that all of the high bits should be set + //! to 1), `pointer | mask`. See ABIMacOSX_arm64::FixAddress for more details + //! here: + //! https://github.com/llvm/llvm-project/blob/001d18664f8bcf63af64f10688809f7681dfbf0b/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp#L817-L830 + //! + //! If the platform does not support pointer authentication, or the range of + //! valid addressees for a pointer was inaccessible, this field will be 0 and + //! should be ignored. + //! + //! This field is present when #version is at least `1`, if the size of the + //! structure is large enough to accommodate it. + uint64_t address_mask; }; #if defined(COMPILER_MSVC) diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/BUILD.gn b/thirdparty/sentry-native/external/crashpad/snapshot/BUILD.gn index 09a3f78a47..9ffdb47bc5 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/BUILD.gn +++ b/thirdparty/sentry-native/external/crashpad/snapshot/BUILD.gn @@ -505,6 +505,10 @@ crashpad_loadable_module("crashpad_snapshot_test_module") { "$mini_chromium_source_parent:base", "../client", ] + if (crashpad_is_in_fuchsia) { + # TODO(fxbug.dev/108368): Remove this once the underlying issue is addressed. + exclude_toolchain_tags = [ "hwasan" ] + } } crashpad_loadable_module("crashpad_snapshot_test_module_large") { @@ -519,6 +523,11 @@ crashpad_loadable_module("crashpad_snapshot_test_module_large") { defines = [ "CRASHPAD_INFO_SIZE_TEST_MODULE_LARGE" ] deps += [ "$mini_chromium_source_parent:base" ] + + if (crashpad_is_in_fuchsia) { + # TODO(fxbug.dev/108368): Remove this once the underlying issue is addressed. + exclude_toolchain_tags = [ "hwasan" ] + } } crashpad_loadable_module("crashpad_snapshot_test_module_small") { @@ -533,6 +542,11 @@ crashpad_loadable_module("crashpad_snapshot_test_module_small") { defines = [ "CRASHPAD_INFO_SIZE_TEST_MODULE_SMALL" ] deps += [ "$mini_chromium_source_parent:base" ] + + if (crashpad_is_in_fuchsia) { + # TODO(fxbug.dev/108368): Remove this once the underlying issue is addressed. + exclude_toolchain_tags = [ "hwasan" ] + } } if ((crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) && @@ -543,6 +557,11 @@ if ((crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) && # This makes `ld` emit both .hash and .gnu.hash sections. ldflags = [ "-Wl,--hash-style=both" ] + + if (crashpad_is_in_fuchsia) { + # TODO(fxbug.dev/108368): Remove this once the underlying issue is addressed. + exclude_toolchain_tags = [ "hwasan" ] + } } } diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/CMakeLists.txt b/thirdparty/sentry-native/external/crashpad/snapshot/CMakeLists.txt index f83f4b417d..ccaaef67c1 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/CMakeLists.txt +++ b/thirdparty/sentry-native/external/crashpad/snapshot/CMakeLists.txt @@ -223,6 +223,17 @@ if(WIN32) "-Wno-unknown-attributes" ) endif() + + if (MINGW OR ("${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}" STREQUAL "") OR (CMAKE_SYSTEM_VERSION LESS 10)) + # Define NTDDI_VERSION >= NTDDI_WIN10_RS5 - so InitializeContext2 definition is always available in process_reader_win.cc + # NTDDI_WIN10_RS5 = 0x0A000006 /* ABRACADABRA_WIN10_RS5 */ + set_property( + SOURCE "win/process_reader_win.cc" + APPEND + PROPERTY COMPILE_DEFINITIONS + WINVER=0x0A00 _WIN32_WINNT=0x0A00 NTDDI_VERSION=0x0A000006 + ) + endif() endif() if(APPLE AND NOT IOS AND CRASHPAD_ENABLE_STACKTRACE) diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/crashpad_types/image_annotation_reader.cc b/thirdparty/sentry-native/external/crashpad/snapshot/crashpad_types/image_annotation_reader.cc index fd90fbd77e..b95a8a8b36 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/crashpad_types/image_annotation_reader.cc +++ b/thirdparty/sentry-native/external/crashpad/snapshot/crashpad_types/image_annotation_reader.cc @@ -26,7 +26,11 @@ #include "client/annotation_list.h" #include "client/simple_string_dictionary.h" #include "snapshot/snapshot_constants.h" +#if BUILDFLAG(IS_FUCHSIA) +#include "util/fuchsia/traits.h" +#else #include "util/linux/traits.h" +#endif namespace crashpad { @@ -39,6 +43,8 @@ struct Annotation { typename Traits::Address value; uint32_t size; uint16_t type; + crashpad::Annotation::ConcurrentAccessGuardMode concurrent_access_guard_mode; + bool spin_guard_state; }; template diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/fuchsia/system_snapshot_fuchsia.h b/thirdparty/sentry-native/external/crashpad/snapshot/fuchsia/system_snapshot_fuchsia.h index efbe19bdb5..3d545bb4b4 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/fuchsia/system_snapshot_fuchsia.h +++ b/thirdparty/sentry-native/external/crashpad/snapshot/fuchsia/system_snapshot_fuchsia.h @@ -73,6 +73,8 @@ class SystemSnapshotFuchsia final : public SystemSnapshot { int* daylight_offset_seconds, std::string* standard_name, std::string* daylight_name) const override; + uint64_t AddressMask() const override { return 0; } + private: std::string os_version_full_; const timeval* snapshot_time_; // weak diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/ios/system_snapshot_ios_intermediate_dump.cc b/thirdparty/sentry-native/external/crashpad/snapshot/ios/system_snapshot_ios_intermediate_dump.cc index 324ec65e45..be676857c1 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/ios/system_snapshot_ios_intermediate_dump.cc +++ b/thirdparty/sentry-native/external/crashpad/snapshot/ios/system_snapshot_ios_intermediate_dump.cc @@ -57,6 +57,7 @@ SystemSnapshotIOSIntermediateDump::SystemSnapshotIOSIntermediateDump() daylight_offset_seconds_(0), standard_name_(), daylight_name_(), + address_mask_(0), initialized_() {} SystemSnapshotIOSIntermediateDump::~SystemSnapshotIOSIntermediateDump() {} @@ -97,6 +98,8 @@ void SystemSnapshotIOSIntermediateDump::Initialize( dst_status_ = SystemSnapshot::kDoesNotObserveDaylightSavingTime; } + GetDataValueFromMap(system_data, Key::kAddressMask, &address_mask_); + vm_size_t page_size; if (GetDataValueFromMap(system_data, Key::kPageSize, &page_size)) { const IOSIntermediateDumpMap* vm_stat = @@ -241,5 +244,10 @@ void SystemSnapshotIOSIntermediateDump::TimeZone( daylight_name->assign(daylight_name_); } +uint64_t SystemSnapshotIOSIntermediateDump::AddressMask() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return address_mask_; +} + } // namespace internal } // namespace crashpad diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/ios/system_snapshot_ios_intermediate_dump.h b/thirdparty/sentry-native/external/crashpad/snapshot/ios/system_snapshot_ios_intermediate_dump.h index 4c9ef11898..6cc09ac78d 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/ios/system_snapshot_ios_intermediate_dump.h +++ b/thirdparty/sentry-native/external/crashpad/snapshot/ios/system_snapshot_ios_intermediate_dump.h @@ -73,6 +73,7 @@ class SystemSnapshotIOSIntermediateDump final : public SystemSnapshot { int* daylight_offset_seconds, std::string* standard_name, std::string* daylight_name) const override; + uint64_t AddressMask() const override; private: std::string os_version_build_; @@ -91,6 +92,7 @@ class SystemSnapshotIOSIntermediateDump final : public SystemSnapshot { int daylight_offset_seconds_; std::string standard_name_; std::string daylight_name_; + uint64_t address_mask_; InitializationStateDcheck initialized_; }; diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/linux/system_snapshot_linux.h b/thirdparty/sentry-native/external/crashpad/snapshot/linux/system_snapshot_linux.h index 4b45a451c4..75dea39e0d 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/linux/system_snapshot_linux.h +++ b/thirdparty/sentry-native/external/crashpad/snapshot/linux/system_snapshot_linux.h @@ -89,6 +89,7 @@ class SystemSnapshotLinux final : public SystemSnapshot { int* daylight_offset_seconds, std::string* standard_name, std::string* daylight_name) const override; + uint64_t AddressMask() const override { return 0; } private: void ReadKernelVersion(const std::string& version_string); diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/mac/mach_o_image_annotations_reader.cc b/thirdparty/sentry-native/external/crashpad/snapshot/mac/mach_o_image_annotations_reader.cc index 1997724102..ec33779b98 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/mac/mach_o_image_annotations_reader.cc +++ b/thirdparty/sentry-native/external/crashpad/snapshot/mac/mach_o_image_annotations_reader.cc @@ -71,6 +71,13 @@ void MachOImageAnnotationsReader::ReadCrashReporterClientAnnotations( const process_types::section* crash_info_section = image_reader_->GetSectionByName( SEG_DATA, "__crash_info", &crash_info_address); + + if (!crash_info_section) { + // On macOS 13, under some circumstances, `__crash_info` ends up in the + // `__DATA_DIRTY` segment. This is known to happen for `dyld`. + crash_info_section = image_reader_->GetSectionByName( + "__DATA_DIRTY", "__crash_info", &crash_info_address); + } if (!crash_info_section) { return; } diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/mac/system_snapshot_mac.cc b/thirdparty/sentry-native/external/crashpad/snapshot/mac/system_snapshot_mac.cc index 00d777e484..3b17252d94 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/mac/system_snapshot_mac.cc +++ b/thirdparty/sentry-native/external/crashpad/snapshot/mac/system_snapshot_mac.cc @@ -390,5 +390,19 @@ void SystemSnapshotMac::TimeZone(DaylightSavingTimeStatus* dst_status, daylight_name); } +uint64_t SystemSnapshotMac::AddressMask() const { + uint64_t mask = 0; +#if defined(ARCH_CPU_ARM64) + // `machdep.virtual_address_size` is the number of addressable bits in + // userspace virtual addresses + uint8_t addressable_bits = + CastIntSysctlByName("machdep.virtual_address_size", 0); + if (addressable_bits) { + mask = ~((1UL << addressable_bits) - 1); + } +#endif + return mask; +} + } // namespace internal } // namespace crashpad diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/mac/system_snapshot_mac.h b/thirdparty/sentry-native/external/crashpad/snapshot/mac/system_snapshot_mac.h index 047ad2b7d3..cf8fbbe925 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/mac/system_snapshot_mac.h +++ b/thirdparty/sentry-native/external/crashpad/snapshot/mac/system_snapshot_mac.h @@ -83,6 +83,7 @@ class SystemSnapshotMac final : public SystemSnapshot { int* daylight_offset_seconds, std::string* standard_name, std::string* daylight_name) const override; + uint64_t AddressMask() const override; private: std::string os_version_full_; diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/minidump/process_snapshot_minidump.cc b/thirdparty/sentry-native/external/crashpad/snapshot/minidump/process_snapshot_minidump.cc index 04fc27118a..e88a2646cd 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/minidump/process_snapshot_minidump.cc +++ b/thirdparty/sentry-native/external/crashpad/snapshot/minidump/process_snapshot_minidump.cc @@ -266,7 +266,10 @@ bool ProcessSnapshotMinidump::InitializeCrashpadInfo() { return true; } - if (stream_it->second->DataSize < sizeof(crashpad_info_)) { + constexpr size_t crashpad_info_min_size = + offsetof(decltype(crashpad_info_), reserved); + size_t remaining_data_size = stream_it->second->DataSize; + if (remaining_data_size < crashpad_info_min_size) { LOG(ERROR) << "crashpad_info size mismatch"; return false; } @@ -275,9 +278,34 @@ bool ProcessSnapshotMinidump::InitializeCrashpadInfo() { return false; } - if (!file_reader_->ReadExactly(&crashpad_info_, sizeof(crashpad_info_))) { + if (!file_reader_->ReadExactly(&crashpad_info_, crashpad_info_min_size)) { return false; } + remaining_data_size -= crashpad_info_min_size; + + // Read `reserved` if available. + size_t crashpad_reserved_size = sizeof(crashpad_info_.reserved); + if (remaining_data_size >= crashpad_reserved_size) { + if (!file_reader_->ReadExactly(&crashpad_info_.reserved, + crashpad_reserved_size)) { + return false; + } + remaining_data_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 (remaining_data_size >= crashpad_address_mask_size) { + if (!file_reader_->ReadExactly(&crashpad_info_.address_mask, + crashpad_address_mask_size)) { + return false; + } + remaining_data_size -= crashpad_address_mask_size; + } else { + crashpad_info_.address_mask = 0; + } if (crashpad_info_.version != MinidumpCrashpadInfo::kVersion) { LOG(ERROR) << "crashpad_info version mismatch"; diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc b/thirdparty/sentry-native/external/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc index 4069364154..00fc3f84d7 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/thirdparty/sentry-native/external/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc @@ -270,6 +270,47 @@ TEST(ProcessSnapshotMinidump, ClientID) { EXPECT_TRUE(process_snapshot.AnnotationsSimpleMap().empty()); } +TEST(ProcessSnapshotMinidump, ReadOldCrashpadInfo) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + UUID client_id; + ASSERT_TRUE( + client_id.InitializeFromString("0001f4a9-d00d-5155-0a55-c0ffeec0ffee")); + + MinidumpCrashpadInfo crashpad_info = {}; + crashpad_info.version = MinidumpCrashpadInfo::kVersion; + crashpad_info.client_id = client_id; + + MINIDUMP_DIRECTORY crashpad_info_directory = {}; + crashpad_info_directory.StreamType = kMinidumpStreamTypeCrashpadInfo; + crashpad_info_directory.Location.Rva = + static_cast(string_file.SeekGet()); + EXPECT_TRUE(string_file.Write(&crashpad_info, sizeof(crashpad_info) - 8)); + crashpad_info_directory.Location.DataSize = sizeof(crashpad_info) - 8; + + header.StreamDirectoryRva = static_cast(string_file.SeekGet()); + EXPECT_TRUE(string_file.Write(&crashpad_info_directory, + sizeof(crashpad_info_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 1; + EXPECT_TRUE(string_file.SeekSet(0)); + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + EXPECT_TRUE(process_snapshot.Initialize(&string_file)); + + UUID actual_client_id; + process_snapshot.ClientID(&actual_client_id); + EXPECT_EQ(actual_client_id, client_id); + + EXPECT_TRUE(process_snapshot.AnnotationsSimpleMap().empty()); +} + TEST(ProcessSnapshotMinidump, AnnotationsSimpleMap) { StringFile string_file; diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/minidump/system_snapshot_minidump.cc b/thirdparty/sentry-native/external/crashpad/snapshot/minidump/system_snapshot_minidump.cc index e6007b1e9c..abccda3187 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/minidump/system_snapshot_minidump.cc +++ b/thirdparty/sentry-native/external/crashpad/snapshot/minidump/system_snapshot_minidump.cc @@ -195,5 +195,11 @@ void SystemSnapshotMinidump::TimeZone(DaylightSavingTimeStatus* dst_status, NOTREACHED(); // https://crashpad.chromium.org/bug/10 } +uint64_t SystemSnapshotMinidump::AddressMask() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return 0; +} + } // namespace internal } // namespace crashpad diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/minidump/system_snapshot_minidump.h b/thirdparty/sentry-native/external/crashpad/snapshot/minidump/system_snapshot_minidump.h index 6b12ab990e..aff425821c 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/minidump/system_snapshot_minidump.h +++ b/thirdparty/sentry-native/external/crashpad/snapshot/minidump/system_snapshot_minidump.h @@ -74,6 +74,7 @@ class SystemSnapshotMinidump : public SystemSnapshot { int* daylight_offset_seconds, std::string* standard_name, std::string* daylight_name) const override; + uint64_t AddressMask() const override; private: MINIDUMP_SYSTEM_INFO minidump_system_info_; diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/system_snapshot.h b/thirdparty/sentry-native/external/crashpad/snapshot/system_snapshot.h index bec638cd1b..a1186edb4f 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/system_snapshot.h +++ b/thirdparty/sentry-native/external/crashpad/snapshot/system_snapshot.h @@ -275,6 +275,20 @@ class SystemSnapshot { int* daylight_offset_seconds, std::string* standard_name, std::string* daylight_name) const = 0; + + //! \brief Returns a mask indicating the range of valid addresses for a + //! pointer. + //! + //! ARM64 supports storing pointer authentication codes in the upper bits of + //! a pointer. This mask is generated based on the number of bits in a pointer + //! reserved for the authentication codes. To recover an address from pointer + //! with an authentication code, `AND` this mask with the pointer. If the pac + //! sign extension bit is set, instead `~` and `OR` this mask with the + //! pointer. + //! + //! If the platform does not support pointer authentication, or the range of + //! valid addressees for a pointer was inaccessible, this field will be 0. + virtual uint64_t AddressMask() const = 0; }; } // namespace crashpad diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/test/test_system_snapshot.cc b/thirdparty/sentry-native/external/crashpad/snapshot/test/test_system_snapshot.cc index 604375993a..a46bce12c3 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/test/test_system_snapshot.cc +++ b/thirdparty/sentry-native/external/crashpad/snapshot/test/test_system_snapshot.cc @@ -36,14 +36,14 @@ TestSystemSnapshot::TestSystemSnapshot() os_version_bugfix_(0), os_version_build_(), os_version_full_(), + address_mask_(0), nx_enabled_(false), machine_description_(), time_zone_dst_status_(kDoesNotObserveDaylightSavingTime), time_zone_standard_offset_seconds_(0), time_zone_daylight_offset_seconds_(0), time_zone_standard_name_(), - time_zone_daylight_name_() { -} + time_zone_daylight_name_() {} TestSystemSnapshot::~TestSystemSnapshot() { } @@ -130,5 +130,9 @@ void TestSystemSnapshot::TimeZone(DaylightSavingTimeStatus* dst_status, *daylight_name = time_zone_daylight_name_; } +uint64_t TestSystemSnapshot::AddressMask() const { + return address_mask_; +} + } // namespace test } // namespace crashpad diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/test/test_system_snapshot.h b/thirdparty/sentry-native/external/crashpad/snapshot/test/test_system_snapshot.h index fefe61fa9d..89cd8413fa 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/test/test_system_snapshot.h +++ b/thirdparty/sentry-native/external/crashpad/snapshot/test/test_system_snapshot.h @@ -90,6 +90,8 @@ class TestSystemSnapshot final : public SystemSnapshot { time_zone_daylight_name_ = daylight_name; } + void SetAddressMask(uint64_t mask) { address_mask_ = mask; } + // SystemSnapshot: CPUArchitecture GetCPUArchitecture() const override; @@ -114,6 +116,7 @@ class TestSystemSnapshot final : public SystemSnapshot { int* daylight_offset_seconds, std::string* standard_name, std::string* daylight_name) const override; + uint64_t AddressMask() const override; private: CPUArchitecture cpu_architecture_; @@ -134,6 +137,7 @@ class TestSystemSnapshot final : public SystemSnapshot { int os_version_bugfix_; std::string os_version_build_; std::string os_version_full_; + uint64_t address_mask_; bool nx_enabled_; std::string machine_description_; DaylightSavingTimeStatus time_zone_dst_status_; diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/win/process_reader_win.cc b/thirdparty/sentry-native/external/crashpad/snapshot/win/process_reader_win.cc index b9718beb88..7573a73509 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/win/process_reader_win.cc +++ b/thirdparty/sentry-native/external/crashpad/snapshot/win/process_reader_win.cc @@ -151,22 +151,20 @@ void DoStackWalk(ProcessReaderWin::Thread* thread, stack_frame.AddrStack.Mode = AddrModeFlat; int machine_type = IMAGE_FILE_MACHINE_I386; - LPVOID ctx = NULL; + CONTEXT ctx; #if defined(ARCH_CPU_X86) - const CONTEXT* ctx_ = thread->context.context(); - stack_frame.AddrPC.Offset = ctx_->Eip; - stack_frame.AddrFrame.Offset = ctx_->Ebp; - stack_frame.AddrStack.Offset = ctx_->Esp; - ctx = (LPVOID)ctx_; + ctx = *thread->context.context(); + stack_frame.AddrPC.Offset = ctx.Eip; + stack_frame.AddrFrame.Offset = ctx.Ebp; + stack_frame.AddrStack.Offset = ctx.Esp; #elif defined(ARCH_CPU_X86_64) // if (!is_64_reading_32) { machine_type = IMAGE_FILE_MACHINE_AMD64; - const CONTEXT* ctx_ = thread->context.context(); - stack_frame.AddrPC.Offset = ctx_->Rip; - stack_frame.AddrFrame.Offset = ctx_->Rbp; - stack_frame.AddrStack.Offset = ctx_->Rsp; - ctx = (LPVOID)ctx_; + ctx = *thread->context.context(); + stack_frame.AddrPC.Offset = ctx.Rip; + stack_frame.AddrFrame.Offset = ctx.Rbp; + stack_frame.AddrStack.Offset = ctx.Rsp; // } else { // const WOW64_CONTEXT* ctx_ = &thread->context.wow64; // stack_frame.AddrPC.Offset = ctx_->Eip; @@ -176,7 +174,7 @@ void DoStackWalk(ProcessReaderWin::Thread* thread, // } // TODO: we dont support this right away, maybe in the future -//#elif defined(ARCH_CPU_ARM64) +// #elif defined(ARCH_CPU_ARM64) // machine_type = IMAGE_FILE_MACHINE_ARM64; #else #error Unsupported Windows Arch @@ -192,7 +190,7 @@ void DoStackWalk(ProcessReaderWin::Thread* thread, process, thread_handle, &stack_frame, - ctx, + &ctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, diff --git a/thirdparty/sentry-native/external/crashpad/snapshot/win/system_snapshot_win.h b/thirdparty/sentry-native/external/crashpad/snapshot/win/system_snapshot_win.h index 6fbcd5737e..fbe2faec2f 100644 --- a/thirdparty/sentry-native/external/crashpad/snapshot/win/system_snapshot_win.h +++ b/thirdparty/sentry-native/external/crashpad/snapshot/win/system_snapshot_win.h @@ -79,6 +79,7 @@ class SystemSnapshotWin final : public SystemSnapshot { int* daylight_offset_seconds, std::string* standard_name, std::string* daylight_name) const override; + uint64_t AddressMask() const override { return 0; } private: std::string os_version_full_; diff --git a/thirdparty/sentry-native/external/crashpad/test/gtest_main.cc b/thirdparty/sentry-native/external/crashpad/test/gtest_main.cc index 605c6acca9..63f13c547d 100644 --- a/thirdparty/sentry-native/external/crashpad/test/gtest_main.cc +++ b/thirdparty/sentry-native/external/crashpad/test/gtest_main.cc @@ -35,7 +35,7 @@ #endif // BUILDFLAG(IS_WIN) #if defined(CRASHPAD_IS_IN_CHROMIUM) -#include "base/bind.h" +#include "base/functional/bind.h" #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" #endif // CRASHPAD_IS_IN_CHROMIUM diff --git a/thirdparty/sentry-native/external/crashpad/test/ios/BUILD.gn b/thirdparty/sentry-native/external/crashpad/test/ios/BUILD.gn index 1987b78247..c17f461c1b 100644 --- a/thirdparty/sentry-native/external/crashpad/test/ios/BUILD.gn +++ b/thirdparty/sentry-native/external/crashpad/test/ios/BUILD.gn @@ -70,6 +70,7 @@ source_set("xcuitests") { deps = [ "../../build:ios_enable_arc", "../../build:ios_xctest", + "../../client:common", "../../test/ios/host:app_shared_sources", "../../third_party/edo", "../../util", diff --git a/thirdparty/sentry-native/external/crashpad/test/ios/crash_type_xctest.mm b/thirdparty/sentry-native/external/crashpad/test/ios/crash_type_xctest.mm index e95760c729..8e32f11f70 100644 --- a/thirdparty/sentry-native/external/crashpad/test/ios/crash_type_xctest.mm +++ b/thirdparty/sentry-native/external/crashpad/test/ios/crash_type_xctest.mm @@ -15,8 +15,11 @@ #import #include +#include + #import "Service/Sources/EDOClientService.h" #include "build/build_config.h" +#include "client/length_delimited_ring_buffer.h" #import "test/ios/host/cptest_shared_object.h" #include "util/mach/exception_types.h" #include "util/mach/mach_extensions.h" @@ -322,6 +325,31 @@ isEqualToString:@"same-name 3"]); XCTAssertTrue([[dict[@"objects"][2] valueForKeyPath:@"#TEST# one"] isEqualToString:@"moocow"]); + // Ensure `ring_buffer` is present but not `busy_ring_buffer`. + XCTAssertEqual(1u, [dict[@"ringbuffers"] count]); + NSData* ringBufferNSData = + [dict[@"ringbuffers"][0] valueForKeyPath:@"#TEST# ring_buffer"]; + crashpad::RingBufferData ringBufferData; + XCTAssertTrue(ringBufferData.DeserializeFromBuffer(ringBufferNSData.bytes, + ringBufferNSData.length)); + crashpad::LengthDelimitedRingBufferReader reader(ringBufferData); + + std::vector ringBufferEntry; + XCTAssertTrue(reader.Pop(ringBufferEntry)); + NSString* firstEntry = [[NSString alloc] initWithBytes:ringBufferEntry.data() + length:ringBufferEntry.size() + encoding:NSUTF8StringEncoding]; + XCTAssertEqualObjects(firstEntry, @"hello"); + ringBufferEntry.clear(); + + XCTAssertTrue(reader.Pop(ringBufferEntry)); + NSString* secondEntry = [[NSString alloc] initWithBytes:ringBufferEntry.data() + length:ringBufferEntry.size() + encoding:NSUTF8StringEncoding]; + XCTAssertEqualObjects(secondEntry, @"goodbye"); + ringBufferEntry.clear(); + + XCTAssertFalse(reader.Pop(ringBufferEntry)); } - (void)testDumpWithoutCrash { diff --git a/thirdparty/sentry-native/external/crashpad/test/ios/host/cptest_application_delegate.mm b/thirdparty/sentry-native/external/crashpad/test/ios/host/cptest_application_delegate.mm index 0af106e74b..c2ee1949e5 100644 --- a/thirdparty/sentry-native/external/crashpad/test/ios/host/cptest_application_delegate.mm +++ b/thirdparty/sentry-native/external/crashpad/test/ios/host/cptest_application_delegate.mm @@ -38,6 +38,7 @@ #include "client/crash_report_database.h" #include "client/crashpad_client.h" #include "client/crashpad_info.h" +#include "client/ring_buffer_annotation.h" #include "client/simple_string_dictionary.h" #include "client/simulate_crash.h" #include "snapshot/minidump/process_snapshot_minidump.h" @@ -58,6 +59,9 @@ using Report = crashpad::CrashReportDatabase::Report; namespace { +constexpr crashpad::Annotation::Type kRingBufferType = + crashpad::Annotation::UserDefinedType(42); + base::FilePath GetDatabaseDir() { base::FilePath database_dir([NSFileManager.defaultManager URLsForDirectory:NSDocumentDirectory @@ -251,7 +255,8 @@ UIWindow* GetAnyWindow() { NSDictionary* dict = @{ @"simplemap" : [@{} mutableCopy], @"vector" : [@[] mutableCopy], - @"objects" : [@[] mutableCopy] + @"objects" : [@[] mutableCopy], + @"ringbuffers" : [@[] mutableCopy], }; for (const auto* module : process_snapshot->Modules()) { for (const auto& kv : module->AnnotationsSimpleMap()) { @@ -262,14 +267,18 @@ UIWindow* GetAnyWindow() { [dict[@"vector"] addObject:@(annotation.c_str())]; } for (const auto& annotation : module->AnnotationObjects()) { - if (annotation.type != + if (annotation.type == static_cast(crashpad::Annotation::Type::kString)) { - continue; + std::string value( + reinterpret_cast(annotation.value.data()), + annotation.value.size()); + [dict[@"objects"] + addObject:@{@(annotation.name.c_str()) : @(value.c_str())}]; + } else if (annotation.type == static_cast(kRingBufferType)) { + NSData* data = [NSData dataWithBytes:annotation.value.data() + length:annotation.value.size()]; + [dict[@"ringbuffers"] addObject:@{@(annotation.name.c_str()) : data}]; } - std::string value(reinterpret_cast(annotation.value.data()), - annotation.value.size()); - [dict[@"objects"] - addObject:@{@(annotation.name.c_str()) : @(value.c_str())}]; } } return [dict passByValue]; @@ -418,12 +427,23 @@ UIWindow* GetAnyWindow() { "#TEST# same-name"}; static crashpad::StringAnnotation<32> test_annotation_four{ "#TEST# same-name"}; + static crashpad::RingBufferAnnotation<32> test_ring_buffer_annotation( + kRingBufferType, "#TEST# ring_buffer"); + static crashpad::RingBufferAnnotation<32> test_busy_ring_buffer_annotation( + kRingBufferType, "#TEST# busy_ring_buffer"); test_annotation_one.Set("moocow"); test_annotation_two.Set("this will be cleared"); test_annotation_three.Set("same-name 3"); test_annotation_four.Set("same-name 4"); test_annotation_two.Clear(); + test_ring_buffer_annotation.Push("hello", 5); + test_ring_buffer_annotation.Push("goodbye", 7); + test_busy_ring_buffer_annotation.Push("busy", 4); + // Take the scoped spin guard on `test_busy_ring_buffer_annotation` to mimic + // an in-flight `Push()` so its contents are not included in the dump. + auto guard = test_busy_ring_buffer_annotation.TryCreateScopedSpinGuard( + /*timeout_nanos=*/0); abort(); } diff --git a/thirdparty/sentry-native/external/crashpad/third_party/lss/lss.h b/thirdparty/sentry-native/external/crashpad/third_party/lss/lss.h index f768a78597..90cb9bcfe7 100644 --- a/thirdparty/sentry-native/external/crashpad/third_party/lss/lss.h +++ b/thirdparty/sentry-native/external/crashpad/third_party/lss/lss.h @@ -20,7 +20,7 @@ #elif defined(CRASHPAD_LSS_SOURCE_EMBEDDED) #include "third_party/lss/lss/linux_syscall_support.h" #elif defined(CRASHPAD_LSS_SOURCE_FUCHSIA) -#include "../../../../third_party/linux-syscall-support/linux_syscall_support.h" +#include "../../../../../third_party/linux-syscall-support/src/linux_syscall_support.h" #else #error Unknown lss source #endif diff --git a/thirdparty/sentry-native/external/crashpad/third_party/mini_chromium/BUILD.gn b/thirdparty/sentry-native/external/crashpad/third_party/mini_chromium/BUILD.gn index cc97cc197e..9d4ff01c05 100644 --- a/thirdparty/sentry-native/external/crashpad/third_party/mini_chromium/BUILD.gn +++ b/thirdparty/sentry-native/external/crashpad/third_party/mini_chromium/BUILD.gn @@ -20,7 +20,7 @@ group("base") { } else if (crashpad_is_standalone) { public_deps = [ "mini_chromium/base" ] } else if (crashpad_is_in_fuchsia) { - public_deps = [ "//third_party/mini_chromium/base" ] + public_deps = [ mini_chromium_import_root + "/base" ] } else if (crashpad_is_external) { public_deps = [ "../../../../mini_chromium/mini_chromium/base" ] } else if (crashpad_is_in_dart) { @@ -42,7 +42,7 @@ group("build") { } else if (crashpad_is_standalone) { public_deps = [ "mini_chromium/build" ] } else if (crashpad_is_in_fuchsia) { - public_deps = [ "//third_party/mini_chromium/build" ] + public_deps = [ mini_chromium_import_root + "/build" ] } else if (crashpad_is_external) { public_deps = [ "../../../../mini_chromium/mini_chromium/build" ] } else if (crashpad_is_in_dart) { @@ -56,11 +56,10 @@ group("chromeos_buildflags") { } else if (crashpad_is_standalone) { public_deps = [ "mini_chromium/build:chromeos_buildflags" ] } else if (crashpad_is_in_fuchsia) { - public_deps = [ "//third_party/mini_chromium/build:chromeos_buildflags" ] + public_deps = [ mini_chromium_import_root + "/build:chromeos_buildflags" ] } else if (crashpad_is_external) { public_deps = [ "../../../../mini_chromium/mini_chromium/build:chromeos_buildflags" ] } else if (crashpad_is_in_dart) { public_deps = [ "//third_party/mini_chromium/mini_chromium/build:chromeos_buildflags" ] } } - diff --git a/thirdparty/sentry-native/external/crashpad/third_party/zlib/CMakeLists.txt b/thirdparty/sentry-native/external/crashpad/third_party/zlib/CMakeLists.txt index eeb449ff33..627b8352cb 100644 --- a/thirdparty/sentry-native/external/crashpad/third_party/zlib/CMakeLists.txt +++ b/thirdparty/sentry-native/external/crashpad/third_party/zlib/CMakeLists.txt @@ -1,15 +1,11 @@ if(CRASHPAD_ZLIB_SYSTEM) add_library(crashpad_zlib INTERFACE) - string(REPLACE ";" "$" GENEX_ZLIB_LIBRARIES "${ZLIB_LIBRARIES}") - target_include_directories(crashpad_zlib INTERFACE - $ - ) target_compile_definitions(crashpad_zlib INTERFACE ZLIB_CONST CRASHPAD_ZLIB_SOURCE_SYSTEM $ ) - target_link_libraries(crashpad_zlib INTERFACE $) + target_link_libraries(crashpad_zlib INTERFACE ZLIB::ZLIB) else() add_library(crashpad_zlib STATIC zlib/adler32.c diff --git a/thirdparty/sentry-native/external/crashpad/util/BUILD.gn b/thirdparty/sentry-native/external/crashpad/util/BUILD.gn index 9e58bf32e4..b84a251a50 100644 --- a/thirdparty/sentry-native/external/crashpad/util/BUILD.gn +++ b/thirdparty/sentry-native/external/crashpad/util/BUILD.gn @@ -267,6 +267,7 @@ crashpad_static_library("util") { "stream/zlib_output_stream.h", "string/split_string.cc", "string/split_string.h", + "synchronization/scoped_spin_guard.h", "synchronization/semaphore.h", "thread/stoppable.h", "thread/thread.cc", @@ -402,6 +403,8 @@ crashpad_static_library("util") { "ios/scoped_background_task.mm", "ios/scoped_vm_read.cc", "ios/scoped_vm_read.h", + "ios/scoped_vm_map.cc", + "ios/scoped_vm_map.h", ] } @@ -561,7 +564,8 @@ crashpad_static_library("util") { # Include generated files starting with "util". if (crashpad_is_in_fuchsia) { - include_dirs = [ "$root_gen_dir/third_party/crashpad" ] + include_dirs = + [ "$root_gen_dir/" + rebase_path(fuchsia_crashpad_root, "//") ] } else { include_dirs = [ "$root_gen_dir/third_party/crashpad/crashpad" ] } @@ -775,6 +779,7 @@ source_set("util_test") { "stream/test_output_stream.h", "stream/zlib_output_stream_test.cc", "string/split_string_test.cc", + "synchronization/scoped_spin_guard_test.cc", "synchronization/semaphore_test.cc", "thread/thread_log_messages_test.cc", "thread/thread_test.cc", @@ -834,6 +839,7 @@ source_set("util_test") { "ios/ios_intermediate_dump_reader_test.cc", "ios/ios_intermediate_dump_writer_test.cc", "ios/scoped_vm_read_test.cc", + "ios/scoped_vm_map_test.cc", ] sources -= [ diff --git a/thirdparty/sentry-native/external/crashpad/util/CMakeLists.txt b/thirdparty/sentry-native/external/crashpad/util/CMakeLists.txt index 4c1d0e6f93..b8918f2e8d 100644 --- a/thirdparty/sentry-native/external/crashpad/util/CMakeLists.txt +++ b/thirdparty/sentry-native/external/crashpad/util/CMakeLists.txt @@ -104,6 +104,7 @@ add_library(crashpad_util STATIC stream/zlib_output_stream.h string/split_string.cc string/split_string.h + synchronization/scoped_spin_guard.h synchronization/semaphore.h thread/stoppable.h thread/thread.cc @@ -225,6 +226,8 @@ if(APPLE) ios/scoped_background_task.mm ios/scoped_vm_read.cc ios/scoped_vm_read.h + ios/scoped_vm_map.cc + ios/scoped_vm_map.h ) # This specific file requires ARC support, while other parts do not # build when ARC is enabled. @@ -245,8 +248,30 @@ if(ANDROID) endif() if(LINUX OR ANDROID) + if (LINUX) + if(NOT CURL_FOUND) # Some other lib might bring libcurl already + find_package(CURL REQUIRED) + endif() + + if(TARGET CURL::libcurl) # Only available in cmake 3.12+ + target_link_libraries(crashpad_util PRIVATE CURL::libcurl) + else() + # Needed for cmake < 3.12 support (cmake 3.12 introduced the target CURL::libcurl) + target_include_directories(crashpad_util PRIVATE ${CURL_INCLUDE_DIR}) + # The exported sentry target must not contain any path of the build machine, therefore use generator expressions + string(REPLACE ";" "$" GENEX_CURL_LIBRARIES "${CURL_LIBRARIES}") + string(REPLACE ";" "$" GENEX_CURL_COMPILE_DEFINITIONS "${CURL_COMPILE_DEFINITIONS}") + target_link_libraries(crashpad_util PRIVATE $) + target_compile_definitions(crashpad_util PRIVATE $) + endif() + + SET(HTTP_TRANSPORT_IMPL net/http_transport_libcurl.cc) + else() + SET(HTTP_TRANSPORT_IMPL net/http_transport_socket.cc) + endif() + target_sources(crashpad_util PRIVATE - net/http_transport_socket.cc + ${HTTP_TRANSPORT_IMPL} linux/address_types.h linux/auxiliary_vector.cc linux/auxiliary_vector.h diff --git a/thirdparty/sentry-native/external/crashpad/util/ios/ios_intermediate_dump_format.h b/thirdparty/sentry-native/external/crashpad/util/ios/ios_intermediate_dump_format.h index f8b7bdf763..9fe7ccf9a2 100644 --- a/thirdparty/sentry-native/external/crashpad/util/ios/ios_intermediate_dump_format.h +++ b/thirdparty/sentry-native/external/crashpad/util/ios/ios_intermediate_dump_format.h @@ -85,6 +85,7 @@ namespace internal { TD(kFree, 5017) \ TD(kInactive, 5018) \ TD(kWired, 5019) \ + TD(kAddressMask, 5020) \ TD(kThreads, 6000) \ TD(kDebugState, 6001) \ TD(kFloatState, 6002) \ @@ -103,7 +104,6 @@ namespace internal { TD(kMaxValue, 65535) \ // clang-format on - //! \brief They key for items in the intermediate dump file. //! //! These values are persisted to the intermediate crash dump file. Entries diff --git a/thirdparty/sentry-native/external/crashpad/util/ios/ios_system_data_collector.h b/thirdparty/sentry-native/external/crashpad/util/ios/ios_system_data_collector.h index 4c252f2d1a..2dfc373a1f 100644 --- a/thirdparty/sentry-native/external/crashpad/util/ios/ios_system_data_collector.h +++ b/thirdparty/sentry-native/external/crashpad/util/ios/ios_system_data_collector.h @@ -43,6 +43,7 @@ class IOSSystemDataCollector { const std::string& StandardName() const { return standard_name_; } const std::string& DaylightName() const { return daylight_name_; } bool IsApplicationActive() const { return active_; } + uint64_t AddressMask() const { return address_mask_; } // Currently unused by minidump. int Orientation() const { return orientation_; } @@ -80,6 +81,7 @@ class IOSSystemDataCollector { std::string standard_name_; std::string daylight_name_; ActiveApplicationCallback active_application_callback_; + uint64_t address_mask_; }; } // namespace internal diff --git a/thirdparty/sentry-native/external/crashpad/util/ios/ios_system_data_collector.mm b/thirdparty/sentry-native/external/crashpad/util/ios/ios_system_data_collector.mm index 7471002883..564c8e7926 100644 --- a/thirdparty/sentry-native/external/crashpad/util/ios/ios_system_data_collector.mm +++ b/thirdparty/sentry-native/external/crashpad/util/ios/ios_system_data_collector.mm @@ -102,6 +102,16 @@ IOSSystemDataCollector::IOSSystemDataCollector() #if defined(ARCH_CPU_X86_64) cpu_vendor_ = ReadStringSysctlByName("machdep.cpu.vendor"); #endif + uint32_t addressable_bits = 0; + size_t len = sizeof(uint32_t); + // `machdep.virtual_address_size` is the number of addressable bits in + // userspace virtual addresses + if (sysctlbyname( + "machdep.virtual_address_size", &addressable_bits, &len, NULL, 0) != + 0) { + addressable_bits = 0; + } + address_mask_ = ~((1UL << addressable_bits) - 1); #if TARGET_OS_SIMULATOR // TODO(justincohen): Consider adding board and model information to diff --git a/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_map.cc b/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_map.cc new file mode 100644 index 0000000000..e52b8778a3 --- /dev/null +++ b/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_map.cc @@ -0,0 +1,86 @@ +// Copyright 2023 The Crashpad Authors +// +// 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 of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/ios/scoped_vm_map.h" + +#include "util/ios/raw_logging.h" + +namespace crashpad { +namespace internal { + +ScopedVMMapInternal::ScopedVMMapInternal() + : data_(0), + region_start_(0), + region_size_(0), + cur_protection_(VM_PROT_NONE) {} + +ScopedVMMapInternal::~ScopedVMMapInternal() { + Reset(); +} + +bool ScopedVMMapInternal::Map(const void* data, const size_t data_length) { + Reset(); + + vm_address_t data_address = reinterpret_cast(data); + vm_address_t page_region_address = trunc_page(data_address); + region_size_ = round_page(data_address - page_region_address + data_length); + if (region_size_ < data_length) { + CRASHPAD_RAW_LOG("ScopedVMMap data_length overflow"); + return false; + } + + // Since region_start_ is 0, vm_remap() will choose an address to which the + // memory will be mapped and store the mapped address in region_start_ on + // success. + vm_prot_t max_protection; + kern_return_t kr = vm_remap(mach_task_self(), + ®ion_start_, + region_size_, + 0, + TRUE, + mach_task_self(), + page_region_address, + FALSE, + &cur_protection_, + &max_protection, + VM_INHERIT_DEFAULT); + if (kr != KERN_SUCCESS) { + // It's expected that this will sometimes fail. Don't log here. + return false; + } + + data_ = region_start_ + (data_address - page_region_address); + return true; +} + +void ScopedVMMapInternal::Reset() { + if (!region_start_) { + return; + } + + kern_return_t kr = + vm_deallocate(mach_task_self(), region_start_, region_size_); + + if (kr != KERN_SUCCESS) { + CRASHPAD_RAW_LOG_ERROR(kr, "vm_deallocate"); + } + + data_ = 0; + region_start_ = 0; + region_size_ = 0; + cur_protection_ = VM_PROT_NONE; +} + +} // namespace internal +} // namespace crashpad diff --git a/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_map.h b/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_map.h new file mode 100644 index 0000000000..d918d2e914 --- /dev/null +++ b/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_map.h @@ -0,0 +1,125 @@ +// Copyright 2023 The Crashpad Authors +// +// 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 of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_UTIL_IOS_SCOPED_VM_MAP_H_ +#define CRASHPAD_UTIL_IOS_SCOPED_VM_MAP_H_ + +#include + +namespace crashpad { +namespace internal { + +//! \brief Non-templated internal class to be used by ScopedVMMap. +//! +//! Note: RUNS-DURING-CRASH. +class ScopedVMMapInternal { + public: + ScopedVMMapInternal(); + + ScopedVMMapInternal(const ScopedVMMapInternal&) = delete; + ScopedVMMapInternal& operator=(const ScopedVMMapInternal&) = delete; + + ~ScopedVMMapInternal(); + + //! \brief Releases any previously mapped data and vm_remaps \a data. Logs an + //! error on failure. + //! + //! \param[in] data Memory to be mapped by vm_remap. + //! \param[in] data_length Length of \a data. + //! + //! \return `true` if all the data was mapped. Logs an error and returns false + //! on failure. + bool Map(const void* data, size_t data_length); + + //! \brief Returns the current protection for the memory in the region. + vm_prot_t CurrentProtection() const { return cur_protection_; } + + vm_address_t data() const { return data_; } + + private: + //! \brief Deallocates any resources allocated by this object and resets it + //! to its original state. + void Reset(); + + // The address within region_start_ at which the mapped data is available. + vm_address_t data_; + + // The region returned by vm_remap(). + vm_address_t region_start_; + + // The size of the region returned by vm_remap(). + vm_size_t region_size_; + + // The current protection for the memory region. + vm_prot_t cur_protection_; +}; + +//! \brief A scoped wrapper for calls to `vm_remap` and `vm_deallocate`. Allows +//! in-process handler to safely read and write memory (modulo its +//! protection level) for the intermediate dump. +//! +//! Note: RUNS-DURING-CRASH. +template +class ScopedVMMap { + public: + ScopedVMMap() : internal_() {} + + ScopedVMMap(const ScopedVMMap&) = delete; + ScopedVMMap& operator=(const ScopedVMMap&) = delete; + + ~ScopedVMMap() {} + + //! \brief Releases any previously mapped data and vm_remaps data. + //! + //! \param[in] data Memory to be mapped by vm_remap. + //! \param[in] count Length of \a data. + //! + //! \return `true` if all \a data was mapped. Returns false on failure. + bool Map(const void* data, size_t count = 1) { + size_t data_length = count * sizeof(T); + return internal_.Map(data, data_length); + } + + //! \brief Releases any previously mapped data and vm_remaps address. + //! + //! Before reading or writing the memory, check `CurrentProtection()` to + //! ensure the data is readable or writable. + //! + //! \param[in] address Address of memory to be mapped by vm_remap. + //! \param[in] count Length of \a data. + //! + //! \return `true` if all of \a address was mapped. Returns false on failure. + bool Map(vm_address_t address, size_t count = 1) { + return Map(reinterpret_cast(address), count); + } + + //! \brief Returns the pointer to memory safe to read and write (respecting + //! the CurrentProtection() level) during the in-process crash handler. + T* operator->() const { return get(); } + + //! \brief Returns the pointer to memory safe to read and write (respecting + //! the CurrentProtection() level) during the in-process crash handler. + T* get() const { return reinterpret_cast(internal_.data()); } + + //! \brief Returns the current protection level of the mapped memory. + vm_prot_t CurrentProtection() const { return internal_.CurrentProtection(); } + + private: + ScopedVMMapInternal internal_; +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_UTIL_IOS_SCOPED_VM_MAP_H_ diff --git a/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_map_test.cc b/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_map_test.cc new file mode 100644 index 0000000000..e88568a7ab --- /dev/null +++ b/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_map_test.cc @@ -0,0 +1,94 @@ +// Copyright 2023 The Crashpad Authors +// +// 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 of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/ios/scoped_vm_map.h" + +#include + +#include "base/mac/scoped_mach_vm.h" +#include "gtest/gtest.h" +#include "test/mac/mach_errors.h" + +namespace crashpad { +namespace test { +namespace { + +TEST(ScopedVMMapTest, BasicFunctionality) { + // bad data or count. + internal::ScopedVMMap vmmap_bad; + EXPECT_FALSE(vmmap_bad.Map(nullptr, 100)); + EXPECT_FALSE(vmmap_bad.Map(reinterpret_cast(0x1000), 100)); + vm_address_t invalid_address = 1; + EXPECT_FALSE(vmmap_bad.Map(&invalid_address, 1000000000)); + EXPECT_FALSE(vmmap_bad.Map(&invalid_address, -1)); + + vm_address_t valid_address = reinterpret_cast(this); + EXPECT_FALSE(vmmap_bad.Map(&valid_address, 1000000000)); + EXPECT_FALSE(vmmap_bad.Map(&valid_address, -1)); + + // array + static constexpr char map_me[] = "map me"; + internal::ScopedVMMap vmmap_string; + ASSERT_TRUE(vmmap_string.Map(map_me, strlen(map_me))); + EXPECT_STREQ(vmmap_string.get(), map_me); + EXPECT_TRUE(vmmap_string.CurrentProtection() & VM_PROT_READ); + + // struct + timeval time_of_day; + EXPECT_TRUE(gettimeofday(&time_of_day, nullptr) == 0); + internal::ScopedVMMap vmmap_time; + ASSERT_TRUE(vmmap_time.Map(&time_of_day)); + constexpr vm_prot_t kReadWrite = VM_PROT_READ | VM_PROT_WRITE; + EXPECT_EQ(vmmap_time.CurrentProtection() & kReadWrite, kReadWrite); + EXPECT_EQ(vmmap_time->tv_sec, time_of_day.tv_sec); + EXPECT_EQ(vmmap_time->tv_usec, time_of_day.tv_usec); + + // reset. + timeval time_of_day2; + EXPECT_TRUE(gettimeofday(&time_of_day2, nullptr) == 0); + ASSERT_TRUE(vmmap_time.Map(&time_of_day2)); + EXPECT_EQ(vmmap_time.CurrentProtection() & kReadWrite, kReadWrite); + EXPECT_EQ(vmmap_time->tv_sec, time_of_day2.tv_sec); + EXPECT_EQ(vmmap_time->tv_usec, time_of_day2.tv_usec); +} + +TEST(ScopedVMMapTest, MissingMiddleVM) { + char* region; + vm_size_t page_size = getpagesize(); + vm_size_t region_size = page_size * 3; + kern_return_t kr = vm_allocate(mach_task_self(), + reinterpret_cast(®ion), + region_size, + VM_FLAGS_ANYWHERE); + ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_allocate"); + + base::mac::ScopedMachVM vm_owner(reinterpret_cast(region), + region_size); + + internal::ScopedVMMap vmmap_missing_middle; + ASSERT_TRUE(vmmap_missing_middle.Map(region, region_size)); + + // Dealloc middle page. + kr = vm_deallocate(mach_task_self(), + reinterpret_cast(region + page_size), + page_size); + ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_deallocate"); + + EXPECT_FALSE(vmmap_missing_middle.Map(region, region_size)); + ASSERT_TRUE(vmmap_missing_middle.Map(region, page_size)); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_read.cc b/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_read.cc index 73585fd535..ba3b694011 100644 --- a/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_read.cc +++ b/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_read.cc @@ -20,25 +20,15 @@ namespace crashpad { namespace internal { ScopedVMReadInternal::ScopedVMReadInternal() - : data_(0), vm_read_data_(0), vm_read_data_count_(0) {} + : data_(0), region_start_(0), region_size_(0) {} ScopedVMReadInternal::~ScopedVMReadInternal() { - if (data_) { - kern_return_t kr = - vm_deallocate(mach_task_self(), vm_read_data_, vm_read_data_count_); - if (kr != KERN_SUCCESS) - CRASHPAD_RAW_LOG_ERROR(kr, "vm_deallocate"); - } + Reset(); } bool ScopedVMReadInternal::Read(const void* data, const size_t data_length) { - if (data_) { - kern_return_t kr = - vm_deallocate(mach_task_self(), vm_read_data_, vm_read_data_count_); - if (kr != KERN_SUCCESS) - CRASHPAD_RAW_LOG_ERROR(kr, "vm_deallocate"); - data_ = 0; - } + Reset(); + vm_address_t data_address = reinterpret_cast(data); vm_address_t page_region_address = trunc_page(data_address); vm_size_t page_region_size = @@ -50,16 +40,30 @@ bool ScopedVMReadInternal::Read(const void* data, const size_t data_length) { kern_return_t kr = vm_read(mach_task_self(), page_region_address, page_region_size, - &vm_read_data_, - &vm_read_data_count_); + ®ion_start_, + ®ion_size_); - if (kr == KERN_SUCCESS) { - data_ = vm_read_data_ + (data_address - page_region_address); - return true; - } else { + if (kr != KERN_SUCCESS) { // It's expected that this will sometimes fail. Don't log here. return false; } + + data_ = region_start_ + (data_address - page_region_address); + return true; +} + +void ScopedVMReadInternal::Reset() { + if (!region_start_) { + return; + } + kern_return_t kr = + vm_deallocate(mach_task_self(), region_start_, region_size_); + if (kr != KERN_SUCCESS) { + CRASHPAD_RAW_LOG_ERROR(kr, "vm_deallocate"); + } + region_start_ = 0; + region_size_ = 0; + data_ = 0; } } // namespace internal diff --git a/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_read.h b/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_read.h index ef6316f0d8..0c956a2ffc 100644 --- a/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_read.h +++ b/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_read.h @@ -46,14 +46,18 @@ class ScopedVMReadInternal { vm_address_t data() const { return data_; } private: - // The address of the requested data. + //! \brief Deallocates any resources allocated by this object and resets it + //! to its original state. + void Reset(); + + // The address within region_start_ at which the the data is available. vm_address_t data_; - // The rounded down page boundary of the requested data. - vm_address_t vm_read_data_; + // The region returned by vm_read(). + vm_address_t region_start_; - // The size of the pages that were actually read. - mach_msg_type_number_t vm_read_data_count_; + // The size of the region returned by vm_read(). + mach_msg_type_number_t region_size_; }; //! \brief A scoped wrapper for calls to `vm_read` and `vm_deallocate`. Allows diff --git a/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_read_test.cc b/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_read_test.cc index 135443b86f..c8b2e7583c 100644 --- a/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_read_test.cc +++ b/thirdparty/sentry-native/external/crashpad/util/ios/scoped_vm_read_test.cc @@ -18,6 +18,7 @@ #include "base/mac/scoped_mach_vm.h" #include "gtest/gtest.h" +#include "test/mac/mach_errors.h" namespace crashpad { namespace test { @@ -26,43 +27,47 @@ namespace { TEST(ScopedVMReadTest, BasicFunctionality) { // bad data or count. internal::ScopedVMRead vmread_bad; - ASSERT_FALSE(vmread_bad.Read(nullptr, 100)); - ASSERT_FALSE(vmread_bad.Read(reinterpret_cast(0x1000), 100)); - vm_address_t address = 1; - ASSERT_FALSE(vmread_bad.Read(&address, 1000000000)); - ASSERT_FALSE(vmread_bad.Read(&address, -1)); + EXPECT_FALSE(vmread_bad.Read(nullptr, 100)); + EXPECT_FALSE(vmread_bad.Read(reinterpret_cast(0x1000), 100)); + vm_address_t invalid_address = 1; + EXPECT_FALSE(vmread_bad.Read(&invalid_address, 1000000000)); + EXPECT_FALSE(vmread_bad.Read(&invalid_address, -1)); + vm_address_t valid_address = reinterpret_cast(this); + EXPECT_FALSE(vmread_bad.Read(&valid_address, 1000000000)); + EXPECT_FALSE(vmread_bad.Read(&valid_address, -1)); // array constexpr char read_me[] = "read me"; internal::ScopedVMRead vmread_string; ASSERT_TRUE(vmread_string.Read(read_me, strlen(read_me))); - EXPECT_STREQ(read_me, vmread_string.get()); + EXPECT_STREQ(vmread_string.get(), read_me); // struct timeval time_of_day; EXPECT_TRUE(gettimeofday(&time_of_day, nullptr) == 0); internal::ScopedVMRead vmread_time; ASSERT_TRUE(vmread_time.Read(&time_of_day)); - EXPECT_EQ(time_of_day.tv_sec, vmread_time->tv_sec); - EXPECT_EQ(time_of_day.tv_usec, vmread_time->tv_usec); + EXPECT_EQ(vmread_time->tv_sec, time_of_day.tv_sec); + EXPECT_EQ(vmread_time->tv_usec, time_of_day.tv_usec); // reset. timeval time_of_day2; EXPECT_TRUE(gettimeofday(&time_of_day2, nullptr) == 0); ASSERT_TRUE(vmread_time.Read(&time_of_day2)); - EXPECT_EQ(time_of_day2.tv_sec, vmread_time->tv_sec); - EXPECT_EQ(time_of_day2.tv_usec, vmread_time->tv_usec); + EXPECT_EQ(vmread_time->tv_sec, time_of_day2.tv_sec); + EXPECT_EQ(vmread_time->tv_usec, time_of_day2.tv_usec); } TEST(ScopedVMReadTest, MissingMiddleVM) { char* region; vm_size_t page_size = getpagesize(); vm_size_t region_size = page_size * 3; - ASSERT_EQ(vm_allocate(mach_task_self(), - reinterpret_cast(®ion), - region_size, - VM_FLAGS_ANYWHERE), - 0); + kern_return_t kr = vm_allocate(mach_task_self(), + reinterpret_cast(®ion), + region_size, + VM_FLAGS_ANYWHERE); + ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_allocate"); + base::mac::ScopedMachVM vm_owner(reinterpret_cast(region), region_size); @@ -70,12 +75,12 @@ TEST(ScopedVMReadTest, MissingMiddleVM) { ASSERT_TRUE(vmread_missing_middle.Read(region, region_size)); // Dealloc middle page. - ASSERT_EQ(vm_deallocate(mach_task_self(), - reinterpret_cast(region + page_size), - page_size), - 0); + kr = vm_deallocate(mach_task_self(), + reinterpret_cast(region + page_size), + page_size); + ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_deallocate"); - ASSERT_FALSE(vmread_missing_middle.Read(region, region_size)); + EXPECT_FALSE(vmread_missing_middle.Read(region, region_size)); ASSERT_TRUE(vmread_missing_middle.Read(region, page_size)); } diff --git a/thirdparty/sentry-native/external/crashpad/util/mac/mac_util_test.mm b/thirdparty/sentry-native/external/crashpad/util/mac/mac_util_test.mm index 6a799bf712..49ee0903a0 100644 --- a/thirdparty/sentry-native/external/crashpad/util/mac/mac_util_test.mm +++ b/thirdparty/sentry-native/external/crashpad/util/mac/mac_util_test.mm @@ -23,17 +23,6 @@ #include "base/strings/stringprintf.h" #include "gtest/gtest.h" -#ifdef __GLIBCXX__ -// When C++ exceptions are disabled, libstdc++ from GCC 4.2 defines |try| and -// |catch| so as to allow exception-expecting C++ code to build properly when -// language support for exceptions is not present. These macros interfere with -// the use of |@try| and |@catch| in Objective-C files such as this one. -// Undefine these macros here, after everything has been #included, since there -// will be no C++ uses and only Objective-C uses from this point on. -#undef try -#undef catch -#endif - namespace crashpad { namespace test { namespace { diff --git a/thirdparty/sentry-native/external/crashpad/util/synchronization/scoped_spin_guard.h b/thirdparty/sentry-native/external/crashpad/util/synchronization/scoped_spin_guard.h new file mode 100644 index 0000000000..f924d991a1 --- /dev/null +++ b/thirdparty/sentry-native/external/crashpad/util/synchronization/scoped_spin_guard.h @@ -0,0 +1,122 @@ +// Copyright 2022 The Crashpad Authors +// +// 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 of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_UTIL_SYNCHRONIZATION_SCOPED_SPIN_GUARD_H_ +#define CRASHPAD_UTIL_SYNCHRONIZATION_SCOPED_SPIN_GUARD_H_ + +#include +#include +#include + +#include "base/check.h" +#include "base/notreached.h" +#include "util/misc/clock.h" + +namespace crashpad { + +//! \brief Spinlock state for `ScopedSpinGuard`. +struct SpinGuardState final { + //! \brief A `ScopedSpinGuard` in an unlocked state. + constexpr SpinGuardState() : locked(false) {} + + SpinGuardState(const SpinGuardState&) = delete; + SpinGuardState& operator=(const SpinGuardState&) = delete; + + //! \brief `true` if the `ScopedSpinGuard` is locked, `false` otherwise. + std::atomic locked; + static_assert(std::atomic::is_always_lock_free, + "std::atomic may not be signal-safe"); + static_assert(sizeof(std::atomic) == sizeof(bool), + "std::atomic adds size to bool"); +}; + +//! \brief A scoped mutual-exclusion guard wrapping a `SpinGuardState` with RAII +//! semantics. +class ScopedSpinGuard final { + //! \brief The duration in nanoseconds between attempts to lock the spinlock. + static constexpr uint64_t kSpinGuardSleepTimeNanos = 10; + + public: + ScopedSpinGuard(const ScopedSpinGuard&) = delete; + ScopedSpinGuard& operator=(const ScopedSpinGuard&) = delete; + ScopedSpinGuard(ScopedSpinGuard&& other) noexcept : state_(nullptr) { + std::swap(state_, other.state_); + } + ScopedSpinGuard& operator=(ScopedSpinGuard&& other) { + std::swap(state_, other.state_); + return *this; + } + + //! \brief Spins up to `timeout_nanos` nanoseconds trying to lock `state`. + //! \param[in] timeout_nanos The timeout in nanoseconds after which this gives + //! up trying to lock the spinlock and returns `std::nullopt`. + //! \param[in,out] state The spinlock state to attempt to lock. This method + //! holds a pointer to `state`, so `state` must outlive the lifetime of + //! this object. + //! \return The locked `ScopedSpinGuard` on success, or `std::nullopt` on + //! timeout. + static std::optional TryCreateScopedSpinGuard( + uint64_t timeout_nanos, + SpinGuardState& state) { + const uint64_t clock_end_time_nanos = + ClockMonotonicNanoseconds() + timeout_nanos; + while (true) { + bool expected_current_value = false; + if (state.locked.compare_exchange_weak(expected_current_value, + true, + std::memory_order_acquire, + std::memory_order_relaxed)) { + return std::make_optional(state); + } + if (ClockMonotonicNanoseconds() >= clock_end_time_nanos) { + return std::nullopt; + } + SleepNanoseconds(kSpinGuardSleepTimeNanos); + } + + NOTREACHED(); + } + + ~ScopedSpinGuard() { + if (state_) { +#ifdef NDEBUG + state_->locked.store(false, std::memory_order_release); +#else + bool old = state_->locked.exchange(false, std::memory_order_release); + DCHECK(old); +#endif + } + } + + //! \brief A `ScopedSpinGuard` wrapping a locked `SpinGuardState`. + //! \param[in,out] locked_state A locked `SpinGuardState`. This method + //! holds a pointer to `state`, so `state` must outlive the lifetime of + //! this object. + ScopedSpinGuard(SpinGuardState& locked_state) : state_(&locked_state) { + DCHECK(locked_state.locked); + } + + private: + // \brief Optional spinlock state, unlocked when this object goes out of + // scope. + // + // If this is `nullptr`, then this object has been moved from, and the state + // is no longer valid. In that case, nothing will be unlocked when this object + // is destroyed. + SpinGuardState* state_; +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_SYNCHRONIZATION_SCOPED_SPIN_GUARD_H_ diff --git a/thirdparty/sentry-native/external/crashpad/util/synchronization/scoped_spin_guard_test.cc b/thirdparty/sentry-native/external/crashpad/util/synchronization/scoped_spin_guard_test.cc new file mode 100644 index 0000000000..9980d50df8 --- /dev/null +++ b/thirdparty/sentry-native/external/crashpad/util/synchronization/scoped_spin_guard_test.cc @@ -0,0 +1,109 @@ +// Copyright 2022 The Crashpad Authors +// +// 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 of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/synchronization/scoped_spin_guard.h" + +#include +#include + +#include "gtest/gtest.h" +#include "util/misc/clock.h" + +namespace crashpad { +namespace test { +namespace { + +TEST(ScopedSpinGuard, TryCreateScopedSpinGuardShouldLockStateWhileInScope) { + SpinGuardState s; + EXPECT_FALSE(s.locked); + { + std::optional guard = + ScopedSpinGuard::TryCreateScopedSpinGuard(/*timeout_nanos=*/0, s); + EXPECT_NE(std::nullopt, guard); + EXPECT_TRUE(s.locked); + } + EXPECT_FALSE(s.locked); +} + +TEST( + ScopedSpinGuard, + TryCreateScopedSpinGuardWithZeroTimeoutShouldFailImmediatelyIfStateLocked) { + SpinGuardState s; + s.locked = true; + std::optional guard = + ScopedSpinGuard::TryCreateScopedSpinGuard(/*timeout_nanos=*/0, s); + EXPECT_EQ(std::nullopt, guard); + EXPECT_TRUE(s.locked); +} + +TEST( + ScopedSpinGuard, + TryCreateScopedSpinGuardWithNonZeroTimeoutShouldSucceedIfStateUnlockedDuringTimeout) { + SpinGuardState s; + s.locked = true; + std::thread unlock_thread([&s] { + constexpr uint64_t kUnlockThreadSleepTimeNanos = 10000; // 10 us + EXPECT_TRUE(s.locked); + SleepNanoseconds(kUnlockThreadSleepTimeNanos); + s.locked = false; + }); + constexpr uint64_t kLockThreadTimeoutNanos = 180000000000ULL; // 3 minutes + std::optional guard = + ScopedSpinGuard::TryCreateScopedSpinGuard(kLockThreadTimeoutNanos, s); + EXPECT_NE(std::nullopt, guard); + EXPECT_TRUE(s.locked); + unlock_thread.join(); +} + +TEST(ScopedSpinGuard, SwapShouldMaintainSpinLock) { + SpinGuardState s; + std::optional outer_guard; + EXPECT_EQ(std::nullopt, outer_guard); + { + std::optional inner_guard = + ScopedSpinGuard::TryCreateScopedSpinGuard(/*timeout_nanos=*/0, s); + EXPECT_NE(std::nullopt, inner_guard); + EXPECT_TRUE(s.locked); + // If the move-assignment operator for `ScopedSpinGuard` is implemented + // incorrectly (e.g., the `= default` implementation), `inner_guard` + // will incorrectly think it still "owns" the spinlock after the swap, + // and when it falls out of scope, it will release the lock prematurely + // when it destructs. + // + // Confirm that the spinlock stays locked even after the swap. + std::swap(outer_guard, inner_guard); + EXPECT_TRUE(s.locked); + EXPECT_EQ(std::nullopt, inner_guard); + } + EXPECT_NE(std::nullopt, outer_guard); + EXPECT_TRUE(s.locked); +} + +TEST(ScopedSpinGuard, MoveAssignmentShouldMaintainSpinLock) { + SpinGuardState s; + std::optional outer_guard; + EXPECT_EQ(std::nullopt, outer_guard); + { + outer_guard = + ScopedSpinGuard::TryCreateScopedSpinGuard(/*timeout_nanos=*/0, s); + EXPECT_NE(std::nullopt, outer_guard); + EXPECT_TRUE(s.locked); + } + EXPECT_NE(std::nullopt, outer_guard); + EXPECT_TRUE(s.locked); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/DwarfSection.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/DwarfSection.cpp index 34d37b0908..7c99bde2c2 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/DwarfSection.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/DwarfSection.cpp @@ -16,6 +16,12 @@ #include +#include +#include +#include +#include +#include + #include #include #include diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/Elf.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/Elf.cpp index ac17f56c30..d34b015b22 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/Elf.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/Elf.cpp @@ -304,6 +304,11 @@ ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) { } else if (e_machine == EM_386) { arch_ = ARCH_X86; interface.reset(new ElfInterface32(memory)); +#ifdef SENTRY_REMOVED + } else if (e_machine == EM_MIPS) { + arch_ = ARCH_MIPS; + interface.reset(new ElfInterface32(memory)); +#endif // SENTRY_REMOVED } else { // Unsupported. return nullptr; @@ -319,6 +324,12 @@ ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) { arch_ = ARCH_ARM64; } else if (e_machine == EM_X86_64) { arch_ = ARCH_X86_64; +#ifdef SENTRY_REMOVED + } else if (e_machine == EM_MIPS) { + arch_ = ARCH_MIPS64; + } else if (e_machine == EM_RISCV) { + arch_ = ARCH_RISCV64; +#endif // SENTRY_REMOVED } else { // Unsupported. return nullptr; diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/GlobalDebugImpl.h b/thirdparty/sentry-native/external/libunwindstack-ndk/GlobalDebugImpl.h index f83a2c6610..3da1fbf174 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/GlobalDebugImpl.h +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/GlobalDebugImpl.h @@ -410,6 +410,9 @@ std::unique_ptr> CreateGlobalDebugImpl( return std::make_unique(arch, jit_memory, search_libs, global_variable_name); } case ARCH_ARM: { +#ifdef SENTRY_REMOVED + case ARCH_MIPS: { +#endif // SENTRY_REMOVED using Impl = GlobalDebugImpl; static_assert(offsetof(typename Impl::JITCodeEntry, symfile_size) == 16, "layout"); static_assert(offsetof(typename Impl::JITCodeEntry, seqlock) == 32, "layout"); @@ -419,6 +422,10 @@ std::unique_ptr> CreateGlobalDebugImpl( } case ARCH_ARM64: case ARCH_X86_64: { +#ifdef SENTRY_REMOVED + case ARCH_MIPS64: + case ARCH_RISCV64: { +#endif // SENTRY_REMOVED using Impl = GlobalDebugImpl; static_assert(offsetof(typename Impl::JITCodeEntry, symfile_size) == 24, "layout"); static_assert(offsetof(typename Impl::JITCodeEntry, seqlock) == 40, "layout"); diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/LogAndroid.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/LogAndroid.cpp index 9e40949bc6..70ed0d80d5 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/LogAndroid.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/LogAndroid.cpp @@ -21,8 +21,15 @@ #include #define LOG_TAG "unwind" +#ifndef SENTRY_MODIFIED #include +#endif // SENTRY_MODIFIED +#ifdef SENTRY_REMOVED +#if defined(__BIONIC__) +#include +#endif +#endif // SENTRY_REMOVED #include #include @@ -39,7 +46,9 @@ static void LogWithPriority(int priority, uint8_t indent, const char* format, va } else { real_format = format; } +#ifndef SENTRY_MODIFIED __android_log_vprint(priority, LOG_TAG, real_format.c_str(), args); +#endif // SENTRY_MODIFIED } void Info(const char* format, ...) { @@ -64,6 +73,24 @@ void Error(const char* format, ...) { } void AsyncSafe(const char*, ...) {} +#ifdef SENTRY_REMOVED +#if defined(__BIONIC__) +void AsyncSafe(const char* format, ...) { + va_list args; + va_start(args, format); + async_safe_format_log_va_list(ANDROID_LOG_ERROR, "libunwindstack", format, args); + va_end(args); +} +#else +void AsyncSafe(const char* format, ...) { + va_list args; + va_start(args, format); + vprintf(format, args); + printf("\n"); + va_end(args); +} +#endif +#endif // SENTRY_REMOVED } // namespace Log diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/LogStdout.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/LogStdout.cpp index 6ce06f882f..ac879a89c8 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/LogStdout.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/LogStdout.cpp @@ -63,6 +63,16 @@ void Error(const char* format, ...) { // Do nothing for async safe. void AsyncSafe(const char*, ...) {} +#ifdef SENTRY_REMOVED +void AsyncSafe(const char* format, ...) { + va_list args; + va_start(args, format); + // Only call vprintf to avoid allocating as much as possible, PrintToStdout uses a std::string. + vprintf(format, args); + printf("\n"); + va_end(args); +} +#endif // SENTRY_REMOVED } // namespace Log diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/Maps.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/Maps.cpp index 9527176c2e..36f9d4c0ad 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/Maps.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/Maps.cpp @@ -183,7 +183,7 @@ bool LocalUpdatableMaps::Reparse(/*out*/ bool* any_changed) { uint64_t start = new_map_info->start(); uint64_t end = new_map_info->end(); uint64_t flags = new_map_info->flags(); - const std::string& name = new_map_info->name(); + const SharedString& name = new_map_info->name(); for (size_t old_map_idx = search_map_idx; old_map_idx < last_map_idx; old_map_idx++) { auto& info = maps_[old_map_idx]; if (start == info->start() && end == info->end() && flags == info->flags() && diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/Memory.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/Memory.cpp index a80ea1313e..1585bd94ec 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/Memory.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/Memory.cpp @@ -1,22 +1,24 @@ /* -* Copyright (C) 2016 The Android Open Source Project -* -* 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 of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2016 The Android Open Source Project + * + * 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 of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SENTRY_ADDED #ifndef _GNU_SOURCE # define _GNU_SOURCE 1 #endif +#endif // SENTRY_ADDED #include #include #include @@ -27,8 +29,10 @@ #include #include #include +#ifndef SENTRY_ADDED #include "unistdfix.h" #include +#endif // SENTRY_ADDED #include #include @@ -50,6 +54,7 @@ #include "MemoryRange.h" #include "MemoryRemote.h" +#ifndef SENTRY_ADDED #if defined(__ANDROID_API__) && __ANDROID_API__ < 23 static ssize_t process_vm_readv(pid_t __pid, const struct iovec *__local_iov, @@ -60,150 +65,151 @@ process_vm_readv(pid_t __pid, const struct iovec *__local_iov, __remote_iov, __remote_iov_count, __flags); } #endif +#endif // SENTRY_ADDED namespace unwindstack { static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) { - // Split up the remote read across page boundaries. - // From the manpage: - // A partial read/write may result if one of the remote_iov elements points to an invalid - // memory region in the remote process. - // - // Partial transfers apply at the granularity of iovec elements. These system calls won't - // perform a partial transfer that splits a single iovec element. - constexpr size_t kMaxIovecs = 64; - struct iovec src_iovs[kMaxIovecs]; + // Split up the remote read across page boundaries. + // From the manpage: + // A partial read/write may result if one of the remote_iov elements points to an invalid + // memory region in the remote process. + // + // Partial transfers apply at the granularity of iovec elements. These system calls won't + // perform a partial transfer that splits a single iovec element. + constexpr size_t kMaxIovecs = 64; + struct iovec src_iovs[kMaxIovecs]; - uint64_t cur = remote_src; - size_t total_read = 0; - while (len > 0) { - struct iovec dst_iov = { - .iov_base = &reinterpret_cast(dst)[total_read], .iov_len = len, - }; + uint64_t cur = remote_src; + size_t total_read = 0; + while (len > 0) { + struct iovec dst_iov = { + .iov_base = &reinterpret_cast(dst)[total_read], .iov_len = len, + }; - size_t iovecs_used = 0; - while (len > 0) { - if (iovecs_used == kMaxIovecs) { - break; - } + size_t iovecs_used = 0; + while (len > 0) { + if (iovecs_used == kMaxIovecs) { + break; + } - // struct iovec uses void* for iov_base. - if (cur >= UINTPTR_MAX) { - errno = EFAULT; - return total_read; - } + // struct iovec uses void* for iov_base. + if (cur >= UINTPTR_MAX) { + errno = EFAULT; + return total_read; + } - src_iovs[iovecs_used].iov_base = reinterpret_cast(cur); + src_iovs[iovecs_used].iov_base = reinterpret_cast(cur); - uintptr_t misalignment = cur & (getpagesize() - 1); - size_t iov_len = getpagesize() - misalignment; - iov_len = std::min(iov_len, len); + uintptr_t misalignment = cur & (getpagesize() - 1); + size_t iov_len = getpagesize() - misalignment; + iov_len = std::min(iov_len, len); - len -= iov_len; - if (__builtin_add_overflow(cur, iov_len, &cur)) { - errno = EFAULT; - return total_read; - } + len -= iov_len; + if (__builtin_add_overflow(cur, iov_len, &cur)) { + errno = EFAULT; + return total_read; + } - src_iovs[iovecs_used].iov_len = iov_len; - ++iovecs_used; - } + src_iovs[iovecs_used].iov_len = iov_len; + ++iovecs_used; + } - ssize_t rc = process_vm_readv(pid, &dst_iov, 1, src_iovs, iovecs_used, 0); - if (rc == -1) { - return total_read; - } - total_read += rc; - } - return total_read; + ssize_t rc = process_vm_readv(pid, &dst_iov, 1, src_iovs, iovecs_used, 0); + if (rc == -1) { + return total_read; + } + total_read += rc; + } + return total_read; } static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) { - // ptrace() returns -1 and sets errno when the operation fails. - // To disambiguate -1 from a valid result, we clear errno beforehand. - errno = 0; - *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast(addr), nullptr); - if (*value == -1 && errno) { - return false; - } - return true; + // ptrace() returns -1 and sets errno when the operation fails. + // To disambiguate -1 from a valid result, we clear errno beforehand. + errno = 0; + *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast(addr), nullptr); + if (*value == -1 && errno) { + return false; + } + return true; } static size_t PtraceRead(pid_t pid, uint64_t addr, void* dst, size_t bytes) { - // Make sure that there is no overflow. - uint64_t max_size; - if (__builtin_add_overflow(addr, bytes, &max_size)) { - return 0; - } + // Make sure that there is no overflow. + uint64_t max_size; + if (__builtin_add_overflow(addr, bytes, &max_size)) { + return 0; + } - size_t bytes_read = 0; - long data; - size_t align_bytes = addr & (sizeof(long) - 1); - if (align_bytes != 0) { - if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) { - return 0; - } - size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes); - memcpy(dst, reinterpret_cast(&data) + align_bytes, copy_bytes); - addr += copy_bytes; - dst = reinterpret_cast(reinterpret_cast(dst) + copy_bytes); - bytes -= copy_bytes; - bytes_read += copy_bytes; - } + size_t bytes_read = 0; + long data; + size_t align_bytes = addr & (sizeof(long) - 1); + if (align_bytes != 0) { + if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) { + return 0; + } + size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes); + memcpy(dst, reinterpret_cast(&data) + align_bytes, copy_bytes); + addr += copy_bytes; + dst = reinterpret_cast(reinterpret_cast(dst) + copy_bytes); + bytes -= copy_bytes; + bytes_read += copy_bytes; + } - for (size_t i = 0; i < bytes / sizeof(long); i++) { - if (!PtraceReadLong(pid, addr, &data)) { - return bytes_read; - } - memcpy(dst, &data, sizeof(long)); - dst = reinterpret_cast(reinterpret_cast(dst) + sizeof(long)); - addr += sizeof(long); - bytes_read += sizeof(long); - } + for (size_t i = 0; i < bytes / sizeof(long); i++) { + if (!PtraceReadLong(pid, addr, &data)) { + return bytes_read; + } + memcpy(dst, &data, sizeof(long)); + dst = reinterpret_cast(reinterpret_cast(dst) + sizeof(long)); + addr += sizeof(long); + bytes_read += sizeof(long); + } - size_t left_over = bytes & (sizeof(long) - 1); - if (left_over) { - if (!PtraceReadLong(pid, addr, &data)) { - return bytes_read; - } - memcpy(dst, &data, left_over); - bytes_read += left_over; - } - return bytes_read; + size_t left_over = bytes & (sizeof(long) - 1); + if (left_over) { + if (!PtraceReadLong(pid, addr, &data)) { + return bytes_read; + } + memcpy(dst, &data, left_over); + bytes_read += left_over; + } + return bytes_read; } bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) { - size_t rc = Read(addr, dst, size); - return rc == size; + size_t rc = Read(addr, dst, size); + return rc == size; } bool Memory::ReadString(uint64_t addr, std::string* dst, size_t max_read) { - char buffer[256]; // Large enough for 99% of symbol names. - size_t size = 0; // Number of bytes which were read into the buffer. - for (size_t offset = 0; offset < max_read; offset += size) { - // Look for null-terminator first, so we can allocate string of exact size. - // If we know the end of valid memory range, do the reads in larger blocks. - size_t read = std::min(sizeof(buffer), max_read - offset); - size = Read(addr + offset, buffer, read); - if (size == 0) { - return false; // We have not found end of string yet and we can not read more data. - } - size_t length = strnlen(buffer, size); // Index of the null-terminator. - if (length < size) { - // We found the null-terminator. Allocate the string and set its content. - if (offset == 0) { - // We did just single read, so the buffer already contains the whole string. - dst->assign(buffer, length); - return true; - } else { - // The buffer contains only the last block. Read the whole string again. - dst->assign(offset + length, '\0'); - return ReadFully(addr, dst->data(), dst->size()); - } - } - } - return false; + char buffer[256]; // Large enough for 99% of symbol names. + size_t size = 0; // Number of bytes which were read into the buffer. + for (size_t offset = 0; offset < max_read; offset += size) { + // Look for null-terminator first, so we can allocate string of exact size. + // If we know the end of valid memory range, do the reads in larger blocks. + size_t read = std::min(sizeof(buffer), max_read - offset); + size = Read(addr + offset, buffer, read); + if (size == 0) { + return false; // We have not found end of string yet and we can not read more data. + } + size_t length = strnlen(buffer, size); // Index of the null-terminator. + if (length < size) { + // We found the null-terminator. Allocate the string and set its content. + if (offset == 0) { + // We did just single read, so the buffer already contains the whole string. + dst->assign(buffer, length); + return true; + } else { + // The buffer contains only the last block. Read the whole string again. + dst->assign(offset + length, '\0'); + return ReadFully(addr, dst->data(), dst->size()); + } + } + } + return false; } std::unique_ptr Memory::CreateFileMemory(const std::string& path, uint64_t offset, @@ -359,6 +365,7 @@ size_t MemoryRemote::Read(uint64_t addr, void* dst, size_t size) { } size_t MemoryLocal::Read(uint64_t addr, void* dst, size_t size) { +#ifndef SENTRY_MODIFIED errno = 0; size_t rv = ProcessVmRead(getpid(), addr, dst, size); // The syscall is only available in Linux 3.2, meaning Android 17. @@ -370,6 +377,7 @@ size_t MemoryLocal::Read(uint64_t addr, void* dst, size_t size) { } #endif return rv; +#endif // SENTRY_MODIFIED } MemoryRange::MemoryRange(const std::shared_ptr& memory, uint64_t begin, uint64_t length, diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/MemoryMte.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/MemoryMte.cpp index bb85c1d50a..4b5ca3125d 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/MemoryMte.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/MemoryMte.cpp @@ -17,6 +17,16 @@ #include #include +#ifdef SENTRY_REMOVED +// #if defined(__BIONIC__) +// #include +// #else +#endif // SENTRY_REMOVED +#define mte_supported() false +#ifdef SENTRY_REMOVED +// #endif +#endif // SENTRY_REMOVED + #include "MemoryLocal.h" #include "MemoryRemote.h" @@ -38,8 +48,20 @@ long MemoryRemote::ReadTag(uint64_t addr) { } long MemoryLocal::ReadTag(uint64_t addr) { +#if defined(__aarch64__) + // Check that the memory is readable first. This is racy with the ldg but there's not much + // we can do about it. + char data; + if (!mte_supported() || !Read(addr, &data, 1)) { + return -1; + } + + __asm__ __volatile__(".arch_extension mte; ldg %0, [%0]" : "+r"(addr) : : "memory"); + return (addr >> 56) & 0xf; +#else (void)addr; return -1; +#endif } } // namespace unwindstack diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/Regs.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/Regs.cpp index 78f6eb996d..b4574c3faf 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/Regs.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/Regs.cpp @@ -14,7 +14,9 @@ * limitations under the License. */ +#include #include +#include #include #include @@ -27,16 +29,25 @@ #include #include #include +#ifdef SENTRY_REMOVED +#include +#endif // SENTRY_REMOVED #include #include #include #include +#ifdef SENTRY_REMOVED +#include +#endif // SENTRY_REMOVED #include #include namespace unwindstack { // The largest user structure. +#ifdef SENTRY_REMOVED +// constexpr size_t MAX_USER_REGS_SIZE = sizeof(mips64_user_regs) + 10; +#endif // SENTRY_REMOVED static constexpr size_t kMaxUserRegsSize = std::max( sizeof(arm_user_regs), std::max(sizeof(arm64_user_regs), std::max(sizeof(x86_user_regs), sizeof(x86_64_user_regs)))); @@ -68,6 +79,10 @@ Regs* Regs::RemoteGet(pid_t pid, ErrorCode* error_code) { return RegsArm::Read(buffer.data()); case sizeof(arm64_user_regs): return RegsArm64::Read(buffer.data()); +#ifdef SENTRY_REMOVED + case sizeof(riscv64_user_regs): + return RegsRiscv64::Read(buffer.data()); +#endif // SENTRY_REMOVED } Log::Error("No matching size of user regs structure for pid %d: size %zu", pid, io.iov_len); @@ -121,6 +136,11 @@ Regs* Regs::CreateFromUcontext(ArchEnum arch, void* ucontext) { return RegsArm::CreateFromUcontext(ucontext); case ARCH_ARM64: return RegsArm64::CreateFromUcontext(ucontext); +#ifdef SENTRY_REMOVED + case ARCH_RISCV64: + return RegsRiscv64::CreateFromUcontext(ucontext); +#endif // SENTRY_REMOVED + case ARCH_UNKNOWN: default: return nullptr; } @@ -135,6 +155,10 @@ ArchEnum Regs::CurrentArch() { return ARCH_X86; #elif defined(__x86_64__) return ARCH_X86_64; +#ifdef SENTRY_REMOVED +//#elif defined(__riscv) + return ARCH_RISCV64; +#endif // SENTRY_REMOVED #else abort(); #endif @@ -150,6 +174,10 @@ Regs* Regs::CreateFromLocal() { regs = new RegsX86(); #elif defined(__x86_64__) regs = new RegsX86_64(); +#ifdef SENTRY_REMOVED +//#elif defined(__riscv) + regs = new RegsRiscv64(); +#endif // SENTRY_REMOVED #else abort(); #endif @@ -188,11 +216,24 @@ uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf, ArchEnum arch) { } return 4; } - case ARCH_ARM64: { - if (rel_pc < 4) { + case ARCH_ARM64: { +#ifdef SENTRY_REMOVED + case ARCH_RISCV64: { +#endif // SENTRY_REMOVED + if (rel_pc < 4) { + return 0; + } + return 4; +#ifdef SENTRY_REMOVED + } + case ARCH_MIPS: + case ARCH_MIPS64: { + if (rel_pc < 8) { return 0; } - return 4; + // For now, just assume no compact branches + return 8; +#endif // SENTRY_REMOVED } case ARCH_X86: case ARCH_X86_64: { diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/RegsArm64.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/RegsArm64.cpp index 0af9a1e392..29c3bd7e1d 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/RegsArm64.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/RegsArm64.cpp @@ -19,6 +19,12 @@ #include +#ifdef SENTRY_REMOVED +#if defined(__BIONIC__) +#include +#endif +#endif // SENTRY_REMOVED + #include #include #include @@ -55,6 +61,12 @@ static uint64_t strip_pac(uint64_t pc, uint64_t mask) { // pre-Armv8.3-A architectures. if (mask) { pc &= ~mask; + } else { +#ifdef SENTRY_REMOVED +#if defined(__BIONIC__) + pc = __bionic_clear_pac_bits(pc); +#endif +#endif // SENTRY_REMOVED } return pc; } diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/Symbols.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/Symbols.cpp index 499cc31155..67c9d0b0bd 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/Symbols.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/Symbols.cpp @@ -32,10 +32,20 @@ namespace unwindstack { Symbols::Symbols(uint64_t offset, uint64_t size, uint64_t entry_size, uint64_t str_offset, uint64_t str_size) : offset_(offset), - count_(entry_size != 0 ? size / entry_size : 0), + count_(entry_size != 0 ? ((size / entry_size > kMaxSymbols) ? kMaxSymbols : size / entry_size) + : 0), entry_size_(entry_size), - str_offset_(str_offset), - str_end_(str_offset_ + str_size) {} + str_offset_(str_offset) { + if (__builtin_add_overflow(str_offset_, str_size, &str_end_)) { + // Set to the max so that the code will still try to get symbol names. + // Any reads that might be invalid will simply return no data, so + // this will not result in crashes. + // The assumption is that this value might have been corrupted, but + // enough of the elf data is valid such that the code can still + // get symbol information. + str_end_ = UINT64_MAX; + } +} template static bool IsFunc(const SymType* entry) { @@ -66,8 +76,13 @@ Symbols::Info* Symbols::BinarySearch(uint64_t addr, Memory* elf_memory, uint64_t while (first < last) { uint32_t current = first + (last - first) / 2; uint32_t symbol_index = RemapIndices ? remap_.value()[current] : current; + uint64_t offset = symbol_index * entry_size_; + if (__builtin_add_overflow(offset, offset_, &offset)) { + // The elf data might be malformed. + return nullptr; + } SymType sym; - if (!elf_memory->ReadFully(offset_ + symbol_index * entry_size_, &sym, sizeof(sym))) { + if (!elf_memory->ReadFully(offset, &sym, sizeof(sym))) { return nullptr; } // There shouldn't be multiple symbols with same end address, but in case there are, @@ -96,13 +111,21 @@ void Symbols::BuildRemapTable(Memory* elf_memory) { for (size_t symbol_idx = 0; symbol_idx < count_;) { // Read symbols from memory. We intentionally bypass the cache to save memory. // Do the reads in batches so that we minimize the number of memory read calls. + uint64_t read_bytes = (count_ - symbol_idx) * entry_size_; uint8_t buffer[1024]; - size_t read = std::min(sizeof(buffer), (count_ - symbol_idx) * entry_size_); - size_t size = elf_memory->Read(offset_ + symbol_idx * entry_size_, buffer, read); - if (size < sizeof(SymType)) { - break; // Stop processing, something looks like it is corrupted. + read_bytes = std::min(sizeof(buffer), read_bytes); + uint64_t offset = symbol_idx * entry_size_; + if (__builtin_add_overflow(offset, offset_, &offset)) { + // The elf data might be malformed. + break; } - for (size_t offset = 0; offset + sizeof(SymType) <= size; offset += entry_size_, symbol_idx++) { + read_bytes = elf_memory->Read(offset, buffer, read_bytes); + if (read_bytes < sizeof(SymType)) { + // The elf data might be malformed. + break; + } + for (uint64_t offset = 0; offset <= read_bytes - sizeof(SymType); + offset += entry_size_, symbol_idx++) { SymType sym; memcpy(&sym, &buffer[offset], sizeof(SymType)); // Copy to ensure alignment. addrs.push_back(sym.st_value); // Always insert so it is indexable by symbol index. @@ -146,7 +169,12 @@ bool Symbols::GetName(uint64_t addr, Memory* elf_memory, SharedString* name, if (info->name.is_null()) { SymType sym; uint32_t symbol_index = remap_.has_value() ? remap_.value()[info->index] : info->index; - if (!elf_memory->ReadFully(offset_ + symbol_index * entry_size_, &sym, sizeof(sym))) { + uint64_t offset = symbol_index * entry_size_; + if (__builtin_add_overflow(offset, offset_, &offset)) { + // The elf data might be malformed. + return false; + } + if (!elf_memory->ReadFully(offset, &sym, sizeof(sym))) { return false; } std::string symbol_name; @@ -177,14 +205,23 @@ bool Symbols::GetGlobal(Memory* elf_memory, const std::string& name, uint64_t* m // Linear scan of all symbols. for (uint32_t i = 0; i < count_; i++) { + uint64_t offset = i * entry_size_; + if (__builtin_add_overflow(offset_, offset, &offset)) { + // The elf data might be malformed. + return false; + } SymType entry; - if (!elf_memory->ReadFully(offset_ + i * entry_size_, &entry, sizeof(entry))) { + if (!elf_memory->ReadFully(offset, &entry, sizeof(entry))) { return false; } if (entry.st_shndx != SHN_UNDEF && ELF32_ST_TYPE(entry.st_info) == STT_OBJECT && ELF32_ST_BIND(entry.st_info) == STB_GLOBAL) { uint64_t str_offset = str_offset_ + entry.st_name; + if (__builtin_add_overflow(str_offset_, entry.st_name, &str_offset)) { + // The elf data might be malformed. + return false; + } if (str_offset < str_end_) { std::string symbol; if (elf_memory->ReadString(str_offset, &symbol, str_end_ - str_offset) && symbol == name) { diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/Symbols.h b/thirdparty/sentry-native/external/libunwindstack-ndk/Symbols.h index 0b467518d4..999c710f5b 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/Symbols.h +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/Symbols.h @@ -64,13 +64,16 @@ class Symbols { const uint64_t count_; const uint64_t entry_size_; const uint64_t str_offset_; - const uint64_t str_end_; + uint64_t str_end_; std::map symbols_; // Cache of read symbols (keyed by function *end* address). std::optional> remap_; // Indices of function symbols sorted by address. // Cache of global data (non-function) symbols. std::unordered_map> global_variables_; + + // Do not allow the total number of symbols to go above this. + constexpr static size_t kMaxSymbols = 1000000; }; } // namespace unwindstack diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/ThreadEntry.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/ThreadEntry.cpp index db34df0ff5..0e62f09d15 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/ThreadEntry.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/ThreadEntry.cpp @@ -74,13 +74,24 @@ ThreadEntry::~ThreadEntry() { } } +const char* ThreadEntry::GetWaitTypeName(WaitType type) { + switch (type) { + case WAIT_FOR_UCONTEXT: + return "ucontext"; + case WAIT_FOR_UNWIND_TO_COMPLETE: + return "unwind to complete"; + case WAIT_FOR_THREAD_TO_RESTART: + return "thread to restart"; + } +} + bool ThreadEntry::Wait(WaitType type) { static const std::chrono::duration wait_time(std::chrono::seconds(10)); std::unique_lock lock(wait_mutex_); if (wait_cond_.wait_for(lock, wait_time, [this, type] { return wait_value_ == type; })) { return true; } else { - Log::AsyncSafe("pthread_cond_timedwait for value %d failed", type); + Log::AsyncSafe("Timeout waiting for %s", GetWaitTypeName(type)); return false; } } diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/ThreadEntry.h b/thirdparty/sentry-native/external/libunwindstack-ndk/ThreadEntry.h index 2f8e88d62d..32501e2b52 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/ThreadEntry.h +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/ThreadEntry.h @@ -70,6 +70,8 @@ class ThreadEntry { static std::mutex entries_mutex_; static std::map entries_; + + static const char* GetWaitTypeName(WaitType type); }; } // namespace unwindstack diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/ThreadUnwinder.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/ThreadUnwinder.cpp index 7b452610fe..71835db6ca 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/ThreadUnwinder.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/ThreadUnwinder.cpp @@ -63,10 +63,8 @@ static void SignalHandler(int, siginfo_t*, void* sigcontext) { // Do not remove the entry here because that can result in a deadlock // if the code cannot properly send a signal to the thread under test. entry->Wake(); - } else { - // At this point, it is possible that entry has been freed, so just exit. - Log::AsyncSafe("Timed out waiting for unwind thread to indicate it completed."); } + // If the wait fails, the entry might have been freed, so only exit. } ThreadUnwinder::ThreadUnwinder(size_t max_frames, Maps* maps) @@ -141,7 +139,6 @@ ThreadEntry* ThreadUnwinder::SendSignalToThread(int signal, pid_t tid) { last_error_.code = ERROR_THREAD_DOES_NOT_EXIST; } else { last_error_.code = ERROR_THREAD_TIMEOUT; - Log::AsyncSafe("Timed out waiting for signal handler to get ucontext data."); } ThreadEntry::Remove(entry); @@ -178,10 +175,8 @@ void ThreadUnwinder::UnwindWithSignal(int signal, pid_t tid, std::unique_ptrWake(); // Wait for the thread to indicate it is done with the ThreadEntry. - if (!entry->Wait(WAIT_FOR_THREAD_TO_RESTART)) { - // Send a warning, but do not mark as a failure to unwind. - Log::AsyncSafe("Timed out waiting for signal handler to indicate it finished."); - } + // If this fails, the Wait command will log an error message. + entry->Wait(WAIT_FOR_THREAD_TO_RESTART); ThreadEntry::Remove(entry); } diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/Unwinder.cpp b/thirdparty/sentry-native/external/libunwindstack-ndk/Unwinder.cpp index facff86d65..b8025142b6 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/Unwinder.cpp +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/Unwinder.cpp @@ -25,10 +25,14 @@ #include #include +#include #include #include +#ifdef SENTRY_REMOVED +#include +#endif // SENTRY_REMOVED #include #include #include @@ -39,8 +43,10 @@ #include "Check.h" +#ifndef SENTRY_ADDED // Use the demangler from libc++. extern "C" char* __cxa_demangle(const char*, char*, size_t*, int* status); +#endif // SENTRY_ADDED namespace unwindstack { @@ -326,6 +332,7 @@ std::string Unwinder::FormatFrame(ArchEnum arch, const FrameData& frame, bool di } if (!frame.function_name.empty()) { +#ifndef SENTRY_MODIFIED char* demangled_name = __cxa_demangle(frame.function_name.c_str(), nullptr, nullptr, nullptr); if (demangled_name == nullptr) { data += " ("; @@ -335,6 +342,7 @@ std::string Unwinder::FormatFrame(ArchEnum arch, const FrameData& frame, bool di data += demangled_name; free(demangled_name); } +#endif // SENTRY_MODIFIED if (frame.function_offset != 0) { data += android::base::StringPrintf("+%" PRId64, frame.function_offset); } diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/AndroidUnwinder.h b/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/AndroidUnwinder.h index de5579df61..1d8ff339f1 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/AndroidUnwinder.h +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/AndroidUnwinder.h @@ -100,6 +100,7 @@ class AndroidUnwinder { std::vector initial_map_names_to_skip_; std::vector map_suffixes_to_ignore_; std::once_flag initialize_; + bool initialize_status_ = false; ArchEnum arch_ = ARCH_UNKNOWN; diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/Arch.h b/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/Arch.h index dd0aa59ad0..41dc00e137 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/Arch.h +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/Arch.h @@ -26,12 +26,20 @@ enum ArchEnum : uint8_t { ARCH_ARM64, ARCH_X86, ARCH_X86_64, +#ifdef SENTRY_REMOVED + ARCH_MIPS, + ARCH_MIPS64, + ARCH_RISCV64, +#endif // SENTRY_REMOVED }; static inline bool ArchIs32Bit(ArchEnum arch) { switch (arch) { case ARCH_ARM: case ARCH_X86: +#ifdef SENTRY_REMOVED + case ARCH_MIPS: +#endif // SENTRY_REMOVED return true; default: return false; diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/Elf.h b/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/Elf.h index 0985042cea..a38323fa47 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/Elf.h +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/Elf.h @@ -33,6 +33,12 @@ #define EM_AARCH64 183 #endif +#ifdef SENTRY_REMOVED +#if !defined(EM_RISCV) +#define EM_RISCV 243 +#endif +#endif // SENTRY_REMOVED + namespace unwindstack { // Forward declaration. diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/RegsGetLocal.h b/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/RegsGetLocal.h index bf3f767cbe..3a90514e03 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/RegsGetLocal.h +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/RegsGetLocal.h @@ -80,6 +80,51 @@ inline __attribute__((__always_inline__)) void AsmGetRegs(void* reg_data) { : "x12", "x13", "memory"); } +#ifdef SENTRY_REMOVED + +inline __attribute__((__always_inline__)) void AsmGetRegs(void* reg_data) { + asm volatile( + "1:\n" + "sd ra, 8(%[base])\n" + "sd sp, 16(%[base])\n" + "sd gp, 24(%[base])\n" + "sd tp, 32(%[base])\n" + "sd t0, 40(%[base])\n" + "sd t1, 48(%[base])\n" + "sd t2, 56(%[base])\n" + "sd s0, 64(%[base])\n" + "sd s1, 72(%[base])\n" + "sd a0, 80(%[base])\n" + "sd a1, 88(%[base])\n" + "sd a2, 96(%[base])\n" + "sd a3, 104(%[base])\n" + "sd a4, 112(%[base])\n" + "sd a5, 120(%[base])\n" + "sd a6, 128(%[base])\n" + "sd a7, 136(%[base])\n" + "sd s2, 144(%[base])\n" + "sd s3, 152(%[base])\n" + "sd s4, 160(%[base])\n" + "sd s5, 168(%[base])\n" + "sd s6, 176(%[base])\n" + "sd s7, 184(%[base])\n" + "sd s8, 192(%[base])\n" + "sd s9, 200(%[base])\n" + "sd s10, 208(%[base])\n" + "sd s11, 216(%[base])\n" + "sd t3, 224(%[base])\n" + "sd t4, 232(%[base])\n" + "sd t5, 240(%[base])\n" + "sd t6, 248(%[base])\n" + "la t1, 1b\n" + "sd t1, 0(%[base])\n" + : [base] "+r"(reg_data) + : + : "t1", "memory"); +} + +#endif // SENTRY_REMOVED + #elif defined(__i386__) || defined(__x86_64__) extern "C" void AsmGetRegs(void* regs); diff --git a/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/SharedString.h b/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/SharedString.h index 1eb4e21dea..bdf709ed83 100644 --- a/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/SharedString.h +++ b/thirdparty/sentry-native/external/libunwindstack-ndk/include/unwindstack/SharedString.h @@ -18,6 +18,7 @@ #include #include +#include namespace unwindstack { @@ -46,7 +47,8 @@ class SharedString { std::shared_ptr data_; }; -static inline bool operator==(const SharedString& a, SharedString& b) { +template >> +static inline bool operator==(const T& a, const T& b) { return static_cast(a) == static_cast(b); } static inline bool operator==(const SharedString& a, std::string_view b) { @@ -55,7 +57,8 @@ static inline bool operator==(const SharedString& a, std::string_view b) { static inline bool operator==(std::string_view a, const SharedString& b) { return a == static_cast(b); } -static inline bool operator!=(const SharedString& a, SharedString& b) { +template >> +static inline bool operator!=(const T& a, const T& b) { return !(a == b); } static inline bool operator!=(const SharedString& a, std::string_view b) { diff --git a/thirdparty/sentry-native/include/sentry.h b/thirdparty/sentry-native/include/sentry.h index 3e5f16a878..b5381642da 100644 --- a/thirdparty/sentry-native/include/sentry.h +++ b/thirdparty/sentry-native/include/sentry.h @@ -30,7 +30,7 @@ extern "C" { # define SENTRY_SDK_NAME "sentry.native" # endif #endif -#define SENTRY_SDK_VERSION "0.5.4" +#define SENTRY_SDK_VERSION "0.6.0" #define SENTRY_SDK_USER_AGENT SENTRY_SDK_NAME "/" SENTRY_SDK_VERSION /* common platform detection */ @@ -1346,16 +1346,6 @@ SENTRY_API void sentry_set_transaction(const char *transaction); */ SENTRY_API void sentry_set_level(sentry_level_t level); -/** - * Starts a new session. - */ -SENTRY_API void sentry_start_session(void); - -/** - * Ends a session. - */ -SENTRY_API void sentry_end_session(void); - /** * Sets the maximum number of spans that can be attached to a * transaction. @@ -1384,6 +1374,31 @@ SENTRY_EXPERIMENTAL_API void sentry_options_set_traces_sample_rate( SENTRY_EXPERIMENTAL_API double sentry_options_get_traces_sample_rate( sentry_options_t *opts); +/* -- Session APIs -- */ + +typedef enum { + SENTRY_SESSION_STATUS_OK, + SENTRY_SESSION_STATUS_CRASHED, + SENTRY_SESSION_STATUS_ABNORMAL, + SENTRY_SESSION_STATUS_EXITED, +} sentry_session_status_t; + +/** + * Starts a new session. + */ +SENTRY_API void sentry_start_session(void); + +/** + * Ends a session. + */ +SENTRY_API void sentry_end_session(void); + +/** + * Ends a session with an explicit `status` code. + */ +SENTRY_EXPERIMENTAL_API void sentry_end_session_with_status( + sentry_session_status_t status); + /* -- Performance Monitoring/Tracing APIs -- */ /** @@ -1846,7 +1861,7 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_iter_headers( * 0 = no crash recognized * -1 = sentry_init() hasn't been called yet */ -SENTRY_EXPERIMENTAL_API int sentry_get_crashed_last_run(); +SENTRY_EXPERIMENTAL_API int sentry_get_crashed_last_run(void); /** * Clear the status of the "crashed-last-run". You should explicitly call @@ -1860,22 +1875,22 @@ SENTRY_EXPERIMENTAL_API int sentry_get_crashed_last_run(); * * Returns 0 on success, 1 on error. */ -SENTRY_EXPERIMENTAL_API int sentry_clear_crashed_last_run(); +SENTRY_EXPERIMENTAL_API int sentry_clear_crashed_last_run(void); /** * Sentry SDK version. */ -SENTRY_EXPERIMENTAL_API const char *sentry_sdk_version(); +SENTRY_EXPERIMENTAL_API const char *sentry_sdk_version(void); /** * Sentry SDK name. */ -SENTRY_EXPERIMENTAL_API const char *sentry_sdk_name(); +SENTRY_EXPERIMENTAL_API const char *sentry_sdk_name(void); /** * Sentry SDK User-Agent. */ -SENTRY_EXPERIMENTAL_API const char *sentry_sdk_user_agent(); +SENTRY_EXPERIMENTAL_API const char *sentry_sdk_user_agent(void); #ifdef __cplusplus } diff --git a/thirdparty/sentry-native/src/backends/sentry_backend_crashpad.cpp b/thirdparty/sentry-native/src/backends/sentry_backend_crashpad.cpp index f9f57fc3ea..c44672341e 100644 --- a/thirdparty/sentry-native/src/backends/sentry_backend_crashpad.cpp +++ b/thirdparty/sentry-native/src/backends/sentry_backend_crashpad.cpp @@ -33,7 +33,7 @@ extern "C" { #include "client/crashpad_info.h" #include "client/prune_crash_reports.h" #include "client/settings.h" -#if defined(_MSC_VER) +#if defined(_WIN32) # include "util/win/termination_codes.h" #endif diff --git a/thirdparty/sentry-native/src/exports.map b/thirdparty/sentry-native/src/exports.map new file mode 100644 index 0000000000..a361e42517 --- /dev/null +++ b/thirdparty/sentry-native/src/exports.map @@ -0,0 +1,4 @@ +{ + global: sentry_*; + local: *; +}; diff --git a/thirdparty/sentry-native/src/sentry_core.c b/thirdparty/sentry-native/src/sentry_core.c index 669948d2d7..b10d6065df 100644 --- a/thirdparty/sentry-native/src/sentry_core.c +++ b/thirdparty/sentry-native/src/sentry_core.c @@ -1014,13 +1014,13 @@ fail: } int -sentry_get_crashed_last_run() +sentry_get_crashed_last_run(void) { return g_last_crash; } int -sentry_clear_crashed_last_run() +sentry_clear_crashed_last_run(void) { bool success = false; sentry_options_t *options = sentry__options_lock(); diff --git a/thirdparty/sentry-native/src/sentry_info.c b/thirdparty/sentry-native/src/sentry_info.c index b2918127b3..ca2f6387a4 100644 --- a/thirdparty/sentry-native/src/sentry_info.c +++ b/thirdparty/sentry-native/src/sentry_info.c @@ -1,19 +1,19 @@ #include "sentry_boot.h" const char * -sentry_sdk_version() +sentry_sdk_version(void) { return SENTRY_SDK_VERSION; } const char * -sentry_sdk_name() +sentry_sdk_name(void) { return SENTRY_SDK_NAME; } const char * -sentry_sdk_user_agent() +sentry_sdk_user_agent(void) { return SENTRY_SDK_USER_AGENT; } diff --git a/thirdparty/sentry-native/src/sentry_scope.c b/thirdparty/sentry-native/src/sentry_scope.c index 321b8f41e6..0201a673bb 100644 --- a/thirdparty/sentry-native/src/sentry_scope.c +++ b/thirdparty/sentry-native/src/sentry_scope.c @@ -118,7 +118,7 @@ sentry__scope_unlock(void) } void -sentry__scope_flush_unlock() +sentry__scope_flush_unlock(void) { sentry__scope_unlock(); SENTRY_WITH_OPTIONS (options) { @@ -245,7 +245,7 @@ sentry__get_span_or_transaction(const sentry_scope_t *scope) #ifdef SENTRY_UNITTEST sentry_value_t -sentry__scope_get_span_or_transaction() +sentry__scope_get_span_or_transaction(void) { SENTRY_WITH_SCOPE (scope) { return sentry__get_span_or_transaction(scope); diff --git a/thirdparty/sentry-native/src/sentry_scope.h b/thirdparty/sentry-native/src/sentry_scope.h index 207b1a9957..5b2ba5fe6e 100644 --- a/thirdparty/sentry-native/src/sentry_scope.h +++ b/thirdparty/sentry-native/src/sentry_scope.h @@ -68,7 +68,7 @@ void sentry__scope_cleanup(void); * This function must be called while holding the scope lock, and it will be * unlocked internally. */ -void sentry__scope_flush_unlock(); +void sentry__scope_flush_unlock(void); /** * This will merge the requested data which is in the given `scope` to the given @@ -98,5 +98,5 @@ void sentry__scope_apply_to_event(const sentry_scope_t *scope, // this is only used in unit tests #ifdef SENTRY_UNITTEST -sentry_value_t sentry__scope_get_span_or_transaction(); +sentry_value_t sentry__scope_get_span_or_transaction(void); #endif diff --git a/thirdparty/sentry-native/src/sentry_session.c b/thirdparty/sentry-native/src/sentry_session.c index 1aa7dc7963..e782d385f1 100644 --- a/thirdparty/sentry-native/src/sentry_session.c +++ b/thirdparty/sentry-native/src/sentry_session.c @@ -265,6 +265,17 @@ sentry__end_current_session_with_status(sentry_session_status_t status) return session; } +static void +sentry__capture_session(sentry_session_t *session) +{ + sentry_envelope_t *envelope = sentry__envelope_new(); + sentry__envelope_add_session(envelope, session); + + SENTRY_WITH_OPTIONS (options) { + sentry__capture_envelope(options->transport, envelope); + } +} + void sentry_end_session(void) { @@ -273,13 +284,20 @@ sentry_end_session(void) return; } - sentry_envelope_t *envelope = sentry__envelope_new(); - sentry__envelope_add_session(envelope, session); + sentry__capture_session(session); sentry__session_free(session); +} - SENTRY_WITH_OPTIONS (options) { - sentry__capture_envelope(options->transport, envelope); +void +sentry_end_session_with_status(sentry_session_status_t status) +{ + sentry_session_t *session = sentry__end_current_session_with_status(status); + if (!session) { + return; } + + sentry__capture_session(session); + sentry__session_free(session); } void diff --git a/thirdparty/sentry-native/src/sentry_session.h b/thirdparty/sentry-native/src/sentry_session.h index 5ba036cbd5..2a18edb4c0 100644 --- a/thirdparty/sentry-native/src/sentry_session.h +++ b/thirdparty/sentry-native/src/sentry_session.h @@ -8,13 +8,6 @@ struct sentry_jsonwriter_s; -typedef enum { - SENTRY_SESSION_STATUS_OK, - SENTRY_SESSION_STATUS_CRASHED, - SENTRY_SESSION_STATUS_ABNORMAL, - SENTRY_SESSION_STATUS_EXITED, -} sentry_session_status_t; - /** * This represents a session, with the number of errors, a status and other * metadata. diff --git a/thirdparty/sentry-native/src/sentry_sync.c b/thirdparty/sentry-native/src/sentry_sync.c index e81d776c20..3e4c1940b6 100644 --- a/thirdparty/sentry-native/src/sentry_sync.c +++ b/thirdparty/sentry-native/src/sentry_sync.c @@ -68,7 +68,7 @@ sentry__thread_setname(sentry_threadid_t thread_id, const char *thread_name) } #else sentry_threadid_t -sentry__thread_get_current_threadid() +sentry__thread_get_current_threadid(void) { return pthread_self(); } diff --git a/thirdparty/sentry-native/src/sentry_sync.h b/thirdparty/sentry-native/src/sentry_sync.h index 11915536a2..0741c30702 100644 --- a/thirdparty/sentry-native/src/sentry_sync.h +++ b/thirdparty/sentry-native/src/sentry_sync.h @@ -13,7 +13,7 @@ # define THREAD_FUNCTION_API #endif -#if defined(__MINGW32__) && !defined(__MINGW64__) +#if defined(__MINGW32__) && !defined(__MINGW64__) && !defined(__clang__) # define UNSIGNED_MINGW unsigned #else # define UNSIGNED_MINGW diff --git a/thirdparty/sentry-native/src/sentry_utils.c b/thirdparty/sentry-native/src/sentry_utils.c index 569fa08333..dbafea8113 100644 --- a/thirdparty/sentry-native/src/sentry_utils.c +++ b/thirdparty/sentry-native/src/sentry_utils.c @@ -480,7 +480,7 @@ sentry__iso8601_to_msec(const char *iso) // to ensure the C locale is also used there. #if !defined(SENTRY_PLATFORM_ANDROID) && !defined(SENTRY_PLATFORM_IOS) static sentry__locale_t -c_locale() +c_locale(void) { static long c_locale_initialized = 0; static sentry__locale_t c_locale; diff --git a/thirdparty/sentry-native/src/unwinder/sentry_unwinder_dbghelp.c b/thirdparty/sentry-native/src/unwinder/sentry_unwinder_dbghelp.c index fd6ec3b725..7d22728dae 100644 --- a/thirdparty/sentry-native/src/unwinder/sentry_unwinder_dbghelp.c +++ b/thirdparty/sentry-native/src/unwinder/sentry_unwinder_dbghelp.c @@ -43,16 +43,32 @@ sentry__unwind_stack_dbghelp( memset(&stack_frame, 0, sizeof(stack_frame)); size_t size = 0; -#if defined(_WIN64) +#if defined(_M_X64) int machine_type = IMAGE_FILE_MACHINE_AMD64; stack_frame.AddrPC.Offset = ctx.Rip; stack_frame.AddrFrame.Offset = ctx.Rbp; stack_frame.AddrStack.Offset = ctx.Rsp; -#else +#elif defined(_M_IX86) int machine_type = IMAGE_FILE_MACHINE_I386; stack_frame.AddrPC.Offset = ctx.Eip; stack_frame.AddrFrame.Offset = ctx.Ebp; stack_frame.AddrStack.Offset = ctx.Esp; +#elif defined(_M_ARM64) + int machine_type = IMAGE_FILE_MACHINE_ARM64; + stack_frame.AddrPC.Offset = ctx.Pc; +# if defined(NONAMELESSUNION) + stack_frame.AddrFrame.Offset = ctx.DUMMYUNIONNAME.DUMMYSTRUCTNAME.Fp; +# else + stack_frame.AddrFrame.Offset = ctx.Fp; +# endif + stack_frame.AddrStack.Offset = ctx.Sp; +#elif defined(_M_ARM) + int machine_type = IMAGE_FILE_MACHINE_ARM; + stack_frame.AddrPC.Offset = ctx.Pc; + stack_frame.AddrFrame.Offset = ctx.R11; + stack_frame.AddrStack.Offset = ctx.Sp; +#else +# error "Platform not supported!" #endif stack_frame.AddrPC.Mode = AddrModeFlat; stack_frame.AddrFrame.Mode = AddrModeFlat; diff --git a/thirdparty/sentry-native/tests/assertions.py b/thirdparty/sentry-native/tests/assertions.py index 9ecc88fd21..934858cea9 100644 --- a/thirdparty/sentry-native/tests/assertions.py +++ b/thirdparty/sentry-native/tests/assertions.py @@ -55,9 +55,9 @@ def assert_meta( } expected_sdk = { "name": "sentry.native", - "version": "0.5.4", + "version": "0.6.0", "packages": [ - {"name": "github:getsentry/sentry-native", "version": "0.5.4"}, + {"name": "github:getsentry/sentry-native", "version": "0.6.0"}, ], } if is_android: diff --git a/thirdparty/sentry-native/tests/cmake.py b/thirdparty/sentry-native/tests/cmake.py index a0566023a3..35c48a8b57 100644 --- a/thirdparty/sentry-native/tests/cmake.py +++ b/thirdparty/sentry-native/tests/cmake.py @@ -143,7 +143,7 @@ def cmake(cwd, targets, options=None): cflags = [] if os.environ.get("ERROR_ON_WARNINGS"): cflags.append("-Werror") - if sys.platform == "win32": + if sys.platform == "win32" and not os.environ.get("TEST_MINGW"): # MP = object level parallelism, WX = warnings as errors cpus = os.cpu_count() cflags.append("/WX /MP{}".format(cpus)) diff --git a/thirdparty/sentry-native/tests/test_integration_http.py b/thirdparty/sentry-native/tests/test_integration_http.py index ebf69be4f3..b1a3f22102 100644 --- a/thirdparty/sentry-native/tests/test_integration_http.py +++ b/thirdparty/sentry-native/tests/test_integration_http.py @@ -24,7 +24,7 @@ from .assertions import ( pytestmark = pytest.mark.skipif(not has_http, reason="tests need http") auth_header = ( - "Sentry sentry_key=uiaeosnrtdy, sentry_version=7, sentry_client=sentry.native/0.5.4" + "Sentry sentry_key=uiaeosnrtdy, sentry_version=7, sentry_client=sentry.native/0.6.0" ) diff --git a/thirdparty/sentry-native/tests/unit/CMakeLists.txt b/thirdparty/sentry-native/tests/unit/CMakeLists.txt index 7c9dc6d173..93acedf270 100644 --- a/thirdparty/sentry-native/tests/unit/CMakeLists.txt +++ b/thirdparty/sentry-native/tests/unit/CMakeLists.txt @@ -54,6 +54,7 @@ target_link_libraries(sentry_test_unit PRIVATE ${SENTRY_LINK_LIBRARIES} ${SENTRY_INTERFACE_LINK_LIBRARIES} "$<$:rt>" + "$<$,$>:-Wl,-E,--build-id=sha1>" ) if(MINGW) diff --git a/thirdparty/sentry-native/tests/unit/test_session.c b/thirdparty/sentry-native/tests/unit/test_session.c index 59fa8774cc..fbe586a02a 100644 --- a/thirdparty/sentry-native/tests/unit/test_session.c +++ b/thirdparty/sentry-native/tests/unit/test_session.c @@ -26,7 +26,7 @@ send_envelope(const sentry_envelope_t *envelope, void *data) SENTRY_VALUE_TYPE_STRING); TEST_CHECK_STRING_EQUAL( sentry_value_as_string(sentry_value_get_by_key(session, "status")), - "exited"); + *called == 2 ? "crashed" : "exited"); TEST_CHECK_STRING_EQUAL( sentry_value_as_string(sentry_value_get_by_key(session, "did")), *called == 1 ? "foo@blabla.invalid" : "swatinem"); @@ -83,9 +83,12 @@ SENTRY_TEST(session_basics) user, "username", sentry_value_new_string("swatinem")); sentry_set_user(user); + sentry_end_session_with_status(SENTRY_SESSION_STATUS_CRASHED); + sentry_start_session(); + sentry_close(); - TEST_CHECK_INT_EQUAL(called, 2); + TEST_CHECK_INT_EQUAL(called, 3); } typedef struct {