diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 358889d8dbc37..6d6cd2b273c01 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -436,7 +436,7 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_copyable_function`` *unimplemented* ---------------------------------------------------------- ----------------- - ``__cpp_lib_debugging`` *unimplemented* + ``__cpp_lib_debugging`` ``202311L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_default_template_type_for_algorithm_values`` *unimplemented* ---------------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst index e56f0a88db138..98ebffcfe857f 100644 --- a/libcxx/docs/ReleaseNotes/22.rst +++ b/libcxx/docs/ReleaseNotes/22.rst @@ -40,6 +40,8 @@ Implemented Papers - P2321R2: ``zip`` (`Github `__) (The paper is partially implemented. ``zip_transform_view`` is implemented in this release) +- P2546R5: Debugging support (`Github `__) +- P2810R4: ``is_debugger_present`` is_replaceable(`Github `__) - P3168R2: Give ``std::optional`` Range Support (`Github `__) Improvements and New Features diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index f873d16808afe..58524d77d0570 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -29,7 +29,7 @@ "","","","","","" "`P0543R3 `__","Saturation arithmetic","2023-11 (Kona)","|Complete|","18","`#105390 `__","" "`P2407R5 `__","Freestanding Library: Partial Classes","2023-11 (Kona)","","","`#105391 `__","" -"`P2546R5 `__","Debugging Support","2023-11 (Kona)","","","`#105392 `__","" +"`P2546R5 `__","Debugging Support","2023-11 (Kona)","|Complete|","22","`#105392 `__","" "`P2905R2 `__","Runtime format strings","2023-11 (Kona)","|Complete|","18","`#105393 `__","" "`P2918R2 `__","Runtime format strings II","2023-11 (Kona)","|Complete|","18","`#105394 `__","" "`P2909R4 `__","Fix formatting of code units as integers (Dude, where’s my ``char``?)","2023-11 (Kona)","|Complete|","18","`#105395 `__","" @@ -57,7 +57,7 @@ "`P2542R8 `__","``views::concat``","2024-03 (Tokyo)","","","`#105419 `__","" "`P2591R5 `__","Concatenation of strings and string views","2024-03 (Tokyo)","|Complete|","19","`#105420 `__","" "`P2248R8 `__","Enabling list-initialization for algorithms","2024-03 (Tokyo)","","","`#105421 `__","" -"`P2810R4 `__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","","","`#105422 `__","" +"`P2810R4 `__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","|Complete|","22","`#105422 `__","" "`P1068R11 `__","Vector API for random number generation","2024-03 (Tokyo)","","","`#105423 `__","" "`P2944R3 `__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Complete|","21","`#105424 `__","The changes to ``tuple``'s equality overload from P2165R4 are not yet implemented." "`P2642R6 `__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","","`#105425 `__","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index db918a16e9a61..5e9698a694981 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -990,6 +990,7 @@ set(files cuchar cwchar cwctype + debugging deque errno.h exception diff --git a/libcxx/include/__configuration/availability.h b/libcxx/include/__configuration/availability.h index 2fbc34a3cf8a2..d1edd7fd39c12 100644 --- a/libcxx/include/__configuration/availability.h +++ b/libcxx/include/__configuration/availability.h @@ -340,6 +340,11 @@ #define _LIBCPP_AVAILABILITY_HAS_BAD_EXPECTED_ACCESS_KEY_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_19 #define _LIBCPP_AVAILABILITY_BAD_EXPECTED_ACCESS_KEY_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE +// This controls the availability of the C++26 debugging functions. +// The platform specific implementation is built in the library. +#define _LIBCPP_AVAILABILITY_HAS_DEBUGGING _LIBCPP_INTRODUCED_IN_LLVM_21 +#define _LIBCPP_AVAILABILITY_DEBUGGING _LIBCPP_INTRODUCED_IN_LLVM_21_ATTRIBUTE + // This controls the availability of floating-point std::from_chars functions. // These overloads were added later than the integer overloads. #define _LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_20 diff --git a/libcxx/include/debugging b/libcxx/include/debugging new file mode 100644 index 0000000000000..b9157859d4440 --- /dev/null +++ b/libcxx/include/debugging @@ -0,0 +1,65 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_DEBUGGING +#define _LIBCPP_DEBUGGING + +/* +// all freestanding +namespace std { + // [debugging.utility], utility + void breakpoint() noexcept; + void breakpoint_if_debugging() noexcept; + bool is_debugger_present() noexcept; +} +*/ + +#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +# include <__cxx03/__config> +#else + +# include <__config> +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 26 + +_LIBCPP_AVAILABILITY_DEBUGGING _LIBCPP_EXPORTED_FROM_ABI void __breakpoint() noexcept; + +_LIBCPP_AVAILABILITY_DEBUGGING _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE inline void breakpoint() noexcept { +# if __has_builtin(__builtin_debugtrap) + __builtin_debugtrap(); +# elif defined(_MSC_VER) + __debugbreak(); +# else + __breakpoint(); +# endif +} + +_LIBCPP_AVAILABILITY_DEBUGGING _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_OVERRIDABLE_FUNC_VIS bool +is_debugger_present() noexcept; + +_LIBCPP_AVAILABILITY_DEBUGGING _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE inline void +breakpoint_if_debugging() noexcept { + if (is_debugger_present()) + breakpoint(); +} + +# endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) + +#endif // _LIBCPP_DEBUGGING diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 63cf8e847751f..d6bf363c6834e 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1221,6 +1221,11 @@ module std [system] { export * } + module debugging { + header "debugging" + export * + } + module deque { module fwd { header "__fwd/deque.h" } diff --git a/libcxx/include/version b/libcxx/include/version index 16917a3bd9ddd..71f70b62cc0e2 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -557,7 +557,9 @@ __cpp_lib_void_t 201411L # define __cpp_lib_constexpr_queue 202502L # define __cpp_lib_constrained_equality 202411L // # define __cpp_lib_copyable_function 202306L -// # define __cpp_lib_debugging 202311L +# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_AVAILABILITY_HAS_DEBUGGING) +# define __cpp_lib_debugging 202311L +# endif // # define __cpp_lib_default_template_type_for_algorithm_values 202403L // # define __cpp_lib_format_path 202403L // # define __cpp_lib_freestanding_algorithm 202311L diff --git a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist index 162757c7e37ec..c83963a508be4 100644 --- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist +++ b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist @@ -963,6 +963,7 @@ {'is_defined': True, 'name': '__ZNSt3__111timed_mutexC2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__111timed_mutexD1Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__111timed_mutexD2Ev', 'type': 'FUNC'} +{'is_defined': True, 'name': '__ZNSt3__112__breakpointEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__112__do_nothingEPv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__112__get_sp_mutEPKv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__112__next_primeEm', 'type': 'FUNC'} @@ -1562,6 +1563,7 @@ {'is_defined': True, 'name': '__ZNSt3__119__thread_local_dataEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} +{'is_defined': True, 'name': '__ZNSt3__119is_debugger_presentEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__120__get_collation_nameEPKc', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__120__libcpp_atomic_waitEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEEx', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__120__libcpp_atomic_waitEPVKvx', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/i686-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/i686-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist index 4b6f3548ce495..e565adf9badd1 100644 --- a/libcxx/lib/abi/i686-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist +++ b/libcxx/lib/abi/i686-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist @@ -599,6 +599,7 @@ {'is_defined': True, 'name': '_ZNSt6__ndk111timed_mutexC2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk111timed_mutexD1Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk111timed_mutexD2Ev', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt6__ndk112__breakpointEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk112__do_nothingEPv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk112__get_sp_mutEPKv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk112__next_primeEj', 'type': 'FUNC'} @@ -1198,6 +1199,7 @@ {'is_defined': True, 'name': '_ZNSt6__ndk119__thread_local_dataEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt6__ndk119is_debugger_presentEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk120__get_collation_nameEPKc', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk120__libcpp_atomic_waitEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEEi', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk120__libcpp_atomic_waitEPVKvi', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist index 2b85596bd87f6..bf5b3e9ab78a2 100644 --- a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist +++ b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist @@ -324,6 +324,7 @@ {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__111timed_mutexC2Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__111timed_mutexD1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__111timed_mutexD2Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'} +{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112__breakpointEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112__do_nothingEPv', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112__get_sp_mutEPKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112__next_primeEm', 'storage_mapping_class': 'DS', 'type': 'FUNC'} @@ -1709,6 +1710,7 @@ {'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'} +{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119is_debugger_presentEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__122__libcpp_verbose_abortEPKcz', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'storage_mapping_class': 'DS', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist index 6ebdab96ed455..6739db364663c 100644 --- a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist +++ b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist @@ -324,6 +324,7 @@ {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__111timed_mutexC2Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__111timed_mutexD1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__111timed_mutexD2Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'} +{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112__breakpointEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112__do_nothingEPv', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112__get_sp_mutEPKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__112__next_primeEm', 'storage_mapping_class': 'DS', 'type': 'FUNC'} @@ -1709,6 +1710,7 @@ {'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'} +{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119is_debugger_presentEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__122__libcpp_verbose_abortEPKcz', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'storage_mapping_class': 'DS', 'type': 'FUNC'} {'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'storage_mapping_class': 'DS', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist index f6f7d7fd8265a..d2820af6c1481 100644 --- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist +++ b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist @@ -973,6 +973,7 @@ {'is_defined': True, 'name': '__ZNSt3__112__rs_defaultD1Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__112__rs_defaultD2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__112__rs_defaultclEv', 'type': 'FUNC'} +{'is_defined': True, 'name': '__ZNSt3__112__breakpointEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__112bad_weak_ptrD0Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__112bad_weak_ptrD1Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__112bad_weak_ptrD2Ev', 'type': 'FUNC'} @@ -1561,6 +1562,7 @@ {'is_defined': True, 'name': '__ZNSt3__119__thread_local_dataEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} +{'is_defined': True, 'name': '__ZNSt3__119is_debugger_presentEv', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__120__get_collation_nameEPKc', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__120__libcpp_atomic_waitEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEEx', 'type': 'FUNC'} {'is_defined': True, 'name': '__ZNSt3__120__libcpp_atomic_waitEPVKvx', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/x86_64-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist index 45f3d7c5904e8..9caafb58fc9ad 100644 --- a/libcxx/lib/abi/x86_64-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist +++ b/libcxx/lib/abi/x86_64-linux-android21.libcxxabi.v1.stable.exceptions.nonew.abilist @@ -599,6 +599,7 @@ {'is_defined': True, 'name': '_ZNSt6__ndk111timed_mutexC2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk111timed_mutexD1Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk111timed_mutexD2Ev', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt6__ndk112__breakpointEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk112__do_nothingEPv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk112__get_sp_mutEPKv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk112__next_primeEm', 'type': 'FUNC'} @@ -1198,6 +1199,7 @@ {'is_defined': True, 'name': '_ZNSt6__ndk119__thread_local_dataEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt6__ndk119is_debugger_presentEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk120__get_collation_nameEPKc', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk120__libcpp_atomic_waitEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEEi', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt6__ndk120__libcpp_atomic_waitEPVKvi', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist index de8cf6deef1df..87f3794aa6c84 100644 --- a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist +++ b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist @@ -613,6 +613,7 @@ {'is_defined': True, 'name': '_ZNSt3__111timed_mutexC2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__111timed_mutexD1Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__111timed_mutexD2Ev', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__112__breakpointEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112__do_nothingEPv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112__get_sp_mutEPKv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112__next_primeEm', 'type': 'FUNC'} @@ -1212,6 +1213,7 @@ {'is_defined': True, 'name': '_ZNSt3__119__thread_local_dataEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__119is_debugger_presentEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__120__get_collation_nameEPKc', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__120__libcpp_atomic_waitEPVKNS_17__cxx_atomic_implIlNS_22__cxx_atomic_base_implIlEEEEl', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__120__libcpp_atomic_waitEPVKvl', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist index 8c55c4385f6f6..449dff73caac2 100644 --- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist +++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist @@ -611,6 +611,7 @@ {'is_defined': True, 'name': '_ZNSt3__111timed_mutexC2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__111timed_mutexD1Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__111timed_mutexD2Ev', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__112__breakpointEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112__do_nothingEPv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112__get_sp_mutEPKv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112__next_primeEm', 'type': 'FUNC'} @@ -1210,6 +1211,7 @@ {'is_defined': True, 'name': '_ZNSt3__119__thread_local_dataEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__119is_debugger_presentEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__120__get_collation_nameEPKc', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__120__libcpp_atomic_waitEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEEi', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__120__libcpp_atomic_waitEPVKvi', 'type': 'FUNC'} diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist index 51caa07a74330..41cd2e4896ea9 100644 --- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist +++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist @@ -582,6 +582,7 @@ {'is_defined': True, 'name': '_ZNSt3__111timed_mutexC2Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__111timed_mutexD1Ev', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__111timed_mutexD2Ev', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__112__breakpointEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112__do_nothingEPv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112__get_sp_mutEPKv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__112__next_primeEm', 'type': 'FUNC'} @@ -1181,6 +1182,7 @@ {'is_defined': True, 'name': '_ZNSt3__119__thread_local_dataEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'type': 'FUNC'} +{'is_defined': True, 'name': '_ZNSt3__119is_debugger_presentEv', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__120__get_collation_nameEPKc', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__120__libcpp_atomic_waitEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEEi', 'type': 'FUNC'} {'is_defined': True, 'name': '_ZNSt3__120__libcpp_atomic_waitEPVKvi', 'type': 'FUNC'} diff --git a/libcxx/modules/CMakeLists.txt b/libcxx/modules/CMakeLists.txt index d47d19a475531..5bcb5ed2fa2a8 100644 --- a/libcxx/modules/CMakeLists.txt +++ b/libcxx/modules/CMakeLists.txt @@ -37,6 +37,7 @@ set(LIBCXX_MODULE_STD_SOURCES std/cuchar.inc std/cwchar.inc std/cwctype.inc + std/debugging.inc std/deque.inc std/exception.inc std/execution.inc diff --git a/libcxx/modules/std.compat.cppm.in b/libcxx/modules/std.compat.cppm.in index dd7385bf33a42..8a22be2d5699f 100644 --- a/libcxx/modules/std.compat.cppm.in +++ b/libcxx/modules/std.compat.cppm.in @@ -48,9 +48,6 @@ module; // into thinking that libc++ provides the header. // #ifndef _WIN32 -# if __has_include() -# error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" -# endif // __has_include() # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() diff --git a/libcxx/modules/std.cppm.in b/libcxx/modules/std.cppm.in index 984b18321923c..b2458474a29c5 100644 --- a/libcxx/modules/std.cppm.in +++ b/libcxx/modules/std.cppm.in @@ -55,6 +55,7 @@ module; #include #include #include +#include #include #include #include @@ -132,9 +133,6 @@ module; // into thinking that libc++ provides the header. // #ifndef _WIN32 -# if __has_include() -# error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" -# endif // __has_include() # if __has_include() # error "please update the header information for in headers_not_available in utils/libcxx/header_information.py" # endif // __has_include() diff --git a/libcxx/modules/std/debugging.inc b/libcxx/modules/std/debugging.inc new file mode 100644 index 0000000000000..9f65024c55c62 --- /dev/null +++ b/libcxx/modules/std/debugging.inc @@ -0,0 +1,17 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +export namespace std { +#if _LIBCPP_STD_VER >= 26 + // [debugging.utility], utility + using std::breakpoint; + using std::breakpoint_if_debugging; + using std::is_debugger_present; +#endif +} // namespace std diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt index f59fe0e08fccb..390cea7e47e9f 100644 --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -6,6 +6,7 @@ set(LIBCXX_SOURCES call_once.cpp charconv.cpp chrono.cpp + debugging.cpp error_category.cpp exception.cpp expected.cpp diff --git a/libcxx/src/debugging.cpp b/libcxx/src/debugging.cpp new file mode 100644 index 0000000000000..e6eb8e472d77b --- /dev/null +++ b/libcxx/src/debugging.cpp @@ -0,0 +1,180 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include <__assert> +#include <__config> +#include + +#if defined(_LIBCPP_WIN32API) +# define WIN32_LEAN_AND_MEAN +# define NOMINMAX +# include +#else +# include +#endif + +#if defined(_AIX) +# include +# include +# include +# include +# include +# include +# include +# include +#elif defined(__APPLE__) || defined(__FreeBSD__) +# if defined(__FreeBSD__) // Include order matters. +# include +# include +# include +# include +# endif // defined(__FreeBSD__) +# include +# include +# include +# include +#elif defined(__linux__) +# include +# include +# include +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// `breakpoint()` implementation + +_LIBCPP_EXPORTED_FROM_ABI void __breakpoint() noexcept { +#if defined(_LIBCPP_WIN32API) + DebugBreak(); +#else + raise(SIGTRAP); +#endif // defined(_LIBCPP_WIN32API) +} + +// `is_debugger_present()` implementation + +_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_WEAK bool is_debugger_present() noexcept { +#if defined(_LIBCPP_WIN32API) + + return IsDebuggerPresent(); + +#elif defined(_AIX) + + // Get the status information of a process by memory mapping the file /proc/PID/status. + // https://www.ibm.com/docs/en/aix/7.3?topic=files-proc-file + char __filename[] = "/proc/4294967295/status"; + if (auto [__ptr, __ec] = std::to_chars(__filename + 6, __filename + 16, ::getpid()); __ec == std::errc()) { + ::strcpy(__ptr, "/status"); + } else { + _LIBCPP_ASSERT_INTERNAL(false, "Could not convert pid to cstring."); + return false; + } + + int __fd = ::open(__filename, O_RDONLY); + if (__fd < 0) { + _LIBCPP_ASSERT_INTERNAL(false, "Could not open '/proc/{pid}/status' for reading."); + return false; + } + + pstatus_t __status; + if (::read(__fd, &__status, sizeof(pstatus_t)) < static_cast(sizeof(pstatus_t))) { + _LIBCPP_ASSERT_INTERNAL(false, "Could not read from '/proc/{pid}/status'."); + return false; + } + + if (__status.pr_flag & STRC) + return true; + + return false; + +#elif defined(__APPLE__) || defined(__FreeBSD__) + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + + // Technical Q&A QA1361: Detecting the Debugger + // https://developer.apple.com/library/archive/qa/qa1361/_index.html + + // Initialize mib, which tells 'sysctl' to fetch the information about the current process. + + array __mib{CTL_KERN, KERN_PROC, KERN_PROC_PID, ::getpid()}; + + // Initialize the flags so that, if 'sysctl' fails for some bizarre + // reason, we get a predictable result. + + struct kinfo_proc __info{}; + + // Call sysctl. + // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/sysctl.3.html + + size_t __info_size = sizeof(__info); + if (::sysctl(__mib.data(), __mib.size(), &__info, &__info_size, nullptr, 0) != 0) { + _LIBCPP_ASSERT_INTERNAL(false, "'sysctl' runtime error"); + return false; + } + + // If the process is being debugged if the 'P_TRACED' flag is set. + // https://github.com/freebsd/freebsd-src/blob/7f3184ba797452703904d33377dada5f0f8eae96/sys/sys/proc.h#L822 + +# if defined(__FreeBSD__) + const auto __p_flag = __info.ki_flag; +# else // __APPLE__ + const auto __p_flag = __info.kp_proc.p_flag; +# endif + + return ((__p_flag & P_TRACED) != 0); + +#elif defined(__linux__) + +# if defined(_LIBCPP_HAS_NO_FILESYSTEM) + _LIBCPP_ASSERT_INTERNAL(false, + "Function is not available. Could not open '/proc/self/status' for reading, libc++ was " + "compiled with _LIBCPP_HAS_NO_FILESYSTEM."); + return false; +# else + // https://docs.kernel.org/filesystems/proc.html + + // Get the status information of a process by reading the file /proc/PID/status. + // The link 'self' points to the process reading the file system. + FILE* __proc_status_fp = ::fopen("/proc/self/status", "r"); + if (__proc_status_fp == nullptr) { + _LIBCPP_ASSERT_INTERNAL(false, "Could not open '/proc/self/status' for reading."); + return false; + } + + char* __line = nullptr; + size_t __lineLen = 0; + const char* __tokenStr = "TracerPid:"; + bool __is_debugger_present = false; + + while ((::getline(&__line, &__lineLen, __proc_status_fp)) != -1) { + // If the process is being debugged "TracerPid"'s value is non-zero. + char* __tokenPos = ::strstr(__line, __tokenStr); + if (__tokenPos == nullptr) { + continue; + } + + __is_debugger_present = (::atoi(__tokenPos + ::strlen(__tokenStr)) != 0); + break; + } + + ::free(__line); + ::fclose(__proc_status_fp); + + return __is_debugger_present; +# endif // _LIBCPP_HAS_NO_FILESYSTEM + +#else + + // The implementation returns 'false' by default. + return false; + +#endif // defined(_LIBCPP_WIN32API) +} + +_LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv index c0031543e47bc..0ecb77b18ca88 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -514,6 +514,7 @@ cwchar cstddef cwchar cwctype cwchar version cwctype cctype +debugging version deque algorithm deque array deque atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv index c0031543e47bc..0ecb77b18ca88 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -514,6 +514,7 @@ cwchar cstddef cwchar cwctype cwchar version cwctype cctype +debugging version deque algorithm deque array deque atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv index c2eb5b44e8d7a..beec20cdbb284 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -524,6 +524,7 @@ cwchar cstddef cwchar cwctype cwchar version cwctype cctype +debugging version deque algorithm deque array deque atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv index 332cb62f35b5f..85acb0fd2008c 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -516,6 +516,7 @@ cwchar cstddef cwchar cwctype cwchar version cwctype cctype +debugging version deque algorithm deque array deque atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv index 55c79acff5a8f..ddcc66d4bce40 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -512,6 +512,7 @@ cwchar cstddef cwchar cwctype cwchar version cwctype cctype +debugging version deque algorithm deque array deque atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv index cb23c7a98de1b..3d7e81b1c75c5 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -239,6 +239,7 @@ ctgmath version cwchar cctype cwchar cwctype cwctype cctype +debugging version deque cctype deque compare deque cstdint diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv index 5f906338f4b7c..957e5de2c8a48 100644 --- a/libcxx/test/libcxx/transitive_includes/cxx26.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -235,6 +235,7 @@ ctgmath version cwchar cctype cwchar cwctype cwctype cctype +debugging version deque cctype deque compare deque cstdint diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/debugging.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/debugging.version.compile.pass.cpp new file mode 100644 index 0000000000000..09f7206ea36c3 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/debugging.version.compile.pass.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. + +// + +// Test the feature test macros defined by + +// clang-format off + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_debugging +# error "__cpp_lib_debugging should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_debugging +# error "__cpp_lib_debugging should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_debugging +# error "__cpp_lib_debugging should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 20 + +# ifdef __cpp_lib_debugging +# error "__cpp_lib_debugging should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 23 + +# ifdef __cpp_lib_debugging +# error "__cpp_lib_debugging should not be defined before c++26" +# endif + +#elif TEST_STD_VER > 23 + +# if TEST_STD_VER >= 26 && defined(_LIBCPP_AVAILABILITY_HAS_DEBUGGING) +# ifndef __cpp_lib_debugging +# error "__cpp_lib_debugging should be defined in c++26" +# endif +# if __cpp_lib_debugging != 202311L +# error "__cpp_lib_debugging should have the value 202311L in c++26" +# endif +# else +# ifdef __cpp_lib_debugging +# error "__cpp_lib_debugging should not be defined when the requirement 'TEST_STD_VER >= 26 && defined(_LIBCPP_AVAILABILITY_HAS_DEBUGGING)' is not met!" +# endif +# endif + +#endif // TEST_STD_VER > 23 + +// clang-format on diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index cde2f258b7732..be6dcb544201d 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -6665,7 +6665,7 @@ # error "__cpp_lib_coroutine should have the value 201902L in c++26" # endif -# if !defined(_LIBCPP_VERSION) +# if TEST_STD_VER >= 26 && defined(_LIBCPP_AVAILABILITY_HAS_DEBUGGING) # ifndef __cpp_lib_debugging # error "__cpp_lib_debugging should be defined in c++26" # endif @@ -6674,7 +6674,7 @@ # endif # else # ifdef __cpp_lib_debugging -# error "__cpp_lib_debugging should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_debugging should not be defined when the requirement 'TEST_STD_VER >= 26 && defined(_LIBCPP_AVAILABILITY_HAS_DEBUGGING)' is not met!" # endif # endif diff --git a/libcxx/test/std/utilities/debugging/is_debugger_present.assertion.pass.cpp b/libcxx/test/std/utilities/debugging/is_debugger_present.assertion.pass.cpp new file mode 100644 index 0000000000000..84778d02b3040 --- /dev/null +++ b/libcxx/test/std/utilities/debugging/is_debugger_present.assertion.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// REQUIRES: linux && no-filesystem + +// + +// bool is_debugger_present() noexcept; + +#include +#include +#include + +#include "check_assertion.h" + +// Test without debugger. + +void test() { + TEST_LIBCPP_ASSERT_FAILURE( + std::is_debugger_present(), + "Function is not available. Could not open '/proc/self/status' for reading, libc++ was " + "compiled with _LIBCPP_HAS_NO_FILESYSTEM."); +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/debugging/is_debugger_present.pass.cpp b/libcxx/test/std/utilities/debugging/is_debugger_present.pass.cpp new file mode 100644 index 0000000000000..ef3c33fbad0dd --- /dev/null +++ b/libcxx/test/std/utilities/debugging/is_debugger_present.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 + +// + +// bool is_debugger_present() noexcept; + +#include +#include +#include + +// Test without debugger. + +void test() { + static_assert(noexcept(std::is_debugger_present())); + + std::same_as decltype(auto) isDebuggerPresent = std::is_debugger_present(); + assert(!isDebuggerPresent); +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/debugging/is_debugger_present__dbx.cmd b/libcxx/test/std/utilities/debugging/is_debugger_present__dbx.cmd new file mode 100644 index 0000000000000..bfc84b099cc9c --- /dev/null +++ b/libcxx/test/std/utilities/debugging/is_debugger_present__dbx.cmd @@ -0,0 +1,4 @@ +stop in StopForDebugger +run +print isDebuggerPresent +quit diff --git a/libcxx/test/std/utilities/debugging/is_debugger_present__dbx.grep b/libcxx/test/std/utilities/debugging/is_debugger_present__dbx.grep new file mode 100644 index 0000000000000..201556e6f9e14 --- /dev/null +++ b/libcxx/test/std/utilities/debugging/is_debugger_present__dbx.grep @@ -0,0 +1,2 @@ + 44 void StopForDebugger(void*) {} +true diff --git a/libcxx/test/std/utilities/debugging/is_debugger_present__dbx.sh.cpp b/libcxx/test/std/utilities/debugging/is_debugger_present__dbx.sh.cpp new file mode 100644 index 0000000000000..6db7f59ae6a4e --- /dev/null +++ b/libcxx/test/std/utilities/debugging/is_debugger_present__dbx.sh.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// REQUIRES: host-has-dbx + +// RUN: %{cxx} %{flags} %s -o %t.exe %{compile_flags} -g %{link_flags} +// RUN: "%{dbx}" -c %S/is_debugger_present__dbx.cmd %t.exe \ +// RUN: | grep -qFf %S/is_debugger_present__dbx.grep + +// + +// bool is_debugger_present() noexcept; + +#include +#include +#include + +#include "test_macros.h" + +#ifdef TEST_COMPILER_GCC +# define OPT_NONE __attribute__((noinline)) +#else +# define OPT_NONE __attribute__((optnone)) +#endif + +// Prevents the compiler optimizing away the parameter in the caller function. +template +void MarkAsLive(Type&&) OPT_NONE; +template +void MarkAsLive(Type&&) {} + +void StopForDebugger(void*) OPT_NONE; +void StopForDebugger(void*) {} + +void test() { + static_assert(noexcept(std::is_debugger_present())); + + std::same_as decltype(auto) isDebuggerPresent = std::is_debugger_present(); + MarkAsLive(isDebuggerPresent); + StopForDebugger(&isDebuggerPresent); +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/debugging/is_debugger_present__gdb.py b/libcxx/test/std/utilities/debugging/is_debugger_present__gdb.py new file mode 100644 index 0000000000000..ea7ecaeadf024 --- /dev/null +++ b/libcxx/test/std/utilities/debugging/is_debugger_present__gdb.py @@ -0,0 +1,120 @@ +# ===----------------------------------------------------------------------===## +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ===----------------------------------------------------------------------===## + +from __future__ import print_function +import gdb + +# https://sourceware.org/gdb/current/onlinedocs/gdb.html/Python.html + +test_failures = 0 + +# Sometimes the inital run command can fail to trace the process. +# (e.g. you don't have ptrace permissions) +# In these cases gdb still sends us an exited event so we cannot +# see what "run" printed to check for a warning message, since +# we get taken to our exit handler before we can look. +# Instead check that at least one test has been run by the time +# we exit. +has_run_tests = False + + +class CheckResult(gdb.Command): + """GDB Tester""" + + def __init__(self): + super(CheckResult, self).__init__("check_is_debugger_present", gdb.COMMAND_DATA) + + def invoke(self, arg, from_tty): + global has_run_tests + + try: + has_run_tests = True + + # Stack frame is: + # 0. StopForDebugger + # 1. Check `isDebuggerPresent` + + compare_frame = gdb.newest_frame().older() + testcase_frame = compare_frame.older() + test_loc = testcase_frame.find_sal() + + # Ignore the convenience variable name and newline + + gdb.newest_frame().select() + expectation_val = compare_frame.read_var("isDebuggerPresent") + + if not expectation_val: + global test_failures + + print("FAIL: " + test_loc.symtab.filename + ":" + str(test_loc.line)) + print("`isDebuggerPresent` value is `false`, value should be `true`") + + test_failures += 1 + else: + print("PASS: " + test_loc.symtab.filename + ":" + str(test_loc.line)) + + except RuntimeError as e: + # At this point, lots of different things could be wrong, so don't try to + # recover or figure it out. Don't exit either, because then it's + # impossible to debug the framework itself. + + print("FAIL: Something is wrong in the test framework.") + print(str(e)) + + test_failures += 1 + + +def exit_handler(event=None): + """Exit handler""" + + global test_failures + global has_run_tests + + if not has_run_tests: + print("FAILED test program did not run correctly, check gdb warnings") + test_failures = -1 + elif test_failures: + print(f"FAILED {test_failures} cases") + exit(test_failures) + + +def main(): + """Main entry point""" + # Start code executed at load time + + global test_failures + + # Disable terminal paging + + gdb.execute("set height 0") + gdb.execute("set python print-stack full") + + CheckResult() + test_bp = gdb.Breakpoint("StopForDebugger") + test_bp.enabled = True + test_bp.silent = True + test_bp.commands = """check_is_debugger_present + continue""" + + # "run" won't return if the program exits; ensure the script regains control. + + # https://sourceware.org/gdb/current/onlinedocs/gdb.html/Events-In-Python.html + gdb.events.exited.connect(exit_handler) + gdb.execute("run") + + # If the program didn't exit, something went wrong, but we don't + # know what. Fail on exit. + + test_failures += 1 + exit_handler(None) + + print(f"Test failures count: {test_failures}") + + +if __name__ == "__main__": + main() diff --git a/libcxx/test/std/utilities/debugging/is_debugger_present__gdb.sh.cpp b/libcxx/test/std/utilities/debugging/is_debugger_present__gdb.sh.cpp new file mode 100644 index 0000000000000..7e0fc40eea19c --- /dev/null +++ b/libcxx/test/std/utilities/debugging/is_debugger_present__gdb.sh.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// REQUIRES: host-has-gdb-with-python +// The Android libc++ tests are run on a non-Android host, connected to an +// Android device over adb. gdb needs special support to make this work (e.g. +// gdbclient.py, ndk-gdb.py, gdbserver), and the Android organization doesn't +// support gdb anymore, favoring lldb instead. +// UNSUPPORTED: android + +// RUN: %{cxx} %{flags} %s -o %t.exe %{compile_flags} -g %{link_flags} +// RUN: "%{gdb}" %t.exe -ex "source %S/is_debugger_present__gdb.py" --silent + +// + +// bool is_debugger_present() noexcept; + +#include +#include +#include + +#include "test_macros.h" + +#ifdef TEST_COMPILER_GCC +# define OPT_NONE __attribute__((noinline)) +#else +# define OPT_NONE __attribute__((optnone)) +#endif + +// Prevents the compiler optimizing away the parameter in the caller function. +template +void MarkAsLive(Type&&) OPT_NONE; +template +void MarkAsLive(Type&&) {} + +void StopForDebugger(void*) OPT_NONE; +void StopForDebugger(void*) {} + +// Test with debugger attached: +// GDB command: `gdb is_debugger_present_with_debugger__gdb.sh -ex run -ex detach -ex quit --silent` + +void test() { + static_assert(noexcept(std::is_debugger_present())); + + std::same_as decltype(auto) isDebuggerPresent = std::is_debugger_present(); +#if defined(TEST_HAS_NO_FILESYSTEM) || defined(_PICOLIB_) + MarkAsLive(!isDebuggerPresent); +#else + MarkAsLive(isDebuggerPresent); +#endif + StopForDebugger(&isDebuggerPresent); +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/debugging/is_debugger_present__lldb.py b/libcxx/test/std/utilities/debugging/is_debugger_present__lldb.py new file mode 100644 index 0000000000000..e0c40daa2eb2f --- /dev/null +++ b/libcxx/test/std/utilities/debugging/is_debugger_present__lldb.py @@ -0,0 +1,84 @@ +# ===----------------------------------------------------------------------===## +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ===----------------------------------------------------------------------===## + +import lldb + +test_failures = 0 + +# Sometimes the inital run command can fail to trace the process. +# (e.g. you don't have ptrace permissions) +# In these cases gdb still sends us an exited event so we cannot +# see what "run" printed to check for a warning message, since +# we get taken to our exit handler before we can look. +# Instead check that at least one test has been run by the time +# we exit. +has_run_tests = False + + +def breakpoint_handler(frame, bp_loc, internal_dict): + global has_run_tests + + try: + has_run_tests = True + + module = frame.GetModule() + filename = module.compile_units[0].file + line = frame.GetLineEntry().GetLine() + parent = frame.get_parent_frame() + expectation_val = parent.FindVariable("isDebuggerPresent") + + if expectation_val is None or expectation_val.value == "false": + global test_failures + + print(f"FAIL: {filename}:{line}") + print("`isDebuggerPresent` value is `false`, value should be `true`") + + test_failures += 1 + else: + print(f"PASS: {filename}:{line}") + + except RuntimeError as e: + # At this point, lots of different things could be wrong, so don't try to + # recover or figure it out. Don't exit either, because then it's + # impossible to debug the framework itself. + + print("FAIL: Something is wrong in the test framework.") + print(str(e)) + + test_failures += 1 + + +def exit_handler(debugger): + """Exit handler""" + + global test_failures + global has_run_tests + + if not has_run_tests: + print("FAILED test program did not run correctly, check lldb warnings") + test_failures = -1 + elif test_failures: + test_failures -= 1 + print(f"FAILED {test_failures} cases") + + debugger.HandleCommand(f"exit {test_failures}") + + +def __lldb_init_module(debugger, internal_dict): + global test_failures + + target = debugger.GetSelectedTarget() + test_bp = target.BreakpointCreateByName("StopForDebugger") + test_bp.SetScriptCallbackFunction("is_debugger_present__lldb.breakpoint_handler") + test_bp.enabled = True + + debugger.HandleCommand("run") + + test_failures += 1 + + exit_handler(debugger) diff --git a/libcxx/test/std/utilities/debugging/is_debugger_present__lldb.sh.cpp b/libcxx/test/std/utilities/debugging/is_debugger_present__lldb.sh.cpp new file mode 100644 index 0000000000000..5c4aeaaa37470 --- /dev/null +++ b/libcxx/test/std/utilities/debugging/is_debugger_present__lldb.sh.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 +// REQUIRES: host-has-lldb +// The Android libc++ tests are run on a non-Android host, connected to an +// Android device over adb. +// UNSUPPORTED: android +// XFAIL: LIBCXX-PICOLIBC-FIXME + +// RUN: %{cxx} %{flags} %s -o %t.exe %{compile_flags} -g %{link_flags} +// RUN: "%{lldb}" %t.exe -o "command script import %S/is_debugger_present__lldb.py" + +// + +// bool is_debugger_present() noexcept; + +#include +#include +#include + +#include "test_macros.h" + +#ifdef TEST_COMPILER_GCC +# define OPT_NONE __attribute__((noinline)) +#else +# define OPT_NONE __attribute__((optnone)) +#endif + +// Prevents the compiler optimizing away the parameter in the caller function. +template +void MarkAsLive(Type&&) OPT_NONE; +template +void MarkAsLive(Type&&) {} + +void StopForDebugger(void*) OPT_NONE; +void StopForDebugger(void*) {} + +// Test with debugger attached: +// LLDB command: `lldb "is_debugger_present_with_debugger__lldb.sh" -o run -o detach -o quit` + +void test() { + static_assert(noexcept(std::is_debugger_present())); + + std::same_as decltype(auto) isDebuggerPresent = std::is_debugger_present(); +#if defined(TEST_HAS_NO_FILESYSTEM) || defined(_PICOLIB_) + MarkAsLive(!isDebuggerPresent); +#else + MarkAsLive(isDebuggerPresent); +#endif + StopForDebugger(&isDebuggerPresent); +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index c1e579c775746..5c7351e40c63d 100644 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -481,7 +481,8 @@ def add_version_header(tc): # "c++26": 202403, # P2810R4: is_debugger_present is_replaceable }, "headers": ["debugging"], - "unimplemented": True, + "test_suite_guard": "TEST_STD_VER >= 26 && defined(_LIBCPP_AVAILABILITY_HAS_DEBUGGING)", + "libcxx_guard": "_LIBCPP_STD_VER >= 26 && defined(_LIBCPP_AVAILABILITY_HAS_DEBUGGING)", }, { "name": "__cpp_lib_default_template_type_for_algorithm_values", diff --git a/libcxx/utils/libcxx/header_information.py b/libcxx/utils/libcxx/header_information.py index d06271a7908cc..e16d423a33428 100644 --- a/libcxx/utils/libcxx/header_information.py +++ b/libcxx/utils/libcxx/header_information.py @@ -163,7 +163,6 @@ def __hash__(self) -> int: # implemented yet. They are used in the generated module input. The C++23 standard # modules will fail to build if a header is added but this list is not updated. headers_not_available = list(map(Header, [ - "debugging", "generator", "hazard_pointer", "inplace_vector", @@ -186,6 +185,7 @@ def __hash__(self) -> int: "coroutine": "// UNSUPPORTED: c++03, c++11, c++14, c++17", "cwchar": "// UNSUPPORTED: no-wide-characters", "cwctype": "// UNSUPPORTED: no-wide-characters", + "debugging": "// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23", "experimental/iterator": "// UNSUPPORTED: c++03", "experimental/propagate_const": "// UNSUPPORTED: c++03", "experimental/simd": "// UNSUPPORTED: c++03", diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py index a964f3bdeeb46..4f1dcac67bb7c 100644 --- a/libcxx/utils/libcxx/test/features.py +++ b/libcxx/utils/libcxx/test/features.py @@ -598,6 +598,7 @@ def _getLocaleFlagsAction(cfg, locale, alts, members): name="LIBCXX-FREEBSD-FIXME", when=lambda cfg: "__FreeBSD__" in compilerMacros(cfg), ), + Feature(name="picolib", when=lambda cfg: "__PICOLIBC__" in compilerMacros(cfg)), Feature( name="LIBCXX-PICOLIBC-FIXME", when=lambda cfg: sourceBuilds( @@ -691,6 +692,43 @@ def _getLocaleFlagsAction(cfg, locale, alts, members): ), ] + +# Detect whether dbx debugger (available on AIX and others) is on the system. +def check_dbx(cfg): + dbx_path = shutil.which("dbx") + if dbx_path is None: + return False + + return True + + +DEFAULT_FEATURES += [ + Feature( + name="host-has-dbx", + when=check_dbx, + actions=[AddSubstitution("%{dbx}", lambda cfg: shutil.which("dbx"))], + ) +] + + +# Detect whether LLDB debugger is on the system. +def check_lldb(cfg): + lldb_path = shutil.which("lldb") + if lldb_path is None: + return False + + return True + + +DEFAULT_FEATURES += [ + Feature( + name="host-has-lldb", + when=check_lldb, + actions=[AddSubstitution("%{lldb}", lambda cfg: shutil.which("lldb"))], + ) +] + + # Detect whether GDB is on the system, has Python scripting and supports # adding breakpoint commands. If so add a substitution to access it. def check_gdb(cfg):