From 45d0164764d6aa4c44fecbdd723271b71fe295df Mon Sep 17 00:00:00 2001 From: Bratislav Filipovic Date: Thu, 30 Jul 2026 17:44:34 +0200 Subject: [PATCH 1/3] gdb: Implement stop-on-solib-events for GPU code objects GDB's "set stop-on-solib-events 1" setting was not working for GPU code objects loaded by the AMD ROCm runtime. While CPU shared library events correctly triggered stops when this setting was enabled, GPU code object load events were silently ignored. The root cause was in amd_dbgapi_target_breakpoint::check_status(), which unconditionally set bs->stop = 0 and bs->print_it = print_it_noop, regardless of the stop_on_solib_events setting. This is in contrast to internal_breakpoint::check_status() for CPU shared libraries, which respects the setting by checking the stop_on_solib_events global variable. The fix adds: 1. A code_object_list_updated flag to amd_dbgapi_inferior_info to track when AMD_DBGAPI_EVENT_KIND_CODE_OBJECT_LIST_UPDATED events are seen during process_event_queue(). 2. Logic in check_status() to check this flag after processing events, and update bs->stop, bs->print, and bs->print_it based on stop_on_solib_events. 3. A print_it() override to display "Stopped due to GPU code object event" to distinguish GPU events from CPU shared library events. This makes GPU code object load events behave consistently with CPU shared library events, allowing users to stop execution when GPU code objects are loaded for inspection and breakpoint placement. A test is included in gdb.rocm/solib-event.exp. --- gdb/amd-dbgapi-target.c | 81 ++++++++++++ gdb/testsuite/gdb.rocm/solib-event-kernel.cpp | 28 +++++ gdb/testsuite/gdb.rocm/solib-event.cpp | 92 ++++++++++++++ gdb/testsuite/gdb.rocm/solib-event.exp | 119 ++++++++++++++++++ 4 files changed, 320 insertions(+) create mode 100644 gdb/testsuite/gdb.rocm/solib-event-kernel.cpp create mode 100644 gdb/testsuite/gdb.rocm/solib-event.cpp create mode 100644 gdb/testsuite/gdb.rocm/solib-event.exp diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c index f3bab7e60cc..6b69502b564 100644 --- a/gdb/amd-dbgapi-target.c +++ b/gdb/amd-dbgapi-target.c @@ -38,6 +38,7 @@ #include "gdbthread.h" #include "inf-loop.h" #include "inferior.h" +#include "infrun.h" #include "location.h" #include "objfiles.h" #include "observable.h" @@ -45,6 +46,7 @@ #include "solib.h" #include "target.h" #include "tid-parse.h" +#include "ui-out.h" #include "bfd/elf-bfd.h" #include "elf/amdgpu.h" #include "cp-support.h" @@ -284,6 +286,11 @@ struct amd_dbgapi_inferior_info /* List of pending events the amd-dbgapi target retrieved from the dbgapi. */ std::list> wave_events; + /* Flag to track if a CODE_OBJECT_LIST_UPDATED event was seen during + process_event_queue. Used to implement stop-on-solib-events for GPU + code objects. */ + bool code_object_list_updated = false; + /* Map of threads with ongoing displaced steps to corresponding amd-dbgapi displaced stepping handles. */ gdb::unordered_mapstop = true; + bs->print = true; + /* Allow print_it () to print the GPU code object event message. */ + bs->print_it = print_it_normal; + } +} + +enum print_stop_action +amd_dbgapi_target_breakpoint::print_it (const bpstat *bs) const +{ + /* We only reach here when check_status set bs->print_it to print_it_normal, + which happens only for GPU code object events when stop_on_solib_events + is enabled. */ + bool any_deleted = !current_program_space->deleted_solibs.empty (); + bool any_added = !current_program_space->added_solibs.empty (); + + if (current_uiout->is_mi_like_p ()) + { + current_uiout->field_string + ("reason", async_reason_lookup (EXEC_ASYNC_SOLIB_EVENT)); + current_uiout->field_string ("object-kind", "gpu-code-object"); + } + + if (any_added || any_deleted) + current_uiout->text (_("Stopped due to GPU code object event:\n")); + else + current_uiout->text (_("Stopped due to GPU code object event (no " + "code objects added or removed)\n")); + + if (any_deleted) + { + current_uiout->text (_(" Inferior unloaded ")); + ui_out_emit_list list_emitter (current_uiout, "removed"); + bool first = true; + for (const std::string &name : current_program_space->deleted_solibs) + { + if (!first) + current_uiout->text (" "); + first = false; + current_uiout->field_string ("code-object", name); + current_uiout->text ("\n"); + } + } + + if (any_added) + { + current_uiout->text (_(" Inferior loaded ")); + ui_out_emit_list list_emitter (current_uiout, "added"); + bool first = true; + for (solib *iter : current_program_space->added_solibs) + { + if (!first) + current_uiout->text (" "); + first = false; + current_uiout->field_string ("code-object", iter->name); + current_uiout->text ("\n"); + } + } + + return PRINT_NOTHING; } bool @@ -2120,6 +2200,7 @@ process_one_event (amd_dbgapi_inferior_info &info, inferior is the inferior that hit the breakpoint, which should still be the case now. */ gdb_assert (info.inf == current_inferior ()); + info.code_object_list_updated = true; handle_solib_event (); break; diff --git a/gdb/testsuite/gdb.rocm/solib-event-kernel.cpp b/gdb/testsuite/gdb.rocm/solib-event-kernel.cpp new file mode 100644 index 00000000000..2f9b4cf04b5 --- /dev/null +++ b/gdb/testsuite/gdb.rocm/solib-event-kernel.cpp @@ -0,0 +1,28 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 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 . */ + +/* Device kernel for solib-event test. + Compiled with --cuda-device-only to produce .co file. */ + +#include "rocm-test-utils.h" +#include + +extern "C" __global__ void +test_kernel () +{ + NOP (1); +} diff --git a/gdb/testsuite/gdb.rocm/solib-event.cpp b/gdb/testsuite/gdb.rocm/solib-event.cpp new file mode 100644 index 00000000000..8a0922d3c01 --- /dev/null +++ b/gdb/testsuite/gdb.rocm/solib-event.cpp @@ -0,0 +1,92 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 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 . */ + +#include "rocm-test-utils.h" +#include +#include +#include + +/* Test file:// events (hipModuleLoad). */ +static void +test_file_load (const char *module_path) +{ + hipModule_t module; + CHECK (hipModuleLoad (&module, module_path)); + + hipFunction_t function; + CHECK (hipModuleGetFunction (&function, module, "test_kernel")); + + CHECK (hipModuleLaunchKernel (function, 1, 1, 1, 1, 1, 1, + 0, nullptr, nullptr, nullptr)); + + CHECK (hipDeviceSynchronize ()); + CHECK (hipModuleUnload (module)); +} + +/* Test memory:// events (hipModuleLoadData). */ +static void +test_memory_load (const char *module_path) +{ + /* Read module file into memory buffer. */ + std::ifstream mod (module_path, std::ios::binary | std::ios::ate); + if (!mod.is_open ()) + { + fprintf (stderr, "Failed to open module file\n"); + exit (EXIT_FAILURE); + } + + size_t module_size = mod.tellg (); + mod.seekg (0, std::ios::beg); + std::vector module_buffer (module_size); + + if (!mod.read (module_buffer.data (), module_size)) + { + fprintf (stderr, "Failed to read module into memory\n"); + exit (EXIT_FAILURE); + } + mod.close (); + + /* Load from memory buffer. */ + hipModule_t module; + CHECK (hipModuleLoadData (&module, module_buffer.data ())); + + hipFunction_t function; + CHECK (hipModuleGetFunction (&function, module, "test_kernel")); + + CHECK (hipModuleLaunchKernel (function, 1, 1, 1, 1, 1, 1, + 0, nullptr, nullptr, nullptr)); + + CHECK (hipDeviceSynchronize ()); + CHECK (hipModuleUnload (module)); +} + +int +main (int argc, char **argv) +{ + if (argc != 2) + { + fprintf (stderr, "Usage: %s \n", argv[0]); + return EXIT_FAILURE; + } + + const char *module_path = argv[1]; + + test_file_load (module_path); + test_memory_load (module_path); + + return 0; +} diff --git a/gdb/testsuite/gdb.rocm/solib-event.exp b/gdb/testsuite/gdb.rocm/solib-event.exp new file mode 100644 index 00000000000..5618ac3292b --- /dev/null +++ b/gdb/testsuite/gdb.rocm/solib-event.exp @@ -0,0 +1,119 @@ +# Copyright 2026 Free Software Foundation, Inc. +# Copyright 2026 Advanced Micro Devices, 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 "set stop-on-solib-events 1" works for GPU code objects. +# Tests both file:// events (hipModuleLoad) and memory:// events +# (hipModuleLoadData), as well as unload events (hipModuleUnload). + +load_lib rocm.exp + +require allow_hip_tests + +standard_testfile .cpp + +# Build device module (.co file). +set kernel_srcfile ${testfile}-kernel.cpp +set hipmodule_path [standard_output_file ${testfile}.co] + +if {[gdb_compile $srcdir/$subdir/$kernel_srcfile \ + $hipmodule_path object \ + {debug hip additional_flags=--cuda-device-only}] != ""} { + return +} + +# Build host executable. +if {[build_executable "failed to prepare" $testfile $srcfile {debug hip}] == -1} { + return +} + +# Helper proc to skip CPU solib events and find GPU events. +# Arguments: +# event_type: "load" or "unload" +# uri_pattern: regex pattern to match (e.g., "file://" or "memory://") +# test_name: descriptive name for the test +proc find_gpu_event {event_type uri_pattern test_name} { + set seen_gpu_event 0 + set max_continues 20 + + # The limit of 20 iterations should be sufficient to cover all CPU + # shared library events that may occur during hipModule* operations. + # HIP runtime may also load internal memory:// code objects during + # hipModuleLoad, so we skip GPU events that don't match our criteria. + for {set i 0} {$i < $max_continues} {incr i} { + gdb_test_multiple "continue" "continue looking for $test_name" { + -re -wrap "Stopped due to GPU code object event.*Inferior (loaded|unloaded) ${uri_pattern}\[^\r\n\]+" { + if {[string equal $event_type "load"] && [string equal $expect_out(1,string) "loaded"]} { + set seen_gpu_event 1 + break + } elseif {[string equal $event_type "unload"] && [string equal $expect_out(1,string) "unloaded"]} { + set seen_gpu_event 1 + break + } + # GPU event doesn't match our criteria (wrong operation type), continue. + } + -re -wrap "Stopped due to GPU code object event.*" { + # GPU event with different URI type (e.g., memory:// when looking for file://), continue. + } + -re -wrap "Stopped due to shared library event.*" { + # CPU solib event, continue looping. + } + -re -wrap "Inferior.*exited" { + break + } + -re -wrap ".*" { + fail "unexpected stop before $test_name" + break + } + } + + if {$seen_gpu_event} { + break + } + } + + gdb_assert {$seen_gpu_event} $test_name +} + +proc do_test {} { + with_rocm_gpu_lock { + clean_restart + gdb_load $::binfile + + if {![runto_main -inferior-args $::hipmodule_path]} { + return + } + + gdb_test_no_output "set stop-on-solib-events 1" + + # Test 1: file:// load event (hipModuleLoad). + gdb_breakpoint "test_file_load" -temporary + gdb_continue_to_breakpoint "at test_file_load" + find_gpu_event "load" "file://" "saw GPU code object load event with file:// prefix" + + # Test 2: file:// unload event (hipModuleUnload). + find_gpu_event "unload" "file://" "saw GPU code object unload event with file:// prefix" + + # Test 3: memory:// load event (hipModuleLoadData). + gdb_breakpoint "test_memory_load" -temporary + gdb_continue_to_breakpoint "at test_memory_load" + find_gpu_event "load" "memory://" "saw GPU code object load event with memory:// prefix" + + # Test 4: memory:// unload event (hipModuleUnload). + find_gpu_event "unload" "memory://" "saw GPU code object unload event with memory:// prefix" + } +} + +do_test From d23d1198db69ff11cdd51853f04f171d9b6b0cc9 Mon Sep 17 00:00:00 2001 From: Bratislav Filipovic Date: Mon, 17 Aug 2026 12:09:33 +0200 Subject: [PATCH 2/3] gdb: Add GPU/CPU control to stop-on-solib-events setting Modified stop-on-solib-events to accept integer values that control stopping on CPU shared libraries vs GPU code objects independently: 0 = Do not stop on shared library events 1 = Stop on CPU shared library events only 2 = Stop on GPU code object events only 3 = Stop on both CPU and GPU library events This follows GDB's precedent for integer-encoded mode settings (like annotation_level) and preserves backward compatibility - users who previously set stop-on-solib-events to 1 continue to get CPU-only behavior. The show command now displays a human-readable explanation of the current value alongside the numeric setting. Renamed solib-event test to gpu-solib-event to better reflect that it specifically tests GPU code object events. Updated the test to use value 2 (GPU events only), which eliminates the need to skip CPU shared library events during test execution. CPU solib event testing is already covered by existing GDB testsuite tests. Ticket: AIROCGDB-589 --- gdb/amd-dbgapi-target.c | 10 +++--- gdb/breakpoint.c | 6 ++-- gdb/infrun.c | 36 +++++++++++++++---- gdb/solib-svr4.c | 8 +++-- gdb/solib.h | 7 ++++ ...-kernel.cpp => gpu-solib-event-kernel.cpp} | 0 .../{solib-event.cpp => gpu-solib-event.cpp} | 0 .../{solib-event.exp => gpu-solib-event.exp} | 22 ++++++------ 8 files changed, 64 insertions(+), 25 deletions(-) rename gdb/testsuite/gdb.rocm/{solib-event-kernel.cpp => gpu-solib-event-kernel.cpp} (100%) rename gdb/testsuite/gdb.rocm/{solib-event.cpp => gpu-solib-event.cpp} (100%) rename gdb/testsuite/gdb.rocm/{solib-event.exp => gpu-solib-event.exp} (83%) diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c index 6b69502b564..c04990fd790 100644 --- a/gdb/amd-dbgapi-target.c +++ b/gdb/amd-dbgapi-target.c @@ -926,9 +926,11 @@ amd_dbgapi_target_breakpoint::check_status (struct bpstat *bs) amd_dbgapi_event_processed (resume_event_id); /* If a CODE_OBJECT_LIST_UPDATED event was seen during event processing, - check if the user requested to stop on solib events. This implements - stop-on-solib-events for GPU code objects. */ - if (info.code_object_list_updated && stop_on_solib_events != 0) + check if the user requested to stop on GPU code object events. This + implements stop-on-solib-events for GPU code objects. */ + if (info.code_object_list_updated + && (stop_on_solib_events == STOP_SOLIB_GPU + || stop_on_solib_events == STOP_SOLIB_ALL)) { bs->stop = true; bs->print = true; @@ -942,7 +944,7 @@ amd_dbgapi_target_breakpoint::print_it (const bpstat *bs) const { /* We only reach here when check_status set bs->print_it to print_it_normal, which happens only for GPU code object events when stop_on_solib_events - is enabled. */ + is set to STOP_SOLIB_GPU or STOP_SOLIB_ALL. */ bool any_deleted = !current_program_space->deleted_solibs.empty (); bool any_added = !current_program_space->added_solibs.empty (); diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index f88680bf4f0..e42331b7f6b 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -12392,8 +12392,10 @@ internal_breakpoint::check_status (bpstat *bs) events. This allows the user to get control and place breakpoints in initializer routines for dynamically loaded objects (among other things). */ - bs->stop = stop_on_solib_events != 0; - bs->print = stop_on_solib_events != 0; + bs->stop = (stop_on_solib_events == STOP_SOLIB_CPU + || stop_on_solib_events == STOP_SOLIB_ALL); + bs->print = (stop_on_solib_events == STOP_SOLIB_CPU + || stop_on_solib_events == STOP_SOLIB_ALL); } else bs->stop = false; diff --git a/gdb/infrun.c b/gdb/infrun.c index 58c66d6191e..3ce711e0882 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -448,8 +448,28 @@ static void show_stop_on_solib_events (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - gdb_printf (file, _("Stopping for shared library events is %s.\n"), - value); + int val = atoi (value); + + gdb_printf (file, _("Stopping for shared library events is %s"), value); + + switch (val) + { + case STOP_SOLIB_NONE: + gdb_printf (file, _(" (disabled).\n")); + break; + case STOP_SOLIB_CPU: + gdb_printf (file, _(" (CPU libraries only).\n")); + break; + case STOP_SOLIB_GPU: + gdb_printf (file, _(" (GPU code objects only).\n")); + break; + case STOP_SOLIB_ALL: + gdb_printf (file, _(" (CPU and GPU).\n")); + break; + default: + gdb_printf (file, _(".\n")); + break; + } } /* True after stop if current stack frame should be printed. */ @@ -6462,7 +6482,8 @@ handle_inferior_event (struct execution_control_state *ecs) and place breakpoints in initializer routines for dynamically loaded objects (among other things). */ ecs->event_thread->set_stop_signal (GDB_SIGNAL_0); - if (stop_on_solib_events) + if (stop_on_solib_events == STOP_SOLIB_CPU + || stop_on_solib_events == STOP_SOLIB_ALL) { /* Make sure we print "Stopped due to solib-event" in normal_stop. */ @@ -11036,9 +11057,12 @@ leave it stopped or free to run as needed."), &stop_on_solib_events, _("\ Set stopping for shared library events."), _("\ Show stopping for shared library events."), _("\ -If nonzero, gdb will give control to the user when the dynamic linker\n\ -notifies gdb of shared library events. The most common event of interest\n\ -to the user would be loading/unloading of a new library."), +Values:\n\ + 0 == Do not stop on shared library events.\n\ + 1 == Stop on CPU shared library events only.\n\ + 2 == Stop on GPU code object events only.\n\ + 3 == Stop on both CPU and GPU library events.\n\ +The most common events of interest are loading/unloading of libraries."), set_stop_on_solib_events, show_stop_on_solib_events, &setlist, &showlist); diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index f2966a424a4..3e272369c48 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -2305,9 +2305,13 @@ svr4_update_solib_event_breakpoint (struct breakpoint *b) if (pa->action == DO_NOTHING) { - if (b->enable_state == bp_disabled && stop_on_solib_events) + if (b->enable_state == bp_disabled + && (stop_on_solib_events == STOP_SOLIB_CPU + || stop_on_solib_events == STOP_SOLIB_ALL)) enable_breakpoint (b); - else if (b->enable_state == bp_enabled && !stop_on_solib_events) + else if (b->enable_state == bp_enabled + && stop_on_solib_events != STOP_SOLIB_CPU + && stop_on_solib_events != STOP_SOLIB_ALL) disable_breakpoint (b); } diff --git a/gdb/solib.h b/gdb/solib.h index 662d467b0cc..0ece66d0d6b 100644 --- a/gdb/solib.h +++ b/gdb/solib.h @@ -33,6 +33,13 @@ struct program_space; extern bool debug_solib; +/* Values for 'set stop-on-solib-events' setting. */ + +#define STOP_SOLIB_NONE 0 +#define STOP_SOLIB_CPU 1 +#define STOP_SOLIB_GPU 2 +#define STOP_SOLIB_ALL 3 + /* Print an "solib" debug statement. */ #define solib_debug_printf(fmt, ...) \ diff --git a/gdb/testsuite/gdb.rocm/solib-event-kernel.cpp b/gdb/testsuite/gdb.rocm/gpu-solib-event-kernel.cpp similarity index 100% rename from gdb/testsuite/gdb.rocm/solib-event-kernel.cpp rename to gdb/testsuite/gdb.rocm/gpu-solib-event-kernel.cpp diff --git a/gdb/testsuite/gdb.rocm/solib-event.cpp b/gdb/testsuite/gdb.rocm/gpu-solib-event.cpp similarity index 100% rename from gdb/testsuite/gdb.rocm/solib-event.cpp rename to gdb/testsuite/gdb.rocm/gpu-solib-event.cpp diff --git a/gdb/testsuite/gdb.rocm/solib-event.exp b/gdb/testsuite/gdb.rocm/gpu-solib-event.exp similarity index 83% rename from gdb/testsuite/gdb.rocm/solib-event.exp rename to gdb/testsuite/gdb.rocm/gpu-solib-event.exp index 5618ac3292b..6ccd033a42b 100644 --- a/gdb/testsuite/gdb.rocm/solib-event.exp +++ b/gdb/testsuite/gdb.rocm/gpu-solib-event.exp @@ -14,9 +14,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Test that "set stop-on-solib-events 1" works for GPU code objects. +# Test that "set stop-on-solib-events" works for GPU code objects. # Tests both file:// events (hipModuleLoad) and memory:// events # (hipModuleLoadData), as well as unload events (hipModuleUnload). +# +# Uses stop-on-solib-events value 2 (GPU events only) to avoid +# stopping on CPU shared library events. load_lib rocm.exp @@ -39,7 +42,9 @@ if {[build_executable "failed to prepare" $testfile $srcfile {debug hip}] == -1} return } -# Helper proc to skip CPU solib events and find GPU events. +# Helper proc to continue until we see the expected GPU event. +# HIP runtime may load internal memory:// code objects, so we need to +# skip GPU events that don't match our specific criteria. # Arguments: # event_type: "load" or "unload" # uri_pattern: regex pattern to match (e.g., "file://" or "memory://") @@ -48,10 +53,6 @@ proc find_gpu_event {event_type uri_pattern test_name} { set seen_gpu_event 0 set max_continues 20 - # The limit of 20 iterations should be sufficient to cover all CPU - # shared library events that may occur during hipModule* operations. - # HIP runtime may also load internal memory:// code objects during - # hipModuleLoad, so we skip GPU events that don't match our criteria. for {set i 0} {$i < $max_continues} {incr i} { gdb_test_multiple "continue" "continue looking for $test_name" { -re -wrap "Stopped due to GPU code object event.*Inferior (loaded|unloaded) ${uri_pattern}\[^\r\n\]+" { @@ -65,10 +66,7 @@ proc find_gpu_event {event_type uri_pattern test_name} { # GPU event doesn't match our criteria (wrong operation type), continue. } -re -wrap "Stopped due to GPU code object event.*" { - # GPU event with different URI type (e.g., memory:// when looking for file://), continue. - } - -re -wrap "Stopped due to shared library event.*" { - # CPU solib event, continue looping. + # GPU event with different URI type, continue. } -re -wrap "Inferior.*exited" { break @@ -96,7 +94,9 @@ proc do_test {} { return } - gdb_test_no_output "set stop-on-solib-events 1" + # Use value 2 to stop on GPU code object events only. + # This avoids CPU shared library events during test execution. + gdb_test_no_output "set stop-on-solib-events 2" # Test 1: file:// load event (hipModuleLoad). gdb_breakpoint "test_file_load" -temporary From 21baa3a9a542070c266fe85b2567121093736b6d Mon Sep 17 00:00:00 2001 From: Bratislav Filipovic Date: Mon, 17 Aug 2026 15:21:44 +0200 Subject: [PATCH 3/3] gdb: Add string literals to stop-on-solib-events setting Enhanced stop-on-solib-events to accept both numeric values (0-3) and string keywords ("none", "cpu", "gpu", "all") for improved usability. Implementation uses GDB's extra_literals mechanism, which provides: - Automatic tab completion for string keywords - Display translation (shows "cpu" instead of "1") - Backward compatibility with numeric input Users can now set the value using either format: set stop-on-solib-events 2 # Numeric (existing) set stop-on-solib-events gpu # String keyword (new) Both formats are equivalent and produce the same internal value. The show command displays the literal string when available, making the current setting more readable. This follows GDB's precedent used by settings like "unlimited" which accept both numeric and string input. Ticket: AIROCGDB-589 --- gdb/infrun.c | 60 ++++++++++++++++------ gdb/testsuite/gdb.rocm/gpu-solib-event.exp | 4 +- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/gdb/infrun.c b/gdb/infrun.c index 3ce711e0882..b6cd174cdc5 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -434,6 +434,17 @@ static struct cmd_list_element *stop_command; of shared library events by the dynamic linker. */ int stop_on_solib_events; +/* Extra literals for stop-on-solib-events setting. + Allows both string keywords and numeric values (0-3). */ +static const literal_def stop_on_solib_events_literals[] = + { + { "none", STOP_SOLIB_NONE, 0 }, /* Accept "none" or 0. */ + { "cpu", STOP_SOLIB_CPU, 1 }, /* Accept "cpu" or 1. */ + { "gpu", STOP_SOLIB_GPU, 2 }, /* Accept "gpu" or 2. */ + { "all", STOP_SOLIB_ALL, 3 }, /* Accept "all" or 3. */ + { nullptr } + }; + /* Enable or disable optional shared library event breakpoints as appropriate when the above flag is changed. */ @@ -448,26 +459,39 @@ static void show_stop_on_solib_events (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - int val = atoi (value); - - gdb_printf (file, _("Stopping for shared library events is %s"), value); - - switch (val) + /* The value string will show the literal ("none", "cpu", "gpu", "all") + when set via keyword, or the number when set numerically. Access the + actual integer value to provide consistent descriptive suffix. */ + switch (stop_on_solib_events) { case STOP_SOLIB_NONE: - gdb_printf (file, _(" (disabled).\n")); + gdb_printf (file, + _("Stopping for shared library events is \"%s\" " + "(disabled).\n"), + value); break; case STOP_SOLIB_CPU: - gdb_printf (file, _(" (CPU libraries only).\n")); + gdb_printf (file, + _("Stopping for shared library events is \"%s\" " + "(CPU libraries only).\n"), + value); break; case STOP_SOLIB_GPU: - gdb_printf (file, _(" (GPU code objects only).\n")); + gdb_printf (file, + _("Stopping for shared library events is \"%s\" " + "(GPU code objects only).\n"), + value); break; case STOP_SOLIB_ALL: - gdb_printf (file, _(" (CPU and GPU).\n")); + gdb_printf (file, + _("Stopping for shared library events is \"%s\" " + "(CPU and GPU).\n"), + value); break; default: - gdb_printf (file, _(".\n")); + gdb_printf (file, + _("Stopping for shared library events is \"%s\".\n"), + value); break; } } @@ -11053,15 +11077,17 @@ leave it stopped or free to run as needed."), /* Update cached state. */ signal_cache_update (-1); - add_setshow_zinteger_cmd ("stop-on-solib-events", class_support, - &stop_on_solib_events, _("\ + add_setshow_uinteger_cmd ("stop-on-solib-events", class_support, + (unsigned int *) &stop_on_solib_events, + stop_on_solib_events_literals, _("\ Set stopping for shared library events."), _("\ Show stopping for shared library events."), _("\ -Values:\n\ - 0 == Do not stop on shared library events.\n\ - 1 == Stop on CPU shared library events only.\n\ - 2 == Stop on GPU code object events only.\n\ - 3 == Stop on both CPU and GPU library events.\n\ +If a number, valid values are 0 through 3. Alternatively, the following\n\ +keywords may be used:\n\ + none - Do not stop on shared library events.\n\ + cpu - Stop on CPU shared library events only.\n\ + gpu - Stop on GPU code object events only.\n\ + all - Stop on both CPU and GPU library events.\n\ The most common events of interest are loading/unloading of libraries."), set_stop_on_solib_events, show_stop_on_solib_events, diff --git a/gdb/testsuite/gdb.rocm/gpu-solib-event.exp b/gdb/testsuite/gdb.rocm/gpu-solib-event.exp index 6ccd033a42b..18343b10912 100644 --- a/gdb/testsuite/gdb.rocm/gpu-solib-event.exp +++ b/gdb/testsuite/gdb.rocm/gpu-solib-event.exp @@ -94,9 +94,9 @@ proc do_test {} { return } - # Use value 2 to stop on GPU code object events only. + # Use "gpu" to stop on GPU code object events only. # This avoids CPU shared library events during test execution. - gdb_test_no_output "set stop-on-solib-events 2" + gdb_test_no_output "set stop-on-solib-events gpu" # Test 1: file:// load event (hipModuleLoad). gdb_breakpoint "test_file_load" -temporary