Displaced Stepping

Displaced Stepping#

AMD DBG API: Displaced Stepping
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_76
 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_76
 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

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_idThe wave using the displaced stepping buffer.
[in]displaced_steppingThe displaced stepping buffer to complete.
Return values
AMD_DBGAPI_STATUS_SUCCESSThe 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_FATALA fatal error occurred. The library is left uninitialized, and no displaced stepping buffer is completed.
AMD_DBGAPI_STATUS_ERROR_NOT_INITIALIZEDThe library is not initialized. The library is left uninitialized, no displaced stepping buffer completed.
AMD_DBGAPI_STATUS_ERROR_INVALID_WAVE_IDwave_id is invalid. No displaced stepping buffer is completed.
AMD_DBGAPI_STATUS_ERROR_INVALID_DISPLACED_STEPPING_IDdisplaced_stepping is invalid. No displaced stepping buffer is completed.
AMD_DBGAPI_STATUS_ERROR_WAVE_NOT_STOPPEDwave_id is not stopped. No displaced stepping buffer is completed.
AMD_DBGAPI_STATUS_ERROR_INVALID_ARGUMENT_COMPATIBILITYdisplaced_stepping is not in use by wave_id (which includes that the wave has already completed the displaced stepping buffer). No displaced stepping buffer is completed.
AMD_DBGAPI_STATUS_ERROR_PROCESS_FROZENThe process is frozen. 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_idThe handle of the displaced stepping buffer being queried.
[in]queryThe query being requested.
[in]value_sizeSize of the memory pointed to by value. Must be equal to the byte size of the query result.
[out]valuePointer to memory where the query result is stored.
Return values
AMD_DBGAPI_STATUS_SUCCESSThe function has been executed successfully and the result is stored in value.
AMD_DBGAPI_STATUS_FATALA fatal error occurred. The library is left uninitialized and value is unaltered.
AMD_DBGAPI_STATUS_ERROR_NOT_INITIALIZEDThe library is not initialized. The library is left uninitialized and value is unaltered.
AMD_DBGAPI_STATUS_ERROR_INVALID_DISPLACED_STEPPING_IDdisplaced_stepping_id is invalid. value is unaltered.
AMD_DBGAPI_STATUS_ERROR_INVALID_ARGUMENTvalue is NULL or query is invalid. value is unaltered.
AMD_DBGAPI_STATUS_ERROR_INVALID_ARGUMENT_COMPATIBILITYvalue_size does not match the size of the query result. value is unaltered.
AMD_DBGAPI_STATUS_ERROR_CLIENT_CALLBACKThis 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_idThe wave for which to create a displaced stepping buffer.
[in]saved_instruction_bytesThe original instruction bytes that the breakpoint instruction replaced. The number of bytes must be AMD_DBGAPI_ARCHITECTURE_INFO_BREAKPOINT_INSTRUCTION_SIZE.
[out]displaced_steppingThe displaced stepping handle.
Return values
AMD_DBGAPI_STATUS_SUCCESSThe function has been executed successfully and displaced_stepping is set to a valid displaced stepping handle.
AMD_DBGAPI_STATUS_FATALA fatal error occurred. The library is left uninitialized, no displaced stepping buffer is allocated, and displaced_stepping is unaltered.
AMD_DBGAPI_STATUS_ERROR_NOT_INITIALIZEDThe 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_IDwave_id is invalid. No displaced stepping buffer is allocated and displaced_stepping is unaltered.
AMD_DBGAPI_STATUS_ERROR_WAVE_NOT_STOPPEDwave_id is not stopped. No displaced stepping buffer is allocated and displaced_stepping is unaltered.
AMD_DBGAPI_STATUS_ERROR_DISPLACED_STEPPING_ACTIVEwave_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_AVAILABLENo 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_ARGUMENToriginal_instruction or displaced_stepping are NULL. No displaced stepping buffer is allocated and displaced_stepping is unaltered.
AMD_DBGAPI_STATUS_ERROR_MEMORY_ACCESSThe 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_INSTRUCTIONThe 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.
AMD_DBGAPI_STATUS_ERROR_PROCESS_FROZENThe process is frozen. No displaced stepping buffer is allocated and displaced_stepping is unaltered.