DXIL Disassembly include DebugValue, DebugDeclare parsing

This commit is contained in:
Jake Turner
2025-01-06 11:21:25 +00:00
parent ab9db02608
commit 233f7d1b97
4 changed files with 157 additions and 102 deletions
@@ -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<int32_t, int32_t> ParseDIExpressionMD(const Metadata *expressionMD) const;
rdcstr GetValueSymtabString(Value *v);
void SetValueSymtabString(Value *v, const rdcstr &s);
+16 -99
View File
@@ -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<DILocalVariable>();
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<Metadata>(inst.args[0]);
RDCASSERT(allocaInstMD);
const Instruction *allocaInst = cast<Instruction>(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<Metadata>(inst.args[1]);
// arg 2 is DIExpression metadata
const Metadata *expressionMD = cast<Metadata>(inst.args[2]);
uint32_t countBytes = 0;
if(expressionMD)
{
if(expressionMD->dwarf->type == DIBase::Type::Expression)
{
const DIExpression *expression = expressionMD->dwarf->As<DXIL::DIExpression>();
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<Metadata>(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<int64_t>(inst.args[1], value));
int32_t byteOffset = (int32_t)(value);
// arg 2 is DILocalVariable metadata
const Metadata *localVariableMD = cast<Metadata>(inst.args[2]);
// arg 3 is DIExpression metadata
uint32_t countBytes = 0;
const Metadata *expressionMD = cast<Metadata>(inst.args[3]);
if(expressionMD)
{
if(expressionMD->dwarf->type == DIBase::Type::Expression)
{
const DIExpression *expression = expressionMD->dwarf->As<DXIL::DIExpression>();
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()
+1 -3
View File
@@ -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<ThreadState> m_Workgroups;
@@ -27,8 +27,10 @@
#include <algorithm>
#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<int32_t, int32_t> Program::ParseDIExpressionMD(const Metadata *expressionMD) const
{
rdcpair<int32_t, int32_t> ret;
ret.first = 0;
ret.second = 0;
if(expressionMD)
{
if(expressionMD->dwarf->type == DIBase::Type::Expression)
{
const DIExpression *expression = expressionMD->dwarf->As<DXIL::DIExpression>();
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<Metadata>(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<int64_t>(inst.args[1], value));
ret.srcByteOffset = (int32_t)(value);
// arg 2 is DILocalVariable metadata
const Metadata *localVariableMD = cast<Metadata>(inst.args[2]);
RDCASSERT(localVariableMD);
RDCASSERTEQUAL(localVariableMD->dwarf->type, DIBase::Type::LocalVariable);
ret.localVariable = localVariableMD->dwarf->As<DILocalVariable>();
// arg 3 is DIExpression metadata
const Metadata *expressionMD = cast<Metadata>(inst.args[3]);
rdcpair<int32_t, int32_t> 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<Metadata>(inst.args[0]);
RDCASSERT(allocaInstMD);
const Instruction *allocaInst = cast<Instruction>(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<Metadata>(inst.args[1]);
RDCASSERT(localVariableMD);
RDCASSERTEQUAL(localVariableMD->dwarf->type, DIBase::Type::LocalVariable);
ret.localVariable = localVariableMD->dwarf->As<DILocalVariable>();
// arg 2 is DIExpression metadata
const Metadata *expressionMD = cast<Metadata>(inst.args[2]);
rdcpair<int32_t, int32_t> srcMapping = ParseDIExpressionMD(expressionMD);
ret.srcByteOffset = srcMapping.first;
ret.srcCountBytes = srcMapping.second;
return ret;
}
}; // namespace DXIL