Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Lancelot SIX <Lancelot.Six@amd.com>
To: simon.marchi@polymtl.ca, gdb-patches@sourceware.org
Cc: Simon Marchi <simon.marchi@efficios.com>
Subject: Re: [PATCH 3/3] gdb/amd-dbgapi: add displaced stepping support
Date: Wed, 15 Jan 2025 11:02:31 +0000	[thread overview]
Message-ID: <8097b8ac-7d99-4472-bc59-599a358e8ede@amd.com> (raw)
In-Reply-To: <20250114191818.2393132-4-simon.marchi@polymtl.ca>

Hi Simon,

I have a couple of minor remarks below.

On 14/01/2025 19:16, simon.marchi@polymtl.ca wrote:
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
> 
> 
> From: Simon Marchi <simon.marchi@efficios.com>
> 
> Implement the target_ops displaced stepping methods to add displaced
> stepping support when debugging AMD GPU programs.  The knowledge of how
> to prepare and finish displaced steps is provided by the amd-dbgapi
> library, so the code here is relatively straightforward.  No need to
> parse instructions or handle fixups, that is done by the lib  We just
> need to remember, for each thread doing a displaced step, the displaced
> stepping id given by the library.
> 
> Add a test to exercise the new functionality.  The compiler generates
> DWARF that GDB doesn't understand yet [1], so trying to step over a
> breakpoint with DWARF present gives:
> 
>      (gdb) si
>      Unhandled dwarf expression opcode 0xe9
> 
> The test purposefully builds the binary without DWARF info to circumvent
> this.
> 
> [1] https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html
> 
> Change-Id: I53f459221a42d4b02a6041eadb8cf554500e2162
> ---
>   gdb/amd-dbgapi-target.c                       | 138 ++++++++++++++++++
>   gdb/testsuite/gdb.rocm/displaced-stepping.exp |  54 +++++++
>   2 files changed, 192 insertions(+)
>   create mode 100644 gdb/testsuite/gdb.rocm/displaced-stepping.exp
> 
> diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
> index 153a35f788ed..996e16abf591 100644
> --- a/gdb/amd-dbgapi-target.c
> +++ b/gdb/amd-dbgapi-target.c
> @@ -24,6 +24,7 @@
>   #include "cli/cli-cmds.h"
>   #include "cli/cli-decode.h"
>   #include "cli/cli-style.h"
> +#include "gdbcore.h"
>   #include "gdbsupport/unordered_map.h"
>   #include "inf-loop.h"
>   #include "inferior.h"
> @@ -215,6 +216,12 @@ struct amd_dbgapi_inferior_info
>     /* List of pending events the amd-dbgapi target retrieved from the dbgapi.  */
>     std::list<std::pair<ptid_t, target_waitstatus>> wave_events;
> 
> +  /* Map of threads with ongoing displaced steps to corresponding amd-dbgapi
> +     displaced stepping handles.  */
> +  gdb::unordered_map<thread_info *,
> +                    decltype (amd_dbgapi_displaced_stepping_id_t::handle)>
> +    stepping_id_map;
> +
>     /* Map of wave ID to wave_info.  We cache wave_info objects because
>        we need to access the info after the wave is gone, in the thread
>        exit nofication.  E.g.:
> @@ -291,6 +298,21 @@ struct amd_dbgapi_target final : public target_ops
>     bool stopped_by_sw_breakpoint () override;
>     bool stopped_by_hw_breakpoint () override;
> 
> +  bool supports_displaced_step (thread_info *thread) override
> +  {
> +    /* Handle displaced stepping for GPU threads only.  */
> +    if (!ptid_is_gpu (thread->ptid))
> +      return beneath ()->supports_displaced_step (thread);
> +
> +    return true;
> +  }
> +
> +  displaced_step_prepare_status displaced_step_prepare
> +    (thread_info *thread, CORE_ADDR &displaced_pc) override;
> +
> +  displaced_step_finish_status displaced_step_finish
> +    (thread_info *thread, const target_waitstatus &status) override;
> +
>   private:
>     /* True if we must report thread events.  */
>     bool m_report_thread_events = false;
> @@ -1897,6 +1919,122 @@ amd_dbgapi_target::update_thread_list ()
>     this->beneath ()->update_thread_list ();
>   }
> 
> +displaced_step_prepare_status
> +amd_dbgapi_target::displaced_step_prepare (thread_info *thread,
> +                                          CORE_ADDR &displaced_pc)
> +{
> +  if (!ptid_is_gpu (thread->ptid))
> +    return beneath ()->displaced_step_prepare (thread, displaced_pc);
> +
> +  gdb_assert (!thread->displaced_step_state.in_progress ());
> +
> +  /* Read the bytes that were overwritten by the breakpoint instruction being
> +     stepped over.  */
> +  CORE_ADDR original_pc = regcache_read_pc (get_thread_regcache (thread));
> +  gdbarch *arch = get_thread_regcache (thread)->arch ();
> +  size_t size = get_amdgpu_gdbarch_tdep (arch)->breakpoint_instruction_size;
> +  gdb::byte_vector overwritten_bytes (size);
> +
> +  read_memory (original_pc, overwritten_bytes.data (), size);
> +
> +  /* Ask dbgapi to start the displaced step.  */
> +  amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (thread->ptid);
> +  amd_dbgapi_displaced_stepping_id_t stepping_id;
> +  amd_dbgapi_status_t status
> +    = amd_dbgapi_displaced_stepping_start (wave_id, overwritten_bytes.data (),
> +                                          &stepping_id);
> +
> +  switch (status)
> +   {
> +    case AMD_DBGAPI_STATUS_SUCCESS:
> +      break;
> +
> +    case AMD_DBGAPI_STATUS_ERROR_DISPLACED_STEPPING_BUFFER_NOT_AVAILABLE:
> +      return DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE;
> +
> +    case AMD_DBGAPI_STATUS_ERROR_ILLEGAL_INSTRUCTION:
> +      return DISPLACED_STEP_PREPARE_STATUS_CANT;
> +
> +    default:
> +      error (_("amd_dbgapi_displaced_stepping_start failed (%s)"),
> +          get_status_string (status));
> +    }
> +
> +  /* Save the displaced stepping id in the per-inferior info.  */
> +  amd_dbgapi_inferior_info *info = get_amd_dbgapi_inferior_info (thread->inf);
> +
> +  bool inserted
> +    = info->stepping_id_map.emplace (thread, stepping_id.handle).second;
> +  gdb_assert (inserted);
> +
> +  /* Get the new (displaced) PC.  */
> +  status = amd_dbgapi_wave_get_info (wave_id, AMD_DBGAPI_WAVE_INFO_PC,
> +                                    sizeof (displaced_pc), &displaced_pc);
> +  if (status != AMD_DBGAPI_STATUS_SUCCESS)
> +    {
> +      amd_dbgapi_displaced_stepping_complete (wave_id, stepping_id);
> +      error (_("amd_dbgapi_wave_get_info failed (%s), could not get the "
> +              "thread's displaced PC."),
> +            get_status_string (status));
> +    }
> +
> +  displaced_debug_printf ("selected buffer at %#lx", displaced_pc);
> +
> +  /* We may have written some registers, so flush the register cache.  */
> +  registers_changed_thread (thread);
> +
> +  return DISPLACED_STEP_PREPARE_STATUS_OK;
> +}
> +
> +displaced_step_finish_status
> +amd_dbgapi_target::displaced_step_finish (thread_info *thread,
> +                                         const target_waitstatus &ws)
> +{
> +  if (!ptid_is_gpu (thread->ptid))
> +    return beneath ()->displaced_step_finish (thread, ws);
> +
> +  gdb_assert (thread->displaced_step_state.in_progress ());
> +
> +  /* Find the displaced stepping id for this thread.  */
> +  amd_dbgapi_inferior_info *info = get_amd_dbgapi_inferior_info (thread->inf);
> +  auto entry = info->stepping_id_map.extract (thread);
> +
> +  gdb_assert (entry.has_value ());
> +  amd_dbgapi_displaced_stepping_id_t stepping_id {entry->second};
> +
> +  /* If the thread exited while stepping, we are done.  The code above
> +     cleared our associated resources.  We don't want to call dbgapi
> +     below: since the thread is gone, we wouldn't be able to find the
> +     necessary wave ID.  dbgapi already took care of releasing its
> +     displaced-stepping-related resources when it deleted the
> +     wave.  */
> +  if (ws.kind () == TARGET_WAITKIND_THREAD_EXITED)
> +    return DISPLACED_STEP_FINISH_STATUS_OK;
> +
> +  amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (thread->ptid);
> +  amd_dbgapi_wave_stop_reasons_t stop_reason;
> +  amd_dbgapi_status_t status
> +    = amd_dbgapi_wave_get_info (wave_id, AMD_DBGAPI_WAVE_INFO_STOP_REASON,
> +                               sizeof (stop_reason), &stop_reason);
> +
> +  if (status != AMD_DBGAPI_STATUS_SUCCESS)
> +    error (_("wave_get_info for wave_%ld failed (%s)"), wave_id.handle,
> +          get_status_string (status));
> +
> +  status = amd_dbgapi_displaced_stepping_complete (wave_id, stepping_id);
> +
> +  if (status != AMD_DBGAPI_STATUS_SUCCESS)
> +    error (_("amd_dbgapi_displaced_stepping_complete failed (%s)"),
> +          get_status_string (status));
> +
> +  /* We may have written some registers, so flush the register cache.  */
> +  registers_changed_thread (thread);
> +
> +  return (stop_reason & AMD_DBGAPI_WAVE_STOP_REASON_SINGLE_STEP) != 0
> +          ? DISPLACED_STEP_FINISH_STATUS_OK
> +          : DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED;
> +}
> +
>   /* inferior_created observer.  */
> 
>   static void
> diff --git a/gdb/testsuite/gdb.rocm/displaced-stepping.exp b/gdb/testsuite/gdb.rocm/displaced-stepping.exp
> new file mode 100644
> index 000000000000..6b26e1adfd7a
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rocm/displaced-stepping.exp
> @@ -0,0 +1,54 @@
> +# Copyright 2024 Free Software Foundation, Inc.

Should probably 2025.

> +
> +# 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 <http://www.gnu.org/licenses/>.
> +
> +# Test displaced stepping on AMD GPUs.
> +
> +load_lib rocm.exp
> +
> +standard_testfile simple.cpp

I though the usage in GDB testsuite was to not share the .cpp across 
multiple testcases.  Should there be a displaced-stepping.cpp?

> +
> +require allow_hipcc_tests
> +
> +# Since GDB doesn't yet understand DWARF expressions generated by the HIP
> +# compiler, purposefully generate the binary without debug info.
> +if {[build_executable "failed to prepare" $testfile $srcfile {hip}]} {
> +    return
> +}
> +
> +proc do_test {} {
> +    clean_restart $::binfile
> +
> +    with_rocm_gpu_lock {
> +       if ![runto_main] {
> +           return
> +       }
> +
> +       gdb_test "with breakpoint pending on -- break do_an_addition" \
> +           "Breakpoint $::decimal \\(do_an_addition\\) pending."
> +
> +       gdb_test "continue" \
> +           "Thread $::decimal hit Breakpoint $::decimal, $::hex in do_an_addition.*"
> +
> +       gdb_test_no_output "set debug displaced on"
> +
> +       gdb_test "stepi" "displaced_step_prepare_throw: prepared successfully.*$::hex in do_an_addition.*"

Just to reduce the noise in the gdb.log file when running the continue, 
this could be

gdb_test "with debug displaced on -- stepi" ...

> +
> +       gdb_test "continue" \
> +           "Inferior 1 .* exited normally.*" \
> +           "continue to end"
> +    }
> +}
> +
> +do_test
> --
> 2.47.1
> 

With those minor comments addressed, and given that it only touches 
amdgpu related code,
Approved-By: Lancelot Six <lancelot.six@amd.com> (amdgpu)

  reply	other threads:[~2025-01-15 11:03 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-14 19:16 [PATCH 0/3] Add displaced stepping support for AMD GPUs simon.marchi
2025-01-14 19:16 ` [PATCH 1/3] gdb/amd-dbgapi: use gdb::unordered_map simon.marchi
2025-01-15 10:55   ` Lancelot SIX
2025-01-15 18:41     ` Simon Marchi
2025-01-15 18:46       ` Simon Marchi
2025-01-15 18:50         ` Guinevere Larsen
2025-01-15 18:55       ` Lancelot SIX
2025-01-14 19:16 ` [PATCH 2/3] gdb: add target displaced stepping support simon.marchi
2025-01-14 19:16 ` [PATCH 3/3] gdb/amd-dbgapi: add " simon.marchi
2025-01-15 11:02   ` Lancelot SIX [this message]
2025-01-15 18:45     ` Simon Marchi
2025-02-25 17:17       ` Simon Marchi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8097b8ac-7d99-4472-bc59-599a358e8ede@amd.com \
    --to=lancelot.six@amd.com \
    --cc=gdb-patches@sourceware.org \
    --cc=simon.marchi@efficios.com \
    --cc=simon.marchi@polymtl.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox