From ac11d1f56e25984c79c6b43f5234c1cdada216cb Mon Sep 17 00:00:00 2001 From: Bratislav Filipovic Date: Thu, 9 Jul 2026 14:40:44 +0200 Subject: [PATCH 1/3] Adjust PC for s_trap 2 to fix __builtin_verbose_trap When a wave stops with s_trap 2, rewind the PC by 4 bytes to point at the trap instruction, similar to breakpoint handling. This ensures the PC remains in the inlined DWARF frame containing debug info for __builtin_verbose_trap messages. Fixes: ROCM-22957 Add test for s_trap 2 PC adjustment Test that __builtin_verbose_trap() correctly stops with PC pointing at the trap instruction. Related: ROCM-22957 --- gdb/amd-dbgapi-target.c | 12 ++-- .../gdb.rocm/builtin_verbose_trap.cpp | 44 ++++++++++++ .../gdb.rocm/builtin_verbose_trap.exp | 72 +++++++++++++++++++ 3 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 gdb/testsuite/gdb.rocm/builtin_verbose_trap.cpp create mode 100644 gdb/testsuite/gdb.rocm/builtin_verbose_trap.exp diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c index f3bab7e60cc..6973b531d26 100644 --- a/gdb/amd-dbgapi-target.c +++ b/gdb/amd-dbgapi-target.c @@ -2076,14 +2076,18 @@ process_one_event (amd_dbgapi_inferior_info &info, if (thread == nullptr) thread = add_gpu_thread (info.inf, event_ptid); - /* If the wave is stopped because of a software breakpoint, the - program counter needs to be adjusted so that it points to the - breakpoint instruction. + /* If the wave is stopped because of a software breakpoint or an abort + trap (s_trap 2, used by __builtin_verbose_trap), the program counter + needs to be adjusted so that it points to the trap instruction. + + For abort traps, this ensures the PC remains in the inlined frame + containing DWARF debug info for verbose trap messages. When dealing with a corefile, it is expected that the PC has been adjusted before generating the corefile, so no need to re-do it now. */ - if ((stop_reason & AMD_DBGAPI_WAVE_STOP_REASON_BREAKPOINT) != 0 + if (((stop_reason & AMD_DBGAPI_WAVE_STOP_REASON_BREAKPOINT) != 0 + || (stop_reason & AMD_DBGAPI_WAVE_STOP_REASON_ASSERT_TRAP) != 0) && get_inferior_core_bfd (info.inf) == nullptr) { regcache *regcache = get_thread_regcache (thread); diff --git a/gdb/testsuite/gdb.rocm/builtin_verbose_trap.cpp b/gdb/testsuite/gdb.rocm/builtin_verbose_trap.cpp new file mode 100644 index 00000000000..4e06ac7a096 --- /dev/null +++ b/gdb/testsuite/gdb.rocm/builtin_verbose_trap.cpp @@ -0,0 +1,44 @@ +/* Copyright (C) 2026 Free Software Foundation, Inc. + Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include + +/* Regular inline function - inline frame should be skipped during stepping. */ +__device__ __attribute__((always_inline)) inline int +add_numbers (int a, int b) +{ + return a + b; +} + +__global__ void +test_trap_kernel () +{ + int x = 1; /* Breakpoint here. */ + int y = 2; + int z = add_numbers (x, y); /* Step into inline function. */ + int r = add_numbers (x, y); + __builtin_verbose_trap ("check verbose", "This is verbose trap!"); +} + +int +main () +{ + test_trap_kernel<<<1, 1>>> (); + return hipDeviceSynchronize () != hipSuccess; +} diff --git a/gdb/testsuite/gdb.rocm/builtin_verbose_trap.exp b/gdb/testsuite/gdb.rocm/builtin_verbose_trap.exp new file mode 100644 index 00000000000..1318d3cc0c2 --- /dev/null +++ b/gdb/testsuite/gdb.rocm/builtin_verbose_trap.exp @@ -0,0 +1,72 @@ +# Copyright (C) 2026 Free Software Foundation, Inc. +# Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved. + +# This file is part of GDB. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program 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. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test that __builtin_verbose_trap PC is correctly adjusted. + +load_lib rocm.exp +require allow_hip_tests +standard_testfile .cpp + +if {[build_executable "failed to build" $testfile $srcfile {debug hip}]} { + return +} + +clean_restart $::testfile + +with_rocm_gpu_lock { + if {![runto_main]} { + return + } + + # Set breakpoint in kernel before inline function call. + gdb_breakpoint "test_trap_kernel" -allow-pending + + # Continue to breakpoint. + gdb_test "continue" \ + ".*Breakpoint.*test_trap_kernel.*" \ + "hit breakpoint in kernel" + + # Step through inline function calls with next. + # The inline frames for add_numbers should be hidden. + gdb_test "next" ".*" "next 1" + gdb_test "next" ".*" "next 2" + gdb_test "next" ".*" "next 3" + + # Verify backtrace does NOT show add_numbers inline frame. + gdb_test "bt" \ + ".*test_trap_kernel.*" \ + "inline frame not shown during stepping" + + gdb_test_no_output "set confirm off" + + # Continue to trigger the trap. + gdb_test "continue" \ + ".*received signal SIGABRT.*" \ + "received trap signal" + + # Check PC points to trap instruction. + # If PC adjustment is working, PC should be at the s_trap instruction. + gdb_test "x/i \$pc" \ + ".*s_trap.*" \ + "PC points to trap instruction" + + # Verify verbose trap message appears in backtrace. + gdb_test "bt" \ + ".*This is verbose trap.*" \ + "verbose trap message appears in backtrace" +} From 1b9efda77c2ba4bcf6fcdfbafd563009b40093f0 Mon Sep 17 00:00:00 2001 From: Bratislav Filipovic Date: Wed, 29 Jul 2026 16:35:40 +0200 Subject: [PATCH 2/3] gdb: Add gdbarch hook to show verbose trap inline frames Implement architecture-specific control over inline frame visibility for verbose trap scenarios using the gdbarch pattern. Add new gdbarch method `show_verbose_trap_inline_frame` that allows architectures to prevent skipping of compiler-generated inline frames containing diagnostic information (e.g., __builtin_verbose_trap). Changes: - gdbarch_components.py: Define new Method `show_verbose_trap_inline_frame` - arch-utils.{c,h}: Provide default implementation (returns false) - amdgpu-tdep.c: Implement AMD GPU-specific version that detects __clang_trap_msg$... frames by name pattern - inline-frame.c: Call gdbarch hook in skip_inline_frames() loop - gdbarch-gen.{c,h}: Regenerated from gdbarch_components.py This approach keeps architecture-specific logic (GPU vs CPU) in architecture-specific files, following GDB's design patterns. Ticket: ROCM-22957 / AIROCGDB-558 --- gdb/amd64-linux-tdep.c | 31 +++++++++++++++++++ gdb/amdgpu-tdep.c | 27 ++++++++++++++++ gdb/arch-utils.c | 11 +++++++ gdb/arch-utils.h | 5 +++ gdb/gdbarch-gen.c | 22 +++++++++++++ gdb/gdbarch-gen.h | 18 +++++++++++ gdb/gdbarch_components.py | 23 ++++++++++++++ gdb/inline-frame.c | 7 ++++- .../gdb.rocm/builtin_verbose_trap.cpp | 3 +- .../gdb.rocm/builtin_verbose_trap.exp | 1 - 10 files changed, 144 insertions(+), 4 deletions(-) diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index 2744f85d668..b8cf63e28f6 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -2088,6 +2088,33 @@ amd64_linux_fetch_hiperr_parameters (frame_info_ptr frame) return amd64_fetch_hiperr_parameters (frame, struct_addr); } +/* Return true if the inline frame FUNC should be shown when stopped + due to STOP_SIGNAL. This allows showing verbose trap inline frames + on x86_64. */ + +static bool +amd64_linux_show_verbose_trap_inline_frame (struct gdbarch *gdbarch, + const struct symbol *func, + enum gdb_signal stop_signal) +{ + /* Only show verbose trap frames when stopped due to illegal instruction. + The ud2 instruction used by verbose traps on x86_64 generates SIGILL. + This ensures we only show the frame when the trap actually fired, + not when user stepped into it with commands like "step". */ + if (stop_signal != GDB_SIGNAL_ILL) + return false; + + /* Check if this is a verbose trap inline frame by looking for the + compiler-generated function name pattern. */ + const char *name = func->linkage_name (); + if (name == nullptr) + return false; + + /* Verbose trap frames have names like: + "__clang_trap_msg$$" */ + return startswith (name, "__clang_trap_msg$"); +} + static void amd64_linux_init_abi_common (struct gdbarch_info info, struct gdbarch *gdbarch, int num_disp_step_buffers) @@ -2154,6 +2181,10 @@ amd64_linux_init_abi_common (struct gdbarch_info info, struct gdbarch *gdbarch, /* Extract hiperr parameters for 'catch hiperr'. */ set_gdbarch_fetch_hiperr_parameters (gdbarch, amd64_linux_fetch_hiperr_parameters); + + /* Show verbose trap inline frames when stopped due to abort. */ + set_gdbarch_show_verbose_trap_inline_frame + (gdbarch, amd64_linux_show_verbose_trap_inline_frame); } static void diff --git a/gdb/amdgpu-tdep.c b/gdb/amdgpu-tdep.c index cceee91dad7..0d3ab9b6f87 100644 --- a/gdb/amdgpu-tdep.c +++ b/gdb/amdgpu-tdep.c @@ -2019,6 +2019,30 @@ amdgpu_supports_arch_info (const struct bfd_arch_info *info) return status == AMD_DBGAPI_STATUS_SUCCESS; } +/* Implementation of gdbarch_show_verbose_trap_inline_frame for AMDGPU. */ + +static bool +amdgpu_show_verbose_trap_inline_frame (struct gdbarch *gdbarch, + const struct symbol *func, + enum gdb_signal stop_signal) +{ + /* Only show verbose trap frames when stopped due to abort signal. + This ensures we only show the frame when the trap actually fired, + not when user stepped into it with commands like "step". */ + if (stop_signal != GDB_SIGNAL_ABRT) + return false; + + /* Check if this is a verbose trap inline frame by looking for the + compiler-generated function name pattern. */ + const char *name = func->linkage_name (); + if (name == nullptr) + return false; + + /* Verbose trap frames have names like: + "__clang_trap_msg$$" */ + return startswith (name, "__clang_trap_msg$"); +} + static struct gdbarch * amdgpu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { @@ -2271,6 +2295,9 @@ amdgpu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_decr_pc_after_break (gdbarch, pc_adjust); + set_gdbarch_show_verbose_trap_inline_frame + (gdbarch, amdgpu_show_verbose_trap_inline_frame); + /* Get info about address spaces. */ size_t address_space_count; amd_dbgapi_address_space_id_t *address_spaces; diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index a820128894b..31aeb01cc41 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -1613,6 +1613,17 @@ core_file_exec_context::environment () const return e; } +/* See arch-utils.h. */ + +bool +default_show_verbose_trap_inline_frame (struct gdbarch *gdbarch, + const struct symbol *func, + enum gdb_signal stop_signal) +{ + /* By default, do not show verbose trap inline frames. */ + return false; +} + INIT_GDB_FILE (gdbarch_utils) { add_setshow_enum_cmd ("endian", class_support, diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index cb259a3cd7e..6160912ee1e 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -451,4 +451,9 @@ extern int default_supported_lanes_count (struct gdbarch *gdbarch, extern std::vector default_get_watchable_aliases (struct gdbarch *gdbarch, ptid_t ptid, int simd_lane, addr_range range); +/* Default implementation of gdbarch_show_verbose_trap_inline_frame. */ +extern bool default_show_verbose_trap_inline_frame + (struct gdbarch *gdbarch, const struct symbol *func, + enum gdb_signal stop_signal); + #endif /* GDB_ARCH_UTILS_H */ diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c index e5e80d46b48..8e49b48c0e3 100644 --- a/gdb/gdbarch-gen.c +++ b/gdb/gdbarch-gen.c @@ -265,6 +265,7 @@ struct gdbarch gdbarch_core_parse_exec_context_ftype *core_parse_exec_context = default_core_parse_exec_context; gdbarch_shadow_stack_push_ftype *shadow_stack_push = nullptr; gdbarch_get_shadow_stack_pointer_ftype *get_shadow_stack_pointer = default_get_shadow_stack_pointer; + gdbarch_show_verbose_trap_inline_frame_ftype *show_verbose_trap_inline_frame = default_show_verbose_trap_inline_frame; }; /* Create a new ``struct gdbarch'' based on information provided by @@ -547,6 +548,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of core_parse_exec_context, invalid_p == 0. */ /* Skip verify of shadow_stack_push, has predicate. */ /* Skip verify of get_shadow_stack_pointer, invalid_p == 0. */ + /* Skip verify of show_verbose_trap_inline_frame, invalid_p == 0. */ if (!log.empty ()) internal_error (_("verify_gdbarch: the following are invalid ...%s"), log.c_str ()); @@ -1421,6 +1423,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) gdb_printf (file, "gdbarch_dump: get_shadow_stack_pointer = <%s>\n", host_address_to_string (gdbarch->get_shadow_stack_pointer)); + gdb_printf (file, + "gdbarch_dump: show_verbose_trap_inline_frame = <%s>\n", + host_address_to_string (gdbarch->show_verbose_trap_inline_frame)); if (gdbarch->dump_tdep != nullptr) gdbarch->dump_tdep (gdbarch, file); } @@ -5600,3 +5605,20 @@ set_gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch, { gdbarch->get_shadow_stack_pointer = get_shadow_stack_pointer; } + +bool +gdbarch_show_verbose_trap_inline_frame (struct gdbarch *gdbarch, const struct symbol *func, enum gdb_signal stop_signal) +{ + gdb_assert (gdbarch != nullptr); + gdb_assert (gdbarch->show_verbose_trap_inline_frame != nullptr); + if (gdbarch_debug >= 2) + gdb_printf (gdb_stdlog, "gdbarch_show_verbose_trap_inline_frame called\n"); + return gdbarch->show_verbose_trap_inline_frame (gdbarch, func, stop_signal); +} + +void +set_gdbarch_show_verbose_trap_inline_frame (struct gdbarch *gdbarch, + gdbarch_show_verbose_trap_inline_frame_ftype show_verbose_trap_inline_frame) +{ + gdbarch->show_verbose_trap_inline_frame = show_verbose_trap_inline_frame; +} diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h index dc4a58fad37..d79ae5275e7 100644 --- a/gdb/gdbarch-gen.h +++ b/gdb/gdbarch-gen.h @@ -1852,3 +1852,21 @@ void set_gdbarch_shadow_stack_push (struct gdbarch *gdbarch, gdbarch_shadow_stac using gdbarch_get_shadow_stack_pointer_ftype = std::optional (struct gdbarch *gdbarch, regcache *regcache, bool &shadow_stack_enabled); std::optional gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch, regcache *regcache, bool &shadow_stack_enabled); void set_gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch, gdbarch_get_shadow_stack_pointer_ftype *get_shadow_stack_pointer); + +/* Return true if the inline frame represented by FUNC should NOT be skipped + when stopped due to STOP_SIGNAL. This allows architectures to show + compiler-generated inline frames that contain verbose trap messages + (e.g., __builtin_verbose_trap). + + By default, inline frames are skipped to provide better stepping experience. + However, for verbose trap scenarios, the inline frame contains important + diagnostic information that should be visible in backtraces. + + Architectures can use this hook to detect verbose trap frames by checking + both the symbol name (e.g., starts with "__clang_trap_msg$") and the stop + signal (e.g., GDB_SIGNAL_ABRT for abort traps), returning true only when + both conditions indicate a verbose trap scenario. */ + +using gdbarch_show_verbose_trap_inline_frame_ftype = bool (struct gdbarch *gdbarch, const struct symbol *func, enum gdb_signal stop_signal); +bool gdbarch_show_verbose_trap_inline_frame (struct gdbarch *gdbarch, const struct symbol *func, enum gdb_signal stop_signal); +void set_gdbarch_show_verbose_trap_inline_frame (struct gdbarch *gdbarch, gdbarch_show_verbose_trap_inline_frame_ftype *show_verbose_trap_inline_frame); diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py index ebd70868427..6780e8ccf96 100644 --- a/gdb/gdbarch_components.py +++ b/gdb/gdbarch_components.py @@ -2944,3 +2944,26 @@ predefault="default_get_shadow_stack_pointer", invalid=False, ) + +Method( + comment=""" +Return true if the inline frame represented by FUNC should NOT be skipped +when stopped due to STOP_SIGNAL. This allows architectures to show +compiler-generated inline frames that contain verbose trap messages +(e.g., __builtin_verbose_trap). + +By default, inline frames are skipped to provide better stepping experience. +However, for verbose trap scenarios, the inline frame contains important +diagnostic information that should be visible in backtraces. + +Architectures can use this hook to detect verbose trap frames by checking +both the symbol name (e.g., starts with "__clang_trap_msg$") and the stop +signal (e.g., GDB_SIGNAL_ABRT for abort traps), returning true only when +both conditions indicate a verbose trap scenario. +""", + type="bool", + name="show_verbose_trap_inline_frame", + params=[("const struct symbol *", "func"), ("enum gdb_signal", "stop_signal")], + predefault="default_show_verbose_trap_inline_frame", + invalid=False, +) diff --git a/gdb/inline-frame.c b/gdb/inline-frame.c index a1ccd4ed0da..ff4c7138164 100644 --- a/gdb/inline-frame.c +++ b/gdb/inline-frame.c @@ -28,6 +28,7 @@ #include "regcache.h" #include "symtab.h" #include "frame.h" +#include "gdbarch.h" #include "cli/cli-cmds.h" #include "cli/cli-style.h" #include @@ -428,10 +429,14 @@ skip_inline_frames (thread_info *thread, bpstat *stop_chain) which contains all of the inlined functions, we never skip this. */ int skipped_frames = 0; + struct gdbarch *gdbarch = get_frame_arch (get_current_frame ()); + enum gdb_signal stop_signal = thread->stop_signal (); + for (const auto sym : function_symbols) { if (stopped_by_user_bp_inline_frame (sym, stop_chain) - || sym == function_symbols.back ()) + || sym == function_symbols.back () + || gdbarch_show_verbose_trap_inline_frame (gdbarch, sym, stop_signal)) break; ++skipped_frames; diff --git a/gdb/testsuite/gdb.rocm/builtin_verbose_trap.cpp b/gdb/testsuite/gdb.rocm/builtin_verbose_trap.cpp index 4e06ac7a096..9e56ee84bb2 100644 --- a/gdb/testsuite/gdb.rocm/builtin_verbose_trap.cpp +++ b/gdb/testsuite/gdb.rocm/builtin_verbose_trap.cpp @@ -31,8 +31,7 @@ test_trap_kernel () { int x = 1; /* Breakpoint here. */ int y = 2; - int z = add_numbers (x, y); /* Step into inline function. */ - int r = add_numbers (x, y); + int z = add_numbers (x, y); /* Step over inline function. */ __builtin_verbose_trap ("check verbose", "This is verbose trap!"); } diff --git a/gdb/testsuite/gdb.rocm/builtin_verbose_trap.exp b/gdb/testsuite/gdb.rocm/builtin_verbose_trap.exp index 1318d3cc0c2..4365e4fd801 100644 --- a/gdb/testsuite/gdb.rocm/builtin_verbose_trap.exp +++ b/gdb/testsuite/gdb.rocm/builtin_verbose_trap.exp @@ -45,7 +45,6 @@ with_rocm_gpu_lock { # The inline frames for add_numbers should be hidden. gdb_test "next" ".*" "next 1" gdb_test "next" ".*" "next 2" - gdb_test "next" ".*" "next 3" # Verify backtrace does NOT show add_numbers inline frame. gdb_test "bt" \ From 3764561c2ddca0cbf30e7c2d17beca0897000540 Mon Sep 17 00:00:00 2001 From: Bratislav Filipovic Date: Tue, 4 Aug 2026 14:21:55 +0200 Subject: [PATCH 3/3] testsuite: Add CPU test for __builtin_verbose_trap __builtin_verbose_trap is a Clang builtin that allows embedding custom trap messages in the binary for better crash diagnostics. Add test for CPU (x86_64) __builtin_verbose_trap inline frame display. This complements the GPU test in gdb.rocm/builtin_verbose_trap.exp. The test verifies that: - Normal inline frames (add_numbers) are hidden during stepping - Verbose trap inline frame IS shown when trap fires with SIGILL - CPU uses ud2 instruction which generates SIGILL (unlike GPU s_trap which generates SIGABRT) Both GPU and CPU share the same DWARF pattern for verbose trap: __clang_trap_msg$$ --- .../gdb.base/builtin_verbose_trap.cpp | 38 ++++++++++++ .../gdb.base/builtin_verbose_trap.exp | 60 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 gdb/testsuite/gdb.base/builtin_verbose_trap.cpp create mode 100644 gdb/testsuite/gdb.base/builtin_verbose_trap.exp diff --git a/gdb/testsuite/gdb.base/builtin_verbose_trap.cpp b/gdb/testsuite/gdb.base/builtin_verbose_trap.cpp new file mode 100644 index 00000000000..77f8d61ea6b --- /dev/null +++ b/gdb/testsuite/gdb.base/builtin_verbose_trap.cpp @@ -0,0 +1,38 @@ +/* Copyright (C) 2026 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* Regular inline function - inline frame should be skipped during stepping. */ +__attribute__((always_inline)) inline int +add_numbers (int a, int b) +{ + return a + b; +} + +void +test_trap_function () +{ + int x = 1; /* Breakpoint here. */ + int y = 2; + int z = add_numbers (x, y); /* Step over inline function. */ + __builtin_verbose_trap ("check verbose", "This is verbose trap!"); +} + +int +main () +{ + test_trap_function (); + return 0; +} diff --git a/gdb/testsuite/gdb.base/builtin_verbose_trap.exp b/gdb/testsuite/gdb.base/builtin_verbose_trap.exp new file mode 100644 index 00000000000..bb8b5df6710 --- /dev/null +++ b/gdb/testsuite/gdb.base/builtin_verbose_trap.exp @@ -0,0 +1,60 @@ +# Copyright (C) 2026 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test that __builtin_verbose_trap inline frames are shown when trap fires. +# __builtin_verbose_trap is a Clang-only builtin, added in Clang 17. + +require {expr {[test_compiler_info clang*] && ![test_compiler_info {clang-1[0-6]-*}]}} + +standard_testfile .cpp + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug c++}]} { + return +} + +if {![runto_main]} { + return +} + +# Set breakpoint in function before inline function call. +gdb_breakpoint "test_trap_function" + +# Continue to breakpoint. +gdb_test "continue" \ + ".*Breakpoint.*test_trap_function.*" \ + "hit breakpoint in function" + +# Step through inline function calls with next. +# The inline frames for add_numbers should be hidden. +gdb_test "next" ".*" "next 1" +gdb_test "next" ".*" "next 2" + +# Verify backtrace does NOT show add_numbers inline frame. +gdb_test "bt" \ + ".*test_trap_function.*" \ + "inline frame not shown during stepping" + +gdb_test_no_output "set confirm off" + +# Continue to trigger the trap. +# CPU uses ud2 instruction which generates SIGILL (not SIGABRT like GPU). +gdb_test "continue" \ + ".*received signal SIGILL.*" \ + "received trap signal" + +# Verify verbose trap message appears in backtrace. +gdb_test "bt" \ + ".*This is verbose trap.*" \ + "verbose trap message appears in backtrace"