================================ Source Level Debugging with HLSL ================================ .. contents:: :local: Introduction ============ This document describes the specifics of source level debuging with HLSL. The basic infrastructure is based on :doc:`Source Level Debugging with LLVM `, so the focus here is on the specifics of DXIL programs compiled from HLSL. DXIL Debug Information Format ============================= The debug information for an HLSL program in DXIL form is stored as an LLVM module with debug information represented according to the :doc:`Source Level Debugging with LLVM ` document. The :ref:`dxil_container_format` describes how a single data structure holds both a DXIL program, debug information, and other optional parts. There are three parts that are associated with debug information. * DFCC_DXIL ('DXIL'). A valid DXIL program has no debug information. This is the program described by debug information. * DFCC_ShaderDebugInfoDXIL ('ILDB'). This is an LLVM module with debug information. It's an augmented version of the original DXIL module. For historical reasons, this is sometimes referred to as 'the PDB of the program'. * DFCC_ShaderDebugName ('ILDN'). This is a name for an external entity holding the debug information. Using Debug Information ======================= The debug information can be used directly by looking up the debug information part and loading into an LLVM module. There is full fidelity with debug information via this mechanism, although it requires linking in the LLVM supporting libraries. For compatibility, the dxcompiler.dll binary also exposes a limited implementation of the DIA APIs. To do this, a CLSID_DxcDiaDataSource class should be created via a call to DxcCreateInstance, and a loadDataFromIStream call with the debug part will initialize it. The DxcContext::Recompile implementation provides an example of how to initialize the diagnostic objects from debug information, extract high-level information and recreate the compilation options and inputs. Using Debug Names ================= The only current use case for the debug name is as a relative path to a file that provides shader debug information. A debugging tool would typically have a list of paths to act as search roots. Command-Line Options ==================== The following command-line options are used with the DirectX Shader Compiler tools to work with debug information. * /Zi. Enables debug information during compilation. * /Zss. Builds debug names that consider source information. * /Zsb. Builds debug names that consider only the output binary. * /Fd. Extracts debug information to a different file. * /Qstrip_debug. Removes debug information from a container. The most common use cases are as follows. * Build debug information and leave it in the container. In this case, simply compiling with /Zi will do the trick. * Build debug information and extract it to an auto-generated external file. In this case, /Zi and /Fd should both be used, and the /Fd value should end in a trailing backslash when using dxc, naming the target directory in which to place the file. /Zss is the default, but /Zsb can be used to deduplicate files. When using /Fd with a directory name, /Qstrip_debug is implied. A less common use case is to specify an explicit name for the external file. In this case, the command-line should include /Zi, /Fd with a specific name, and /Qstrip_debug. Implementation Notes ==================== The current implementation provides a few interesting behaviors worth noting. * The shader debug name is derived from either the DXIL or the ILDB parts by hashing the byte contents, but it can be replaced programmatically. * Source content is included in the debug information blob by default. This helps with scenarios where the code never exists on-disk, but is instead generated on-the-fly. * Typically the derivation is done from the ILDB part, which includes source-specific information, and so two shaders with different sources will have different debug information. However the option is provided via (-Zsb) to include debug information that only takes into consideration the DXIL binary. In this case, two shaders that compile to the same binary will have the same debug information, which can be used to deduplicate content when any equivalent source program is acceptable for debugging. Future Directions ================= This section is purely speculative, but captures some of the thoughts about future debugging capabilities. * If driver-level constructs should be debugged, they need to be mapped to DXIL first, and from there on to HLSL. * Including content in debug is convenient, especially when sources are transient, but they are inefficient (again, especially for a large number of transient sources). Deduplicating sources would be beneficial. * Integration with symbol servers and source servers can simplify some of the developer workflows.