mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 01:50:38 +00:00
DXIL Disassembly include DebugValue, DebugDeclare parsing
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user