Skip to content

Commit

Permalink
DXIL Disassembly include DebugValue, DebugDeclare parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
Zorro666 committed Jan 6, 2025
1 parent ab9db02 commit 233f7d1
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 102 deletions.
15 changes: 15 additions & 0 deletions renderdoc/driver/shaders/dxil/dxil_bytecode.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1652,6 +1664,9 @@ class Program : public DXBC::IDebugInfo
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);
Expand Down
115 changes: 16 additions & 99 deletions renderdoc/driver/shaders/dxil/dxil_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
4 changes: 1 addition & 3 deletions renderdoc/driver/shaders/dxil/dxil_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -538,9 +538,7 @@ class Debugger : public DXBCContainerDebugger
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;
Expand Down
125 changes: 125 additions & 0 deletions renderdoc/driver/shaders/dxil/dxil_disassemble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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

0 comments on commit 233f7d1

Please sign in to comment.