AMD_DBGAPI: Displaced Stepping

AMD_DBGAPI 0.64.0

Data Structures | Macros | Enumerations | Functions
Displaced Stepping

Operations related to AMD GPU breakpoint displaced stepping. More...

## Data Structures
struct | amd_dbgapi_displaced_stepping_id_t
| Opaque displaced stepping handle. More...

## Macros
#define | AMD_DBGAPI_DISPLACED_STEPPING_NONE (amd_dbgapi_displaced_stepping_id_t{ 0 })
| The NULL displaced stepping handle. More...

## Enumerations
enum | amd_dbgapi_displaced_stepping_info_t { AMD_DBGAPI_DISPLACED_STEPPING_INFO_PROCESS = 1 }
| Displaced stepping queries that are supported by amd_dbgapi_displaced_stepping_id_t. More...

## Functions
amd_dbgapi_status_t AMD_DBGAPI | amd_dbgapi_displaced_stepping_get_info (amd_dbgapi_displaced_stepping_id_t displaced_stepping_id, amd_dbgapi_displaced_stepping_info_t query, size_t value_size, void *value) AMD_DBGAPI_VERSION_0_54
| Query information about a displaced stepping buffer. More...
amd_dbgapi_status_t AMD_DBGAPI | amd_dbgapi_displaced_stepping_start (amd_dbgapi_wave_id_t wave_id, const void *saved_instruction_bytes, amd_dbgapi_displaced_stepping_id_t *displaced_stepping) AMD_DBGAPI_VERSION_0_54
| Associate an active displaced stepping buffer with a wave. More...
amd_dbgapi_status_t AMD_DBGAPI | amd_dbgapi_displaced_stepping_complete (amd_dbgapi_wave_id_t wave_id, amd_dbgapi_displaced_stepping_id_t displaced_stepping) AMD_DBGAPI_VERSION_0_54
| Complete a displaced stepping buffer for a wave. More...

## Detailed Description

Operations related to AMD GPU breakpoint displaced stepping.

The library supports displaced stepping buffers. These allow an instruction that is overwritten by a breakpoint instruction to be copied to a buffer and single stepped in that buffer. This avoids needing to remove the breakpoint instruction by replacing it with the original instruction bytes, single stepping the original instruction, and finally restoring the breakpoint instruction.

This allows a client to support non-stop debugging where waves are left executing while others are halted after hitting a breakpoint. If resuming from a breakpoint involved removing the breakpoint, it could result in the running waves missing the removed breakpoint.

When an instruction is copied into a displaced stepping buffer, it may be necessary to modify the instruction, or its register inputs to account for the fact that it is executing at a different address. Similarly, after single stepping it, registers and program counter may need adjusting. It may also be possible to know the effect of an instruction and avoid single stepping it at all and simply update the wave state directly. For example, branches can be trivial to emulate this way.

The operations in this section allow displaced stepping buffers to be allocated and used. They will take care of all the architecture specific details described above.

The number of displaced stepping buffers supported by the library is unspecified, but there is always at least one. It may be possible for the library to share the same displaced stepping buffer with multiple waves. For example, if the waves are at the same breakpoint. The library will determine when this is possible, but the client should not rely on this. Some waves at the same breakpoint may be able to share while others may not. In general, it is best for the client to single step as many waves as possible to minimize the time to get all waves stepped over the breakpoints.

The client may be able to maximize the number of waves it can single step at once by requesting displaced stepping buffers for all waves at the same breakpoint. Just because there is no displaced stepping buffer for one wave, does not mean another wave cannot be assigned to a displaced stepping buffer through sharing, or through buffers being associated with specific agents or queues.

If allocating a displaced stepping buffer (amd_dbgapi_displaced_stepping_start) is successful, then the client must resume the wave (amd_dbgapi_wave_resume) in single step mode. When the single step is reported as completed (AMD_DBGAPI_EVENT_KIND_WAVE_STOP), the buffer can be released (amd_dbgapi_displaced_stepping_complete), and the wave resumed normally (amd_dbgapi_wave_resume).

If the single step is reported as terminated (AMD_DBGAPI_EVENT_KIND_WAVE_COMMAND_TERMINATED), then that indicates that the wave has exited. When a wave exits, any associated displaced stepping buffer is automatically released.

If the wave does not report the single step as complete (AMD_DBGAPI_EVENT_KIND_WAVE_STOP) or terminated (AMD_DBGAPI_EVENT_KIND_WAVE_COMMAND_TERMINATED), then the wave can be stopped (amd_dbgapi_wave_stop), and the buffer released (amd_dbgapi_displaced_stepping_complete). This will leave the wave still at the breakpoint, and the client can retry stepping over the breakpoint later (amd_dbgapi_displaced_stepping_start).

If allocating a displaced stepping buffer indicates no more are available, the client must complete ongoing single steppings and release the associated buffers. It can do that by ensuring the waves with allocated stepping buffers are resumed in single step mode, ensure that the waves will make forward progress, and process any reported pending events. This allows waves to perform the single step, report the single step has completed by an event, and the client's processing of the event will release the displaced stepping buffer (amd_dbgapi_displaced_stepping_complete). That may free up a displaced stepping buffer for use by the client for other waves. Since there is always at least one displaced stepping buffer, in general, the worst case is that one wave at a time can be single stepped over a breakpoint using a displaced stepping buffer.

However, the weak forward progress of AMD GPU execution can result in no waves that have successfully been allocated a displaced stepping buffer from actually reporting completion of the single step. For example, this can happen if the waves being single stepped are prevented from becoming resident on the hardware due to other waves that are halted. The waves being single stepped can be stopped before completing the single step to release the displaced stepping buffer for use by a different set of waves. In the worst case, the user may have to continue halted waves and allow them to terminate before other waves can make forward progress to complete the single step using a displaced stepping buffer.

See also
  amd_dbgapi_wave_resume, amd_dbgapi_wave_stop, amd_dbgapi_process_set_progress, amd_dbgapi_process_next_pending_event

## Macro Definition Documentation

## ◆ AMD_DBGAPI_DISPLACED_STEPPING_NONE

#define AMD_DBGAPI_DISPLACED_STEPPING_NONE (amd_dbgapi_displaced_stepping_id_t{ 0 })

The NULL displaced stepping handle.

## Enumeration Type Documentation

## ◆ amd_dbgapi_displaced_stepping_info_t

enum amd_dbgapi_displaced_stepping_info_t

Displaced stepping queries that are supported by amd_dbgapi_displaced_stepping_id_t.

Each query specifies the type of data returned in the `value` argument to amd_dbgapi_displaced_stepping_id_t.

Enumerator
AMD_DBGAPI_DISPLACED_STEPPING_INFO_PROCESS | Return the process to which this displaced stepping buffer belongs. The type of this attribute is amd_dbgapi_process_id_t.

## Function Documentation

## ◆ amd_dbgapi_displaced_stepping_complete()

amd_dbgapi_status_t AMD_DBGAPI amd_dbgapi_displaced_stepping_complete | ( | amd_dbgapi_wave_id_t | wave_id,
|  | amd_dbgapi_displaced_stepping_id_t | displaced_stepping
| ) |  |

Complete a displaced stepping buffer for a wave.

The wave must be stopped and have an associated displaced stepping buffer by using amd_dbgapi_displaced_stepping_start.

If the wave single step has not completed, the wave state is reset to what it was before amd_dbgapi_displaced_stepping_start. The wave is left stopped and the client can retry stepping over the breakpoint again later.

If the single step has completed, then the wave state is updated to be after the instruction at which the breakpoint instruction is placed.

Completing a displaced stepping buffer may read and write the wave program counter and other registers so the client should invalidate any cached register values after completing a displaced stepping buffer. The wave is left stopped and can be resumed normally by the client.

If the wave is the last one using the displaced stepping buffer, the buffer is freed and the handle invalidated.

Parameters

  [in] | wave_id | The wave using the displaced stepping buffer.
  [in] | displaced_stepping | The displaced stepping buffer to complete.

Return values

  AMD_DBGAPI_STATUS_SUCCESS | The function has been executed successfully. The displaced stepping buffer is completed, and the wave is either stepped over the breakpoint, or still at the breakpoint.
  AMD_DBGAPI_STATUS_FATAL | A fatal error occurred. The library is left uninitialized, and no displaced stepping buffer is completed.
  AMD_DBGAPI_STATUS_ERROR_NOT_INITIALIZED | The library is not initialized. The library is left uninitialized, no displaced stepping buffer completed.
  AMD_DBGAPI_STATUS_ERROR_INVALID_WAVE_ID | `wave_id` is invalid. No displaced stepping buffer is completed.
  AMD_DBGAPI_STATUS_ERROR_INVALID_DISPLACED_STEPPING_ID | `displaced_stepping` is invalid. No displaced stepping buffer is completed.
  AMD_DBGAPI_STATUS_ERROR_WAVE_NOT_STOPPED | `wave_id` is not stopped. No displaced stepping buffer is completed.
  AMD_DBGAPI_STATUS_ERROR_INVALID_ARGUMENT_COMPATIBILITY | `displaced_stepping` is not in use by `wave_id` (which includes that the wave has already competed the displaced stepping buffer). No displaced stepping buffer is completed.

## ◆ amd_dbgapi_displaced_stepping_get_info()

amd_dbgapi_status_t AMD_DBGAPI amd_dbgapi_displaced_stepping_get_info | ( | amd_dbgapi_displaced_stepping_id_t | displaced_stepping_id,
|  | amd_dbgapi_displaced_stepping_info_t | query,
|  | size_t | value_size,
|  | void * | value
| ) |  |

Query information about a displaced stepping buffer.

amd_dbgapi_displaced_stepping_info_t specifies the queries supported and the type returned using the `value` argument.

Parameters

  [in] | displaced_stepping_id | The handle of the displaced stepping buffer being queried.
  [in] | query | The query being requested.
  [in] | value_size | Size of the memory pointed to by `value`. Must be equal to the byte size of the query result.
  [out] | value | Pointer to memory where the query result is stored.

Return values

  AMD_DBGAPI_STATUS_SUCCESS | The function has been executed successfully and the result is stored in `value`.
  AMD_DBGAPI_STATUS_FATAL | A fatal error occurred. The library is left uninitialized and `value` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_NOT_INITIALIZED | The library is not initialized. The library is left uninitialized and `value` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_INVALID_DISPLACED_STEPPING_ID | `displaced_stepping_id` is invalid. `value` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_INVALID_ARGUMENT | `value` is NULL or `query` is invalid. `value` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_INVALID_ARGUMENT_COMPATIBILITY | `value_size` does not match the size of the `query` result. `value` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_CLIENT_CALLBACK | This will be reported if the amd_dbgapi_callbacks_s::allocate_memory callback used to allocate `value` returns NULL. `value` is unaltered.

## ◆ amd_dbgapi_displaced_stepping_start()

amd_dbgapi_status_t AMD_DBGAPI amd_dbgapi_displaced_stepping_start | ( | amd_dbgapi_wave_id_t | wave_id,
|  | const void * | saved_instruction_bytes,
|  | amd_dbgapi_displaced_stepping_id_t * | displaced_stepping
| ) |  |

Associate an active displaced stepping buffer with a wave.

The wave must be stopped and not already have an active displaced stepping buffer.

Displaced stepping buffers are intended to be used to step over breakpoints. In that case, the wave will be stopped with a program counter set to a breakpoint instruction that was placed by the client overwriting all or part of the original instruction where the breakpoint was placed. The client must provide the overwritten bytes of the original instruction.

The wave program counter and other registers may be read and written as part of creating a displaced stepping buffer. Therefore, the client should flush any dirty cached register values before creating a displaced stepping buffer.

If a displaced stepping handle is returned successfully, the wave is still stopped. The client should resume the wave in single step mode using amd_dbgapi_wave_resume. Once the single step is complete as indicated by the AMD_DBGAPI_EVENT_KIND_WAVE_STOP event with a stop reason that includes AMD_DBGAPI_WAVE_STOP_REASON_SINGLE_STEP, the client should use amd_dbgapi_displaced_stepping_complete to release the displaced stepping buffer. The wave can then be resumed normally using amd_dbgapi_wave_resume.

If the single step is cancelled by stopping the wave, the client must determine if the wave completed the single step to determine if the wave can be resumed or must retry the displaced stepping later. See amd_dbgapi_wave_stop.

Parameters

  [in] | wave_id | The wave for which to create a displaced stepping buffer.
  [in] | saved_instruction_bytes | The original instruction bytes that the breakpoint instruction replaced. The number of bytes must be AMD_DBGAPI_ARCHITECTURE_INFO_BREAKPOINT_INSTRUCTION_SIZE.
  [out] | displaced_stepping | The displaced stepping handle.

Return values

  AMD_DBGAPI_STATUS_SUCCESS | The function has been executed successfully and `displaced_stepping` is set to a valid displaced stepping handle.
  AMD_DBGAPI_STATUS_FATAL | A fatal error occurred. The library is left uninitialized, no displaced stepping buffer is allocated, and `displaced_stepping` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_NOT_INITIALIZED | The library is not initialized. The library is left uninitialized, no displaced stepping buffer is allocated, and `displaced_stepping` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_INVALID_WAVE_ID | `wave_id` is invalid. No displaced stepping buffer is allocated and `displaced_stepping` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_WAVE_NOT_STOPPED | `wave_id` is not stopped. No displaced stepping buffer is allocated and `displaced_stepping` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_DISPLACED_STEPPING_ACTIVE | `wave_id` already has an active displaced stepping buffer. No displaced stepping buffer is allocated and `displaced_stepping` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_DISPLACED_STEPPING_BUFFER_NOT_AVAILABLE | No more displaced stepping buffers are available that are suitable for use by `wave_id`. No displaced stepping buffer is allocated and `displaced_stepping` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_INVALID_ARGUMENT | `original_instruction` or `displaced_stepping` are NULL. No displaced stepping buffer is allocated and `displaced_stepping` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_MEMORY_ACCESS | The memory at the wave's program counter could not be successfully read. No displaced stepping buffer is allocated and `displaced_stepping` is unaltered.
  AMD_DBGAPI_STATUS_ERROR_ILLEGAL_INSTRUCTION | The instruction at the wave's program counter is not a legal instruction for the architecture. No displaced stepping buffer is allocated and `displaced_stepping` is unaltered.