From 233f7d1b970f2bec3c9095ede4b5916a90eeb65b Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Mon, 6 Jan 2025 11:21:25 +0000 Subject: [PATCH] DXIL Disassembly include DebugValue, DebugDeclare parsing --- renderdoc/driver/shaders/dxil/dxil_bytecode.h | 15 +++ renderdoc/driver/shaders/dxil/dxil_debug.cpp | 115 +++------------- renderdoc/driver/shaders/dxil/dxil_debug.h | 4 +- .../driver/shaders/dxil/dxil_disassemble.cpp | 125 ++++++++++++++++++ 4 files changed, 157 insertions(+), 102 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode.h b/renderdoc/driver/shaders/dxil/dxil_bytecode.h index c35722f99..b84f03fe6 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode.h +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode.h @@ -54,6 +54,8 @@ namespace DXIL static const rdcstr DXIL_FAKE_OUTPUT_STRUCT_NAME("_OUT"); static const rdcstr DXIL_FAKE_INPUT_STRUCT_NAME("_IN"); +struct DILocalVariable; + enum class FunctionFamily : uint8_t { Unknown, @@ -1580,6 +1582,16 @@ struct ResourceReference uint32_t resourceIndex; }; +struct SourceMappingInfo +{ + const DILocalVariable *localVariable; + int32_t srcByteOffset; + int32_t srcCountBytes; + DXILDebug::Id dbgVarId; + rdcstr dbgVarName; + bool isDeclare; +}; + class Program : public DXBC::IDebugInfo { friend DXILDebug::Debugger; @@ -1652,6 +1664,9 @@ protected: rdcstr GetDebugScopeFilePath(const DIBase *d) const; uint64_t GetDebugScopeLine(const DIBase *d) const; const Metadata *GetDebugScopeParent(const DIBase *d) const; + SourceMappingInfo ParseDbgOpValue(const DXIL::Instruction &inst) const; + SourceMappingInfo ParseDbgOpDeclare(const DXIL::Instruction &inst) const; + rdcpair ParseDIExpressionMD(const Metadata *expressionMD) const; rdcstr GetValueSymtabString(Value *v); void SetValueSymtabString(Value *v, const rdcstr &s); diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.cpp b/renderdoc/driver/shaders/dxil/dxil_debug.cpp index 29a457b48..5bdf61687 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_debug.cpp @@ -6674,123 +6674,40 @@ const TypeData &Debugger::AddDebugType(const DXIL::Metadata *typeMD) return m_DebugInfo.types[typeMD]; } -void Debugger::AddLocalVariable(const DXIL::Metadata *localVariableMD, uint32_t instructionIndex, - bool isDeclare, int32_t byteOffset, uint32_t countBytes, - Id debugVarSSAId, const rdcstr &debugVarSSAName) +void Debugger::AddLocalVariable(const DXIL::SourceMappingInfo &srcMapping, uint32_t instructionIndex) { - RDCASSERT(localVariableMD); - RDCASSERTEQUAL(localVariableMD->dwarf->type, DIBase::Type::LocalVariable); - const DILocalVariable *localVariable = localVariableMD->dwarf->As(); + ScopedDebugData *scope = AddScopedDebugData(srcMapping.localVariable->scope); - ScopedDebugData *scope = AddScopedDebugData(localVariable->scope); - - rdcstr sourceVarName = m_Program->GetDebugVarName(localVariable); LocalMapping localMapping; - localMapping.variable = localVariable; - localMapping.sourceVarName = sourceVarName; - localMapping.debugVarSSAName = debugVarSSAName; - localMapping.debugVarSSAId = debugVarSSAId; - localMapping.byteOffset = byteOffset; - localMapping.countBytes = countBytes; + localMapping.sourceVarName = m_Program->GetDebugVarName(srcMapping.localVariable); + localMapping.variable = srcMapping.localVariable; + localMapping.debugVarSSAName = srcMapping.dbgVarName; + localMapping.debugVarSSAId = srcMapping.dbgVarId; + localMapping.byteOffset = srcMapping.srcByteOffset; + localMapping.countBytes = srcMapping.srcCountBytes; + localMapping.isDeclare = srcMapping.isDeclare; localMapping.instIndex = instructionIndex; - localMapping.isDeclare = isDeclare; scope->localMappings.push_back(localMapping); - const DXIL::Metadata *typeMD = localVariable->type; + const DXIL::Metadata *typeMD = srcMapping.localVariable->type; if(m_DebugInfo.types.count(typeMD) == 0) AddDebugType(typeMD); - if(m_DebugInfo.locals.count(localVariable) == 0) - m_DebugInfo.locals[localVariable] = localMapping; + if(m_DebugInfo.locals.count(srcMapping.localVariable) == 0) + m_DebugInfo.locals[srcMapping.localVariable] = localMapping; } void Debugger::ParseDbgOpDeclare(const DXIL::Instruction &inst, uint32_t instructionIndex) { - // arg 0 contains the SSA Id of the alloca result which represents the local variable (a pointer) - const Metadata *allocaInstMD = cast(inst.args[0]); - RDCASSERT(allocaInstMD); - const Instruction *allocaInst = cast(allocaInstMD->value); - RDCASSERT(allocaInst); - RDCASSERTEQUAL(allocaInst->op, Operation::Alloca); - Id resultId = Program::GetResultSSAId(*allocaInst); - rdcstr resultName; - Program::MakeResultId(*allocaInst, resultName); - int32_t byteOffset = 0; - - // arg 1 is DILocalVariable metadata - const Metadata *localVariableMD = cast(inst.args[1]); - - // arg 2 is DIExpression metadata - const Metadata *expressionMD = cast(inst.args[2]); - uint32_t countBytes = 0; - if(expressionMD) - { - if(expressionMD->dwarf->type == DIBase::Type::Expression) - { - const DIExpression *expression = expressionMD->dwarf->As(); - switch(expression->op) - { - case DXIL::DW_OP::DW_OP_bit_piece: - byteOffset += (uint32_t)(expression->evaluated.bit_piece.offset / 8); - countBytes = (uint32_t)(expression->evaluated.bit_piece.size / 8); - break; - case DXIL::DW_OP::DW_OP_none: break; - case DXIL::DW_OP::DW_OP_nop: break; - default: RDCERR("Unhandled DIExpression op %s", ToStr(expression->op).c_str()); break; - } - } - else - { - RDCERR("Unhandled Expression Metadata %s", ToStr(expressionMD->dwarf->type).c_str()); - } - } - - AddLocalVariable(localVariableMD, instructionIndex, true, byteOffset, countBytes, resultId, - resultName); + DXIL::SourceMappingInfo sourceMappingInfo = m_Program->ParseDbgOpDeclare(inst); + AddLocalVariable(sourceMappingInfo, instructionIndex); } void Debugger::ParseDbgOpValue(const DXIL::Instruction &inst, uint32_t instructionIndex) { - // arg 0 is metadata containing the new value - const Metadata *valueMD = cast(inst.args[0]); - Id resultId = GetSSAId(valueMD->value); - rdcstr resultName = m_Program->GetArgumentName(valueMD->value); - // arg 1 is i64 byte offset in the source variable where the new value is written - int64_t value = 0; - RDCASSERT(getival(inst.args[1], value)); - int32_t byteOffset = (int32_t)(value); - - // arg 2 is DILocalVariable metadata - const Metadata *localVariableMD = cast(inst.args[2]); - - // arg 3 is DIExpression metadata - uint32_t countBytes = 0; - const Metadata *expressionMD = cast(inst.args[3]); - if(expressionMD) - { - if(expressionMD->dwarf->type == DIBase::Type::Expression) - { - const DIExpression *expression = expressionMD->dwarf->As(); - switch(expression->op) - { - case DXIL::DW_OP::DW_OP_bit_piece: - byteOffset += (uint32_t)(expression->evaluated.bit_piece.offset / 8); - countBytes = (uint32_t)(expression->evaluated.bit_piece.size / 8); - break; - case DXIL::DW_OP::DW_OP_none: break; - case DXIL::DW_OP::DW_OP_nop: break; - default: RDCERR("Unhandled DIExpression op %s", ToStr(expression->op).c_str()); break; - } - } - else - { - RDCERR("Unhandled Expression Metadata %s", ToStr(expressionMD->dwarf->type).c_str()); - } - } - - AddLocalVariable(localVariableMD, instructionIndex, false, byteOffset, countBytes, resultId, - resultName); + DXIL::SourceMappingInfo sourceMappingInfo = m_Program->ParseDbgOpValue(inst); + AddLocalVariable(sourceMappingInfo, instructionIndex); } void Debugger::ParseDebugData() diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.h b/renderdoc/driver/shaders/dxil/dxil_debug.h index 9bd739fd2..a42416cdf 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.h +++ b/renderdoc/driver/shaders/dxil/dxil_debug.h @@ -538,9 +538,7 @@ private: ScopedDebugData *AddScopedDebugData(const DXIL::Metadata *scopeMD); ScopedDebugData *FindScopedDebugData(const DXIL::Metadata *md) const; const TypeData &AddDebugType(const DXIL::Metadata *typeMD); - void AddLocalVariable(const DXIL::Metadata *localVariableMD, uint32_t instructionIndex, - bool isDeclare, int32_t byteOffset, uint32_t countBytes, Id debugSSAId, - const rdcstr &debugVarSSAName); + void AddLocalVariable(const DXIL::SourceMappingInfo &srcMapping, uint32_t instructionIndex); void ParseDebugData(); rdcarray m_Workgroups; diff --git a/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp b/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp index c0f100072..04f72df8a 100644 --- a/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp @@ -27,8 +27,10 @@ #include #include "common/formatting.h" #include "maths/half_convert.h" +#include "strings/string_utils.h" #include "dxil_bytecode.h" #include "dxil_common.h" +#include "dxil_debuginfo.h" #if ENABLED(DXC_COMPATIBLE_DISASM) && ENABLED(RDOC_RELEASE) @@ -4343,6 +4345,40 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection) } else if(callFunc->family == FunctionFamily::LLVMDbg) { + SourceMappingInfo sourceMappingInfo; + switch(callFunc->llvmIntrinsicOp) + { + case LLVMIntrinsicOp::DbgDeclare: + lineStr = "DbgDeclare"; + sourceMappingInfo = ParseDbgOpDeclare(inst); + break; + case LLVMIntrinsicOp::DbgValue: + lineStr = "DbgValue"; + sourceMappingInfo = ParseDbgOpValue(inst); + break; + default: break; + } + if(sourceMappingInfo.localVariable) + { + rdcstr sourceVarName = GetDebugVarName(sourceMappingInfo.localVariable); + rdcstr functionName = GetFunctionScopeName(sourceMappingInfo.localVariable); + + commentStr += StringFormat::Fmt( + "Function '%s' Variable '%s' Offset %u Count %u bytes maps to %s", + functionName.c_str(), sourceVarName.c_str(), sourceMappingInfo.srcByteOffset, + sourceMappingInfo.srcCountBytes, sourceMappingInfo.dbgVarName.c_str()); + + uint32_t dbgLoc = inst.debugLoc; + if(dbgLoc != ~0U) + { + const DebugLocation &debugLoc = m_DebugLocations[dbgLoc]; + + rdcstr shaderFilePath = standardise_directory_separator( + GetDebugScopeFilePath(sourceMappingInfo.localVariable)); + commentStr += StringFormat::Fmt( + " ; File:%s Line:%u", get_basename(shaderFilePath).c_str(), debugLoc.line); + } + } } else if(callFunc->family == FunctionFamily::LLVMInstrinsic) { @@ -6130,4 +6166,93 @@ void Program::MakeResultId(const DXIL::Instruction &inst, rdcstr &resultId) resultId = StringFormat::Fmt("%c%s", '_', ToStr(inst.slot).c_str()); } +rdcpair Program::ParseDIExpressionMD(const Metadata *expressionMD) const +{ + rdcpair ret; + ret.first = 0; + ret.second = 0; + + if(expressionMD) + { + if(expressionMD->dwarf->type == DIBase::Type::Expression) + { + const DIExpression *expression = expressionMD->dwarf->As(); + switch(expression->op) + { + case DXIL::DW_OP::DW_OP_bit_piece: + ret.first = (uint32_t)(expression->evaluated.bit_piece.offset / 8); + ret.second = (uint32_t)(expression->evaluated.bit_piece.size / 8); + break; + case DXIL::DW_OP::DW_OP_none: break; + case DXIL::DW_OP::DW_OP_nop: break; + default: RDCERR("Unhandled DIExpression op %s", ToStr(expression->op).c_str()); break; + } + } + else + { + RDCERR("Unhandled Expression Metadata %s", ToStr(expressionMD->dwarf->type).c_str()); + } + } + return ret; +} + +SourceMappingInfo Program::ParseDbgOpValue(const DXIL::Instruction &inst) const +{ + SourceMappingInfo ret; + ret.isDeclare = false; + + // arg 0 is metadata containing the new value + const Metadata *valueMD = cast(inst.args[0]); + ret.dbgVarId = GetSSAId(valueMD->value); + ret.dbgVarName = GetArgumentName(valueMD->value); + + // arg 1 is i64 byte offset in the source variable where the new value is written + int64_t value = 0; + RDCASSERT(getival(inst.args[1], value)); + ret.srcByteOffset = (int32_t)(value); + + // arg 2 is DILocalVariable metadata + const Metadata *localVariableMD = cast(inst.args[2]); + RDCASSERT(localVariableMD); + RDCASSERTEQUAL(localVariableMD->dwarf->type, DIBase::Type::LocalVariable); + ret.localVariable = localVariableMD->dwarf->As(); + + // arg 3 is DIExpression metadata + const Metadata *expressionMD = cast(inst.args[3]); + rdcpair srcMapping = ParseDIExpressionMD(expressionMD); + ret.srcByteOffset += srcMapping.first; + ret.srcCountBytes = srcMapping.second; + + return ret; +} + +SourceMappingInfo Program::ParseDbgOpDeclare(const DXIL::Instruction &inst) const +{ + SourceMappingInfo ret; + ret.isDeclare = true; + + // arg 0 contains the SSA Id of the alloca result which represents the local variable (a pointer) + const Metadata *allocaInstMD = cast(inst.args[0]); + RDCASSERT(allocaInstMD); + const Instruction *allocaInst = cast(allocaInstMD->value); + RDCASSERT(allocaInst); + RDCASSERTEQUAL(allocaInst->op, Operation::Alloca); + ret.dbgVarId = Program::GetResultSSAId(*allocaInst); + Program::MakeResultId(*allocaInst, ret.dbgVarName); + + // arg 1 is DILocalVariable metadata + const Metadata *localVariableMD = cast(inst.args[1]); + RDCASSERT(localVariableMD); + RDCASSERTEQUAL(localVariableMD->dwarf->type, DIBase::Type::LocalVariable); + ret.localVariable = localVariableMD->dwarf->As(); + + // arg 2 is DIExpression metadata + const Metadata *expressionMD = cast(inst.args[2]); + rdcpair srcMapping = ParseDIExpressionMD(expressionMD); + ret.srcByteOffset = srcMapping.first; + ret.srcCountBytes = srcMapping.second; + + return ret; +} + }; // namespace DXIL