DxilDiaDataSource.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilDiaDataSource.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // DIA API implementation for DXIL modules. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "DxilDiaDataSource.h"
  12. #include "dxc/DxilContainer/DxilContainer.h"
  13. #include "dxc/DXIL/DxilUtil.h"
  14. #include "dxc/DXIL/DxilPDB.h"
  15. #include "dxc/Support/FileIOHelper.h"
  16. #include "dxc/Support/dxcapi.impl.h"
  17. #include "llvm/Support/MSFileSystem.h"
  18. #include "llvm/Support/FileSystem.h"
  19. #include "llvm/Support/MemoryBuffer.h"
  20. #include "llvm/IR/DebugInfo.h"
  21. #include "llvm/IR/LLVMContext.h"
  22. #include "llvm/IR/Module.h"
  23. #include "DxilDiaSession.h"
  24. dxil_dia::DataSource::DataSource(IMalloc *pMalloc) : m_pMalloc(pMalloc) {
  25. }
  26. dxil_dia::DataSource::~DataSource() {
  27. // These are cross-referenced, so let's be explicit.
  28. m_finder.reset();
  29. m_module.reset();
  30. m_context.reset();
  31. }
  32. STDMETHODIMP dxil_dia::DataSource::get_lastError(BSTR *pRetVal) {
  33. *pRetVal = nullptr;
  34. return S_OK;
  35. }
  36. namespace dxil_dia
  37. {
  38. std::unique_ptr<llvm::MemoryBuffer> getMemBufferFromBlob(_In_ IDxcBlob *pBlob,
  39. const llvm::Twine &BufferName) {
  40. llvm::StringRef Data((LPSTR)pBlob->GetBufferPointer(), pBlob->GetBufferSize());
  41. return llvm::MemoryBuffer::getMemBufferCopy(Data, BufferName);
  42. }
  43. std::unique_ptr<llvm::MemoryBuffer> getMemBufferFromStream(_In_ IStream *pStream,
  44. const llvm::Twine &BufferName) {
  45. CComPtr<IDxcBlob> pBlob;
  46. if (SUCCEEDED(pStream->QueryInterface(&pBlob))) {
  47. return getMemBufferFromBlob(pBlob, BufferName);
  48. }
  49. STATSTG statstg;
  50. IFT(pStream->Stat(&statstg, STATFLAG_NONAME));
  51. size_t size = statstg.cbSize.LowPart;
  52. std::unique_ptr<llvm::MemoryBuffer> result(
  53. llvm::MemoryBuffer::getNewUninitMemBuffer(size, BufferName));
  54. char *pBuffer = (char *)result.get()->getBufferStart();
  55. ULONG read;
  56. IFT(pStream->Read(pBuffer, size, &read));
  57. return result;
  58. }
  59. } // namespace dxil_dia
  60. STDMETHODIMP dxil_dia::DataSource::loadDataFromIStream(_In_ IStream *pInputIStream) {
  61. try {
  62. DxcThreadMalloc TM(m_pMalloc);
  63. if (m_module.get() != nullptr) {
  64. return E_FAIL;
  65. }
  66. // Setup filesystem because bitcode reader might emit warning
  67. ::llvm::sys::fs::MSFileSystem* msfPtr;
  68. IFT(CreateMSFileSystemForDisk(&msfPtr));
  69. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  70. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  71. IFTLLVM(pts.error_code());
  72. CComPtr<IStream> pIStream = pInputIStream;
  73. CComPtr<IDxcBlob> pContainer;
  74. if (SUCCEEDED(hlsl::pdb::LoadDataFromStream(m_pMalloc, pInputIStream, &pContainer))) {
  75. const hlsl::DxilContainerHeader *pContainerHeader =
  76. hlsl::IsDxilContainerLike(pContainer->GetBufferPointer(), pContainer->GetBufferSize());
  77. if (!hlsl::IsValidDxilContainer(pContainerHeader, pContainer->GetBufferSize()))
  78. return E_FAIL;
  79. const hlsl::DxilPartHeader *PartHeader =
  80. hlsl::GetDxilPartByType(pContainerHeader, hlsl::DFCC_ShaderDebugInfoDXIL);
  81. if (!PartHeader)
  82. return E_FAIL;
  83. CComPtr<IDxcBlobEncoding> pPinnedBlob;
  84. IFR(hlsl::DxcCreateBlobWithEncodingFromPinned(PartHeader+1, PartHeader->PartSize, CP_ACP, &pPinnedBlob));
  85. pIStream.Release();
  86. IFR(hlsl::CreateReadOnlyBlobStream(pPinnedBlob, &pIStream));
  87. }
  88. m_context.reset();
  89. m_finder.reset();
  90. m_context = std::make_shared<llvm::LLVMContext>();
  91. llvm::MemoryBuffer *pBitcodeBuffer;
  92. std::unique_ptr<llvm::MemoryBuffer> pEmbeddedBuffer;
  93. std::unique_ptr<llvm::MemoryBuffer> pBuffer =
  94. getMemBufferFromStream(pIStream, "data");
  95. size_t bufferSize = pBuffer->getBufferSize();
  96. // The buffer can hold LLVM bitcode for a module, or the ILDB
  97. // part from a container.
  98. if (bufferSize < sizeof(UINT32)) {
  99. return DXC_E_MALFORMED_CONTAINER;
  100. }
  101. const UINT32 BC_C0DE = ((INT32)(INT8)'B' | (INT32)(INT8)'C' << 8 | (INT32)0xDEC0 << 16); // BC0xc0de in big endian
  102. if (BC_C0DE == *(const UINT32*)pBuffer->getBufferStart()) {
  103. pBitcodeBuffer = pBuffer.get();
  104. } else {
  105. if (bufferSize <= sizeof(hlsl::DxilProgramHeader)) {
  106. return DXC_E_MALFORMED_CONTAINER;
  107. }
  108. hlsl::DxilProgramHeader *pDxilProgramHeader = (hlsl::DxilProgramHeader *)pBuffer->getBufferStart();
  109. if (pDxilProgramHeader->BitcodeHeader.DxilMagic != hlsl::DxilMagicValue) {
  110. return DXC_E_MALFORMED_CONTAINER;
  111. }
  112. UINT32 BlobSize;
  113. const char *pBitcode = nullptr;
  114. hlsl::GetDxilProgramBitcode(pDxilProgramHeader, &pBitcode, &BlobSize);
  115. std::unique_ptr<llvm::MemoryBuffer> p = llvm::MemoryBuffer::getMemBuffer(
  116. llvm::StringRef(pBitcode, BlobSize), "data", false /* RequiresNullTerminator */);
  117. pEmbeddedBuffer.swap(p);
  118. pBitcodeBuffer = pEmbeddedBuffer.get();
  119. }
  120. std::string DiagStr;
  121. std::unique_ptr<llvm::Module> pModule = hlsl::dxilutil::LoadModuleFromBitcode(
  122. pBitcodeBuffer, *m_context.get(), DiagStr);
  123. if (!pModule.get())
  124. return E_FAIL;
  125. m_finder = std::make_shared<llvm::DebugInfoFinder>();
  126. m_finder->processModule(*pModule.get());
  127. m_module.reset(pModule.release());
  128. }
  129. CATCH_CPP_RETURN_HRESULT();
  130. return S_OK;
  131. }
  132. STDMETHODIMP dxil_dia::DataSource::openSession(_COM_Outptr_ IDiaSession **ppSession) {
  133. DxcThreadMalloc TM(m_pMalloc);
  134. *ppSession = nullptr;
  135. if (m_module.get() == nullptr)
  136. return E_FAIL;
  137. CComPtr<Session> pSession = Session::Alloc(DxcGetThreadMallocNoRef());
  138. IFROOM(pSession.p);
  139. pSession->Init(m_context, m_module, m_finder);
  140. *ppSession = pSession.Detach();
  141. return S_OK;
  142. }
  143. HRESULT CreateDxcDiaDataSource(_In_ REFIID riid, _Out_ LPVOID* ppv) {
  144. CComPtr<dxil_dia::DataSource> result = CreateOnMalloc<dxil_dia::DataSource>(DxcGetThreadMallocNoRef());
  145. if (result == nullptr) {
  146. *ppv = nullptr;
  147. return E_OUTOFMEMORY;
  148. }
  149. return result.p->QueryInterface(riid, ppv);
  150. }