On Fri, 11 Apr 2025 at 10:31, Tomasz Kaminski <tkami...@redhat.com> wrote: > > > > On Fri, Apr 11, 2025 at 10:13 AM Jonathan Wakely <jwak...@redhat.com> wrote: >> >> On Fri, 11 Apr 2025 at 08:00, Tomasz Kaminski <tkami...@redhat.com> wrote: >> > >> > >> > >> > On Thu, Apr 10, 2025 at 6:53 PM Jonathan Wakely <jwak...@redhat.com> wrote: >> >> >> >> It would be good to provide a macOS definition of is_debugger_present as >> >> per https://developer.apple.com/library/archive/qa/qa1361/_index.html >> >> but that isn't included in this change. >> >> >> >> libstdc++-v3/ChangeLog: >> >> >> >> * config.h.in: Regenerate. >> >> * configure: Regenerate. >> >> * configure.ac: Check for facilities needed by <debugging>. >> >> * include/Makefile.am: Add new header. >> >> * include/Makefile.in: Regenerate. >> >> * include/bits/version.def (debugging): Add. >> >> * include/bits/version.h: Regenerate. >> >> * src/c++26/Makefile.am: Add new file. >> >> * src/c++26/Makefile.in: Regenerate. >> >> * include/std/debugging: New file. >> >> * src/c++26/debugging.cc: New file. >> >> * testsuite/19_diagnostics/debugging/breakpoint.cc: New test. >> >> * testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc: >> >> New test. >> >> * testsuite/19_diagnostics/debugging/is_debugger_present.cc: New >> >> test. >> >> --- >> >> >> >> I sent v1 of this patch in June last year: >> >> https://gcc.gnu.org/pipermail/gcc-patches/2024-June/653293.html >> >> My comments about testing with GDB still apply. >> >> >> >> Compared to v1, this adds a void __gnu_cxx::attach_debugger(bool) >> >> function that could be called by debuggers to announce that they are >> >> attaching and detaching. It also adds a systemtap probe point to >> >> std::breakpoint(). >> >> >> >> Tested x86_64-linux. >> >> >> >> N.B. this only adds new symbols to the libstdc++exp.a archive, not to >> >> libstdc++.so so it's not a risky change at this stage. >> >> >> >> libstdc++-v3/config.h.in | 9 + >> >> libstdc++-v3/configure | 22 +++ >> >> libstdc++-v3/configure.ac | 9 + >> >> libstdc++-v3/include/Makefile.am | 1 + >> >> libstdc++-v3/include/Makefile.in | 1 + >> >> libstdc++-v3/include/bits/version.def | 8 + >> >> libstdc++-v3/include/bits/version.h | 10 ++ >> >> libstdc++-v3/include/std/debugging | 77 ++++++++ >> >> libstdc++-v3/src/c++26/Makefile.am | 4 +- >> >> libstdc++-v3/src/c++26/Makefile.in | 7 +- >> >> libstdc++-v3/src/c++26/debugging.cc | 165 ++++++++++++++++++ >> >> .../19_diagnostics/debugging/breakpoint.cc | 13 ++ >> >> .../debugging/breakpoint_if_debugging.cc | 13 ++ >> >> .../debugging/is_debugger_present.cc | 14 ++ >> >> 14 files changed, 350 insertions(+), 3 deletions(-) >> >> create mode 100644 libstdc++-v3/include/std/debugging >> >> create mode 100644 libstdc++-v3/src/c++26/debugging.cc >> >> create mode 100644 >> >> libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint.cc >> >> create mode 100644 >> >> libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc >> >> create mode 100644 >> >> libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present.cc >> >> >> >> diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in >> >> index 77bbaf1beaa..3f1331ff36f 100644 >> >> --- a/libstdc++-v3/config.h.in >> >> +++ b/libstdc++-v3/config.h.in >> >> @@ -70,6 +70,9 @@ >> >> /* Define to 1 if you have the `cosl' function. */ >> >> #undef HAVE_COSL >> >> >> >> +/* Define to 1 if you have the <debugapi.h> header file. */ >> >> +#undef HAVE_DEBUGAPI_H >> >> + >> >> /* Define to 1 if you have the declaration of `strnlen', and to 0 if you >> >> don't. */ >> >> #undef HAVE_DECL_STRNLEN >> >> @@ -439,6 +442,9 @@ >> >> /* Define to 1 if you have the <sys/param.h> header file. */ >> >> #undef HAVE_SYS_PARAM_H >> >> >> >> +/* Define to 1 if you have the <sys/ptrace.h> header file. */ >> >> +#undef HAVE_SYS_PTRACE_H >> >> + >> >> /* Define to 1 if you have the <sys/resource.h> header file. */ >> >> #undef HAVE_SYS_RESOURCE_H >> >> >> >> @@ -850,6 +856,9 @@ >> >> /* Define if nl_langinfo_l should be used for std::text_encoding. */ >> >> #undef _GLIBCXX_USE_NL_LANGINFO_L >> >> >> >> +/* Define if /proc/self/status should be used for <debugging>. */ >> >> +#undef _GLIBCXX_USE_PROC_SELF_STATUS >> >> + >> >> /* Define if pthreads_num_processors_np is available in <pthread.h>. */ >> >> #undef _GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP >> >> >> >> diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure >> >> index 819a1d82876..8143df91c38 100755 >> >> --- a/libstdc++-v3/configure >> >> +++ b/libstdc++-v3/configure >> >> @@ -54700,6 +54700,28 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu >> >> >> >> >> >> >> >> +# For std::is_debugger_present >> >> +case "$target_os" in >> >> + linux*) >> >> + >> >> +$as_echo "#define _GLIBCXX_USE_PROC_SELF_STATUS 1" >>confdefs.h >> >> + >> >> + ;; >> >> +esac >> >> +for ac_header in sys/ptrace.h debugapi.h >> >> +do : >> >> + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` >> >> +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" >> >> "$ac_includes_default" >> >> +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : >> >> + cat >>confdefs.h <<_ACEOF >> >> +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 >> >> +_ACEOF >> >> + >> >> +fi >> >> + >> >> +done >> >> + >> >> + >> >> # Define documentation rules conditionally. >> >> >> >> # See if makeinfo has been installed and is modern enough >> >> diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac >> >> index a6c01b29e94..83adb46454e 100644 >> >> --- a/libstdc++-v3/configure.ac >> >> +++ b/libstdc++-v3/configure.ac >> >> @@ -587,6 +587,15 @@ GLIBCXX_CHECK_FILEBUF_NATIVE_HANDLES >> >> # For std::text_encoding >> >> GLIBCXX_CHECK_TEXT_ENCODING >> >> >> >> +# For std::is_debugger_present >> >> +case "$target_os" in >> >> + linux*) >> >> + AC_DEFINE([_GLIBCXX_USE_PROC_SELF_STATUS],1, >> >> + [Define if /proc/self/status should be used for >> >> <debugging>.]) >> >> + ;; >> >> +esac >> >> +AC_CHECK_HEADERS([sys/ptrace.h debugapi.h]) >> >> + >> >> # Define documentation rules conditionally. >> >> >> >> # See if makeinfo has been installed and is modern enough >> >> diff --git a/libstdc++-v3/include/Makefile.am >> >> b/libstdc++-v3/include/Makefile.am >> >> index 537774c2668..6bb3f3dc3d6 100644 >> >> --- a/libstdc++-v3/include/Makefile.am >> >> +++ b/libstdc++-v3/include/Makefile.am >> >> @@ -67,6 +67,7 @@ std_headers = \ >> >> ${std_srcdir}/codecvt \ >> >> ${std_srcdir}/complex \ >> >> ${std_srcdir}/condition_variable \ >> >> + ${std_srcdir}/debugging \ >> >> ${std_srcdir}/deque \ >> >> ${std_srcdir}/execution \ >> >> ${std_srcdir}/filesystem \ >> >> diff --git a/libstdc++-v3/include/Makefile.in >> >> b/libstdc++-v3/include/Makefile.in >> >> index 7b96b2207f8..81c3cfce4c4 100644 >> >> --- a/libstdc++-v3/include/Makefile.in >> >> +++ b/libstdc++-v3/include/Makefile.in >> >> @@ -423,6 +423,7 @@ std_freestanding = \ >> >> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/codecvt \ >> >> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/complex \ >> >> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/condition_variable \ >> >> +@GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/debugging \ >> >> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/deque \ >> >> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/execution \ >> >> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/filesystem \ >> >> diff --git a/libstdc++-v3/include/bits/version.def >> >> b/libstdc++-v3/include/bits/version.def >> >> index 2ec1b40bd38..092d0427e4a 100644 >> >> --- a/libstdc++-v3/include/bits/version.def >> >> +++ b/libstdc++-v3/include/bits/version.def >> >> @@ -1841,6 +1841,14 @@ ftms = { >> >> }; >> >> }; >> >> >> >> +ftms = { >> >> + name = debugging; >> >> + values = { >> >> + v = 202403; >> >> + cxxmin = 26; >> >> + }; >> >> >> >> +}; >> >> + >> >> ftms = { >> >> name = fstream_native_handle; >> >> values = { >> >> diff --git a/libstdc++-v3/include/bits/version.h >> >> b/libstdc++-v3/include/bits/version.h >> >> index 04c1349c84b..12892fc135d 100644 >> >> --- a/libstdc++-v3/include/bits/version.h >> >> +++ b/libstdc++-v3/include/bits/version.h >> >> @@ -2044,6 +2044,16 @@ >> >> #endif /* !defined(__cpp_lib_constexpr_new) && >> >> defined(__glibcxx_want_constexpr_new) */ >> >> #undef __glibcxx_want_constexpr_new >> >> >> >> +#if !defined(__cpp_lib_debugging) >> >> +# if (__cplusplus > 202302L) >> >> +# define __glibcxx_debugging 202403L >> >> +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_debugging) >> >> +# define __cpp_lib_debugging 202403L >> >> +# endif >> >> +# endif >> >> +#endif /* !defined(__cpp_lib_debugging) && >> >> defined(__glibcxx_want_debugging) */ >> >> +#undef __glibcxx_want_debugging >> >> + >> >> #if !defined(__cpp_lib_fstream_native_handle) >> >> # if (__cplusplus > 202302L) && _GLIBCXX_HOSTED >> >> # define __glibcxx_fstream_native_handle 202306L >> >> diff --git a/libstdc++-v3/include/std/debugging >> >> b/libstdc++-v3/include/std/debugging >> >> new file mode 100644 >> >> index 00000000000..4cf7e4acbc4 >> >> --- /dev/null >> >> +++ b/libstdc++-v3/include/std/debugging >> >> @@ -0,0 +1,77 @@ >> >> +// Debugging support -*- C++ -*- >> >> + >> >> +// Copyright The GNU Toolchain Authors. >> >> +// >> >> +// This file is part of the GNU ISO C++ Library. This library is free >> >> +// software; you can redistribute it and/or modify it under the >> >> +// terms of the GNU General Public License as published by the >> >> +// Free Software Foundation; either version 3. >> >> + >> >> +// This library is distributed in the hope that it will be useful, >> >> +// but WITHOUT ANY WARRANTY; without even the implied warranty of >> >> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> >> +// GNU General Public License for more details. >> >> + >> >> +// Under Section 7 of GPL version 3, you are granted additional >> >> +// permissions described in the GCC Runtime Library Exception, version >> >> +// 3.1, as published by the Free Software Foundation. >> >> + >> >> +// You should have received a copy of the GNU General Public License and >> >> +// a copy of the GCC Runtime Library Exception along with this program; >> >> +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see >> >> +// <http://www.gnu.org/licenses/>. >> >> + >> >> +/** @file include/debugging >> >> + * This is a Standard C++ Library header. >> >> + */ >> >> + >> >> +#ifndef _GLIBCXX_DEBUGGING >> >> +#define _GLIBCXX_DEBUGGING 1 >> >> + >> >> +#define __glibcxx_want_debugging >> >> +#include <bits/version.h> >> >> + >> >> +#if __cpp_lib_debugging // C++ >= 26 >> >> +namespace std _GLIBCXX_VISIBILITY(default) >> >> +{ >> >> +// N.B. _GLIBCXX_BEGIN_NAMESPACE_VERSION is not used here. >> >> + >> >> +/** Try to determine if the program is running under control of a >> >> debugger. >> >> + * >> >> + * On GNU/Linux systems this function will only return true if the >> >> program >> >> + * is being traced by another program which is known to be a debugger. >> >> + * This is determined by checking the command name of the tracing program >> >> + * against a list of known debuggers, such as "gdb". >> >> + * >> >> + * On other POSIX-based systems, this function will return true if the >> >> + * program is being traced by any other process, which means it can >> >> return >> >> + * true for non-debugger utilities that use the ptrace system call. >> >> + * >> >> + * @since C++26 >> >> + */ >> >> +bool >> >> +is_debugger_present() noexcept; >> >> + >> >> +/** Stop the program with a breakpoint or debug trap. >> >> + * >> >> + * The details of how a breakpoint is implemented are platform-specific. >> >> + * Some systems provide a special instruction, such as `int3` in x86. >> >> + * When no more appropriate mechanism is available, this will stop the >> >> + * program using `__builtin_trap()`. It might not be possible for the >> >> + * program to continue after such a breakpoint. >> >> + * >> >> + * @since C++26 >> >> + */ >> >> +void >> >> +breakpoint() noexcept; >> >> + >> >> +/** Stop the program if it is running under control of a debugger. >> >> + * >> >> + * @since C++26 >> >> + */ >> >> +void >> >> +breakpoint_if_debugging() noexcept; >> >> + >> >> +} // namespace std >> >> +#endif >> >> +#endif // _GLIBCXX_DEBUGGING >> >> diff --git a/libstdc++-v3/src/c++26/Makefile.am >> >> b/libstdc++-v3/src/c++26/Makefile.am >> >> index 5defa4ac481..4123b7dd369 100644 >> >> --- a/libstdc++-v3/src/c++26/Makefile.am >> >> +++ b/libstdc++-v3/src/c++26/Makefile.am >> >> @@ -35,7 +35,9 @@ else >> >> inst_sources = >> >> endif >> >> >> >> -sources = text_encoding.cc >> >> +sources = \ >> >> + debugging.cc \ >> >> + text_encoding.cc >> >> >> >> vpath % $(top_srcdir)/src/c++26 >> >> >> >> diff --git a/libstdc++-v3/src/c++26/Makefile.in >> >> b/libstdc++-v3/src/c++26/Makefile.in >> >> index 77e73b2b265..1c317d6ac7c 100644 >> >> --- a/libstdc++-v3/src/c++26/Makefile.in >> >> +++ b/libstdc++-v3/src/c++26/Makefile.in >> >> @@ -121,7 +121,7 @@ CONFIG_CLEAN_FILES = >> >> CONFIG_CLEAN_VPATH_FILES = >> >> LTLIBRARIES = $(noinst_LTLIBRARIES) >> >> libc__26convenience_la_LIBADD = >> >> -am__objects_1 = text_encoding.lo >> >> +am__objects_1 = debugging.lo text_encoding.lo >> >> am__objects_2 = >> >> @GLIBCXX_HOSTED_TRUE@am_libc__26convenience_la_OBJECTS = \ >> >> @GLIBCXX_HOSTED_TRUE@ $(am__objects_1) $(am__objects_2) >> >> @@ -430,7 +430,10 @@ headers = >> >> >> >> # XTEMPLATE_FLAGS = -fno-implicit-templates >> >> @ENABLE_EXTERN_TEMPLATE_TRUE@inst_sources = >> >> -sources = text_encoding.cc >> >> +sources = \ >> >> + debugging.cc \ >> >> + text_encoding.cc >> >> + >> >> @GLIBCXX_HOSTED_FALSE@libc__26convenience_la_SOURCES = >> >> @GLIBCXX_HOSTED_TRUE@libc__26convenience_la_SOURCES = $(sources) >> >> $(inst_sources) >> >> >> >> diff --git a/libstdc++-v3/src/c++26/debugging.cc >> >> b/libstdc++-v3/src/c++26/debugging.cc >> >> new file mode 100644 >> >> index 00000000000..5ad85309ba1 >> >> --- /dev/null >> >> +++ b/libstdc++-v3/src/c++26/debugging.cc >> >> @@ -0,0 +1,165 @@ >> >> +// Implementation of <debugging> -*- C++ -*- >> >> + >> >> +// Copyright The GNU Toolchain Authors. >> >> +// >> >> +// This file is part of the GNU ISO C++ Library. This library is free >> >> +// software; you can redistribute it and/or modify it under the >> >> +// terms of the GNU General Public License as published by the >> >> +// Free Software Foundation; either version 3. >> >> + >> >> +// This library is distributed in the hope that it will be useful, >> >> +// but WITHOUT ANY WARRANTY; without even the implied warranty of >> >> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> >> +// GNU General Public License for more details. >> >> + >> >> +// Under Section 7 of GPL version 3, you are granted additional >> >> +// permissions described in the GCC Runtime Library Exception, version >> >> +// 3.1, as published by the Free Software Foundation. >> >> + >> >> +// You should have received a copy of the GNU General Public License and >> >> +// a copy of the GCC Runtime Library Exception along with this program; >> >> +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see >> >> +// <http://www.gnu.org/licenses/>. >> >> + >> >> +#include <debugging> >> >> + >> >> +#if __cpp_lib_debugging >> >> + >> >> +#if _GLIBCXX_USE_PROC_SELF_STATUS >> >> +# include <fstream> >> >> +# include <string> >> >> +#endif >> >> + >> >> +#if _GLIBCXX_HAVE_SYS_PTRACE_H >> >> +# include <sys/ptrace.h> >> >> +# include <errno.h> >> >> +#endif >> >> + >> >> +#if _GLIBCXX_HAVE_DEBUGAPI_H >> >> +# include <debugapi.h> >> >> +#endif >> >> + >> >> +#ifdef _GLIBCXX_HAVE_SYS_SDT_H >> >> +# include <sys/sdt.h> >> >> +/* We only want to use stap probes starting with v3. Earlier versions >> >> + added too much startup cost. */ >> >> +# if defined (STAP_PROBE) && _SDT_NOTE_TYPE >= 3 >> >> +# define PROBE(name) STAP_PROBE(libstdcxx, name) >> >> +# endif >> >> +#endif >> >> + >> >> +#ifndef PROBE >> >> +# define PROBE(name) >> >> +#endif >> >> + >> >> +namespace >> >> +{ >> >> + volatile bool debugger_attached = false; >> >> +} >> >> + >> >> +namespace __gnu_cxx >> >> +{ >> >> + // This should be called by debuggers when they attach and detach. >> >> + void attach_debugger(bool attached) { debugger_attached = attached; } >> >> +} >> >> + >> >> +_GLIBCXX_WEAK_DEFINITION >> >> +bool >> >> +std::is_debugger_present() noexcept >> >> +{ >> >> + if (debugger_attached) >> >> + return true; >> >> + >> >> +#if _GLIBCXX_HOSTED >> >> +# if _GLIBCXX_USE_PROC_SELF_STATUS >> >> + const string_view prefix = "TracerPid:\t"; >> >> + ifstream in("/proc/self/status"); >> >> + string line; >> >> + while (std::getline(in, line)) >> >> + { >> >> + if (!line.starts_with(prefix)) >> >> + continue; >> >> + >> >> + string_view tracer = line; >> >> + tracer.remove_prefix(prefix.size()); >> >> + if (tracer.size() == 1 && tracer[0] == '0') [[likely]] >> >> + return false; // Not being traced. >> >> + >> >> + in.close(); >> >> + string_view cmd; >> >> + string proc_dir = "/proc/" + string(tracer) + '/'; >> >> + in.open(proc_dir + "comm"); // since Linux 2.6.33 >> >> + if (std::getline(in, line)) [[likely]] >> >> + cmd = line; >> >> + else >> >> + { >> >> + in.close(); >> >> + in.open(proc_dir + "cmdline"); >> >> + if (std::getline(in, line)) >> >> + cmd = line.c_str(); // Only up to first '\0' >> >> + else >> >> + return false; >> >> + } >> >> + >> >> + for (auto i : {"gdb", "lldb"}) // known debuggers >> >> + if (cmd.ends_with(i)) >> >> + return true; >> >> + >> >> + // We found the TracerPid line, no need to do any more work. >> >> + return false; >> >> + } >> >> +# endif >> >> +# if _GLIBCXX_HAVE_SYS_PTRACE_H >> > >> > Are _GLIBCXX_USE_PROC_SELF_STATUS and _GLIBCXX_HAVE_SYS_PTRACE_H >> > exclusive, i.e. both cannot be true at same time? >> >> They're not exclusive, e.g. Linux has both /proc/self and ptrace. Most >> UNIX systems only have ptrace. >> >> > If not, using `ptrace` seems to be preferablable, given that it does not >> > involve fstreams. >> >> But it can give false positives. There are other uses of ptrace that >> are not debuggers, e.g. running the program under strace. The >> /proc/self version checks for the tracer name, so should only detect >> real debuggers. > > We will still use the ptrace result, if `proc/self` exists but does not > contain the TracerPid line.
Yes, that was my intention. According to Documentation/filesystems/proc.rst the TracerPid line was added for Linux 2.4, although it wasn't actually set until later (maybe 2.6?): https://lkml.org/lkml/2002/9/6/96 But that means we'll find a TracerPid line even for ancient kernels. If its PID is zero (e.g. because it's in a different pid namespace, or it's kernel 2.4) or the cmdline of the tracer is not readable by the process (e.g. because the debugger is running as a different user), then we'll still find a TracerPid and return early. > I am not sure if this is a possible case, but if not I would prefer the use > of `elif` here. I had intended it to be used as a fallback, but based on what I wrote above, it looks like that fallback will never happen. >> >> >> >> >> >> + if (::ptrace(PTRACE_TRACEME, 0, 1, 0) == -1) >> >> + return errno == EPERM; >> >> +# endif >> >> +# if _GLIBCXX_HAVE_DEBUGAPI_H && defined(_WIN32) && !defined(__CYGWIN__) >> >> + return IsDebuggerPresent(); >> >> +# endif >> >> +#endif // HOSTED >> >> + return false; >> >> +} >> >> + >> >> +void >> >> +std::breakpoint() noexcept >> >> +{ >> >> + PROBE(std::breakpoint); >> >> + >> >> +#if _GLIBCXX_HAVE_DEBUGAPI_H && defined(_WIN32) && !defined(__CYGWIN__) >> >> + DebugBreak(); >> >> +#elif __has_builtin(__builtin_debugtrap) >> >> + __builtin_debugtrap(); // Clang >> >> +#elif defined(__i386__) || defined(__x86_64__) >> >> + __asm__ volatile ("int3; nop"); >> >> +#elifdef __thumb__ >> >> + __asm__ volatile (".inst 0xde01"); >> >> +#elifdef __aarch64__ >> >> + __asm__ volatile (".inst 0xd4200000"); >> >> +#elifdef __arm__ >> >> + __asm__ volatile (".inst 0xe7f001f0"); >> >> +#elifdef __riscv >> >> + /* section 2.8 in the RISC-V unprivileged ISA manual says for >> >> semi-hosted >> >> + * environments we want the sequence: >> >> + * slli x0, x0, 0x1f # Entry NOP >> >> + * ebreak # Break to debugger >> >> + * srai x0, x0, 7 # NOP encoding the semihosting call number 7 >> >> + */ >> >> + __asm__ volatile (".4byte 0x00100073"); >> >> +#elifdef __powerpc__ >> >> + __asm__ volatile(".4byte 0x7d821008"); >> >> +#else >> >> + __builtin_trap(); >> >> +#endif >> >> +} // If the debugger stops here, std::breakpoint() was called. >> >> + >> >> +// This is intentionally not defined inline. A non-inline definition >> >> allows >> >> +// debuggers to insert a breakpoint on calls to the function, avoiding >> >> the >> >> +// overhead of calling `is_debugger_present()`. >> >> +void >> >> +std::breakpoint_if_debugging() noexcept >> >> +{ >> >> + if (std::is_debugger_present()) [[unlikely]] >> >> + std::breakpoint(); >> >> +} >> >> + >> >> +#endif // __cpp_lib_debugging >> >> diff --git >> >> a/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint.cc >> >> b/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint.cc >> >> new file mode 100644 >> >> index 00000000000..ad24177f644 >> >> --- /dev/null >> >> +++ b/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint.cc >> >> @@ -0,0 +1,13 @@ >> >> +// { dg-do run { target c++26 xfail c++26 } } >> >> +// { dg-options "-lstdc++exp" } >> >> +// { dg-require-cpp-feature-test __cpp_lib_debugging } >> >> +#include <debugging> >> >> +#include <type_traits> >> >> + >> >> +static_assert( noexcept(std::breakpoint()) ); >> >> +static_assert( std::is_void_v<decltype(std::breakpoint())> ); >> >> + >> >> +int main() >> >> +{ >> >> + std::breakpoint(); >> >> +} >> >> diff --git >> >> a/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc >> >> >> >> b/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc >> >> new file mode 100644 >> >> index 00000000000..26461836ef7 >> >> --- /dev/null >> >> +++ >> >> b/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc >> >> @@ -0,0 +1,13 @@ >> >> +// { dg-do run { target c++26 } } >> >> +// { dg-options "-lstdc++exp" } >> >> +// { dg-require-cpp-feature-test __cpp_lib_debugging } >> >> +#include <debugging> >> >> +#include <type_traits> >> >> + >> >> +static_assert( noexcept(std::breakpoint_if_debugging()) ); >> >> +static_assert( std::is_void_v<decltype(std::breakpoint_if_debugging())> >> >> ); >> >> + >> >> +int main() >> >> +{ >> >> + std::breakpoint_if_debugging(); >> >> +} >> >> diff --git >> >> a/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present.cc >> >> b/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present.cc >> >> new file mode 100644 >> >> index 00000000000..8dbfa694243 >> >> --- /dev/null >> >> +++ >> >> b/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present.cc >> >> @@ -0,0 +1,14 @@ >> >> +// { dg-do run { target c++26 } } >> >> +// { dg-options "-lstdc++exp" } >> >> +// { dg-require-cpp-feature-test __cpp_lib_debugging } >> >> +#include <debugging> >> >> +#include <type_traits> >> >> +#include <testsuite_hooks.h> >> >> + >> >> +static_assert( noexcept(std::is_debugger_present()) ); >> >> +static_assert( std::is_same_v<decltype(std::is_debugger_present()), >> >> bool> ); >> >> + >> >> +int main() >> >> +{ >> >> + VERIFY( ! std::is_debugger_present() ); >> >> +} >> >> -- >> >> 2.49.0 >> >> >>