/////////////////////////////////////////////////////////////////////////////// // // // DxcPixDxilDebugInfo.cpp // // Copyright (C) Microsoft Corporation. All rights reserved. // // This file is distributed under the University of Illinois Open Source // // License. See LICENSE.TXT for details. // // // // Defines the main class for dxcompiler's API for PIX support. // // // /////////////////////////////////////////////////////////////////////////////// #include "dxc/Support/WinIncludes.h" #include "dxc/Support/exception.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugInfoMetadata.h" #include "DxcPixLiveVariables.h" #include "DxcPixDxilDebugInfo.h" #include "DxcPixBase.h" #include "dxc/DxilPixPasses/DxilPixVirtualRegisters.h" STDMETHODIMP dxil_debug_info::DxcPixDxilDebugInfo::GetLiveVariablesAt( _In_ DWORD InstructionOffset, _COM_Outptr_ IDxcPixDxilLiveVariables **ppLiveVariables) { return m_LiveVars->GetLiveVariablesAtInstruction( FindInstruction(InstructionOffset), ppLiveVariables); } STDMETHODIMP dxil_debug_info::DxcPixDxilDebugInfo::IsVariableInRegister( _In_ DWORD InstructionOffset, _In_ const wchar_t *VariableName) { return S_OK; } STDMETHODIMP dxil_debug_info::DxcPixDxilDebugInfo::GetFunctionName( _In_ DWORD InstructionOffset, _Outptr_result_z_ BSTR *ppFunctionName) { llvm::Instruction *IP = FindInstruction(InstructionOffset); const llvm::DITypeIdentifierMap EmptyMap; if (const llvm::DebugLoc &DL = IP->getDebugLoc()) { auto *S = llvm::dyn_cast(DL.getScope()); while(S != nullptr && !llvm::isa(S)) { if (auto *SS = llvm::dyn_cast(S)) { *ppFunctionName = CComBSTR(CA2W(SS->getName().data())).Detach(); return S_OK; } S = S->getScope().resolve(EmptyMap); } } *ppFunctionName = CComBSTR(L"").Detach(); return S_FALSE; } STDMETHODIMP dxil_debug_info::DxcPixDxilDebugInfo::GetStackDepth( _In_ DWORD InstructionOffset, _Outptr_ DWORD *StackDepth ) { llvm::Instruction *IP = FindInstruction(InstructionOffset); DWORD Depth = 0; llvm::DebugLoc DL = IP->getDebugLoc(); while (DL && DL.getInlinedAtScope() != nullptr) { DL = DL.getInlinedAt(); ++Depth; } *StackDepth = Depth; return S_OK; } #include "DxilDiaSession.h" dxil_debug_info::DxcPixDxilDebugInfo::DxcPixDxilDebugInfo( IMalloc *pMalloc, dxil_dia::Session *pSession) : m_pMalloc(pMalloc) , m_pSession(pSession) , m_LiveVars(new LiveVariables()) { m_LiveVars->Init(this); } dxil_debug_info::DxcPixDxilDebugInfo::~DxcPixDxilDebugInfo() = default; llvm::Module* dxil_debug_info::DxcPixDxilDebugInfo::GetModuleRef() { return &m_pSession->ModuleRef(); } llvm::Instruction* dxil_debug_info::DxcPixDxilDebugInfo::FindInstruction( DWORD InstructionOffset ) const { const auto Instructions = m_pSession->InstructionsRef(); auto it = Instructions.find(InstructionOffset); if (it == Instructions.end()) { throw hlsl::Exception(E_BOUNDS, "Out-of-bounds: Instruction offset"); } return const_cast(it->second); } STDMETHODIMP dxil_debug_info::DxcPixDxilDebugInfo::InstructionOffsetsFromSourceLocation( _In_ const wchar_t *FileName, _In_ DWORD SourceLine, _In_ DWORD SourceColumn, _COM_Outptr_ IDxcPixDxilInstructionOffsets **ppOffsets) { return dxil_debug_info::NewDxcPixDxilDebugInfoObjectOrThrow< dxil_debug_info::DxcPixDxilInstructionOffsets>( ppOffsets, m_pMalloc, m_pSession, FileName, SourceLine, SourceColumn); } static bool CompareFilenames(const wchar_t * l, const char * r) { while (*l && *r) { bool theSame = false; if (*l == L'/' && *r == '\\') { theSame = true; } if (*l == L'\\' && *r == '/') { theSame = true; } if (!theSame) { if (::tolower(*l) != ::tolower(*r)) { return false; } } l++; r++; } if (*l || *r) { return false; } return true; } dxil_debug_info::DxcPixDxilInstructionOffsets::DxcPixDxilInstructionOffsets( IMalloc *pMalloc, dxil_dia::Session *pSession, const wchar_t *FileName, DWORD SourceLine, DWORD SourceColumn) { assert(SourceColumn == 0); (void)SourceColumn; auto files = pSession->Contents()->operands(); for (const auto& file : files) { auto candidateFilename = llvm::dyn_cast(file->getOperand(0)) ->getString(); if (CompareFilenames(FileName, candidateFilename.str().c_str())) { auto Fn = pSession->DxilModuleRef().GetEntryFunction(); auto &Blocks = Fn->getBasicBlockList(); for (auto& CurrentBlock : Blocks) { auto& Is = CurrentBlock.getInstList(); for (auto& Inst : Is) { auto & debugLoc = Inst.getDebugLoc(); if (debugLoc) { unsigned line = debugLoc.getLine(); if (line == SourceLine) { std::uint32_t InstructionNumber; if (pix_dxil::PixDxilInstNum::FromInst(&Inst, &InstructionNumber)) { m_offsets.push_back(InstructionNumber); } } } } } } } } DWORD dxil_debug_info::DxcPixDxilInstructionOffsets::GetCount() { return static_cast(m_offsets.size()); } DWORD dxil_debug_info::DxcPixDxilInstructionOffsets::GetOffsetByIndex(DWORD Index) { if (Index < static_cast(m_offsets.size())) { return m_offsets[Index]; } return static_cast(-1); }