1 //===- DIASession.cpp - DIA implementation of IPDBSession -------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
8 #include "llvm/DebugInfo/PDB/DIA/DIASession.h"
9 #include "llvm/ADT/STLExtras.h"
10 #include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h"
11 #include "llvm/DebugInfo/PDB/DIA/DIAEnumFrameData.h"
12 #include "llvm/DebugInfo/PDB/DIA/DIAEnumInjectedSources.h"
13 #include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h"
14 #include "llvm/DebugInfo/PDB/DIA/DIAEnumSectionContribs.h"
15 #include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h"
16 #include "llvm/DebugInfo/PDB/DIA/DIAEnumTables.h"
17 #include "llvm/DebugInfo/PDB/DIA/DIAError.h"
18 #include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h"
19 #include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h"
20 #include "llvm/DebugInfo/PDB/DIA/DIASupport.h"
21 #include "llvm/DebugInfo/PDB/GenericError.h"
22 #include "llvm/DebugInfo/PDB/PDB.h"
23 #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
24 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
25 #include "llvm/Support/ConvertUTF.h"
26 #include "llvm/Support/Format.h"
27 #include "llvm/Support/FormatVariadic.h"
28 #include "llvm/Support/raw_ostream.h"
31 using namespace llvm::pdb
;
33 template <typename
... Ts
>
34 static Error
ErrorFromHResult(HRESULT Result
, const char *Str
, Ts
&&... Args
) {
35 SmallString
<64> MessageStorage
;
37 if (sizeof...(Args
) > 0) {
38 MessageStorage
= formatv(Str
, std::forward
<Ts
>(Args
)...).str();
39 Context
= MessageStorage
;
45 return errorCodeToError(std::error_code(ENOENT
, std::generic_category()));
47 return make_error
<DIAError
>(dia_error_code::invalid_file_format
, Context
);
49 return make_error
<DIAError
>(dia_error_code::invalid_parameter
, Context
);
51 return make_error
<DIAError
>(dia_error_code::already_loaded
, Context
);
52 case E_PDB_INVALID_SIG
:
53 case E_PDB_INVALID_AGE
:
54 return make_error
<DIAError
>(dia_error_code::debug_info_mismatch
, Context
);
57 raw_string_ostream
OS(S
);
58 OS
<< "HRESULT: " << format_hex(static_cast<DWORD
>(Result
), 10, true)
60 return make_error
<DIAError
>(dia_error_code::unspecified
, OS
.str());
65 static Error
LoadDIA(CComPtr
<IDiaDataSource
> &DiaDataSource
) {
66 if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource
, nullptr, CLSCTX_INPROC_SERVER
,
68 reinterpret_cast<LPVOID
*>(&DiaDataSource
))))
69 return Error::success();
71 // If the CoCreateInstance call above failed, msdia*.dll is not registered.
72 // Try loading the DLL corresponding to the #included DIA SDK.
73 #if !defined(_MSC_VER)
74 return llvm::make_error
<PDBError
>(pdb_error_code::dia_failed_loading
);
76 const wchar_t *msdia_dll
= L
"msdia140.dll";
78 if (FAILED(HR
= NoRegCoCreate(msdia_dll
, CLSID_DiaSource
, IID_IDiaDataSource
,
79 reinterpret_cast<LPVOID
*>(&DiaDataSource
))))
80 return ErrorFromHResult(HR
, "Calling NoRegCoCreate");
81 return Error::success();
85 DIASession::DIASession(CComPtr
<IDiaSession
> DiaSession
) : Session(DiaSession
) {}
87 Error
DIASession::createFromPdb(StringRef Path
,
88 std::unique_ptr
<IPDBSession
> &Session
) {
89 CComPtr
<IDiaDataSource
> DiaDataSource
;
90 CComPtr
<IDiaSession
> DiaSession
;
92 // We assume that CoInitializeEx has already been called by the executable.
93 if (auto E
= LoadDIA(DiaDataSource
))
96 llvm::SmallVector
<UTF16
, 128> Path16
;
97 if (!llvm::convertUTF8ToUTF16String(Path
, Path16
))
98 return make_error
<PDBError
>(pdb_error_code::invalid_utf8_path
, Path
);
100 const wchar_t *Path16Str
= reinterpret_cast<const wchar_t *>(Path16
.data());
102 if (FAILED(HR
= DiaDataSource
->loadDataFromPdb(Path16Str
))) {
103 return ErrorFromHResult(HR
, "Calling loadDataFromPdb {0}", Path
);
106 if (FAILED(HR
= DiaDataSource
->openSession(&DiaSession
)))
107 return ErrorFromHResult(HR
, "Calling openSession");
109 Session
.reset(new DIASession(DiaSession
));
110 return Error::success();
113 Error
DIASession::createFromExe(StringRef Path
,
114 std::unique_ptr
<IPDBSession
> &Session
) {
115 CComPtr
<IDiaDataSource
> DiaDataSource
;
116 CComPtr
<IDiaSession
> DiaSession
;
118 // We assume that CoInitializeEx has already been called by the executable.
119 if (auto EC
= LoadDIA(DiaDataSource
))
122 llvm::SmallVector
<UTF16
, 128> Path16
;
123 if (!llvm::convertUTF8ToUTF16String(Path
, Path16
))
124 return make_error
<PDBError
>(pdb_error_code::invalid_utf8_path
, Path
);
126 const wchar_t *Path16Str
= reinterpret_cast<const wchar_t *>(Path16
.data());
128 if (FAILED(HR
= DiaDataSource
->loadDataForExe(Path16Str
, nullptr, nullptr)))
129 return ErrorFromHResult(HR
, "Calling loadDataForExe");
131 if (FAILED(HR
= DiaDataSource
->openSession(&DiaSession
)))
132 return ErrorFromHResult(HR
, "Calling openSession");
134 Session
.reset(new DIASession(DiaSession
));
135 return Error::success();
138 uint64_t DIASession::getLoadAddress() const {
139 uint64_t LoadAddress
;
140 bool success
= (S_OK
== Session
->get_loadAddress(&LoadAddress
));
141 return (success
) ? LoadAddress
: 0;
144 bool DIASession::setLoadAddress(uint64_t Address
) {
145 return (S_OK
== Session
->put_loadAddress(Address
));
148 std::unique_ptr
<PDBSymbolExe
> DIASession::getGlobalScope() {
149 CComPtr
<IDiaSymbol
> GlobalScope
;
150 if (S_OK
!= Session
->get_globalScope(&GlobalScope
))
153 auto RawSymbol
= std::make_unique
<DIARawSymbol
>(*this, GlobalScope
);
154 auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol
)));
155 std::unique_ptr
<PDBSymbolExe
> ExeSymbol(
156 static_cast<PDBSymbolExe
*>(PdbSymbol
.release()));
160 bool DIASession::addressForVA(uint64_t VA
, uint32_t &Section
,
161 uint32_t &Offset
) const {
162 DWORD ArgSection
, ArgOffset
= 0;
163 if (S_OK
== Session
->addressForVA(VA
, &ArgSection
, &ArgOffset
)) {
164 Section
= static_cast<uint32_t>(ArgSection
);
165 Offset
= static_cast<uint32_t>(ArgOffset
);
171 bool DIASession::addressForRVA(uint32_t RVA
, uint32_t &Section
,
172 uint32_t &Offset
) const {
173 DWORD ArgSection
, ArgOffset
= 0;
174 if (S_OK
== Session
->addressForRVA(RVA
, &ArgSection
, &ArgOffset
)) {
175 Section
= static_cast<uint32_t>(ArgSection
);
176 Offset
= static_cast<uint32_t>(ArgOffset
);
182 std::unique_ptr
<PDBSymbol
>
183 DIASession::getSymbolById(SymIndexId SymbolId
) const {
184 CComPtr
<IDiaSymbol
> LocatedSymbol
;
185 if (S_OK
!= Session
->symbolById(SymbolId
, &LocatedSymbol
))
188 auto RawSymbol
= std::make_unique
<DIARawSymbol
>(*this, LocatedSymbol
);
189 return PDBSymbol::create(*this, std::move(RawSymbol
));
192 std::unique_ptr
<PDBSymbol
>
193 DIASession::findSymbolByAddress(uint64_t Address
, PDB_SymType Type
) const {
194 enum SymTagEnum EnumVal
= static_cast<enum SymTagEnum
>(Type
);
196 CComPtr
<IDiaSymbol
> Symbol
;
197 if (S_OK
!= Session
->findSymbolByVA(Address
, EnumVal
, &Symbol
)) {
198 ULONGLONG LoadAddr
= 0;
199 if (S_OK
!= Session
->get_loadAddress(&LoadAddr
))
201 DWORD RVA
= static_cast<DWORD
>(Address
- LoadAddr
);
202 if (S_OK
!= Session
->findSymbolByRVA(RVA
, EnumVal
, &Symbol
))
205 auto RawSymbol
= std::make_unique
<DIARawSymbol
>(*this, Symbol
);
206 return PDBSymbol::create(*this, std::move(RawSymbol
));
209 std::unique_ptr
<PDBSymbol
> DIASession::findSymbolByRVA(uint32_t RVA
,
210 PDB_SymType Type
) const {
211 enum SymTagEnum EnumVal
= static_cast<enum SymTagEnum
>(Type
);
213 CComPtr
<IDiaSymbol
> Symbol
;
214 if (S_OK
!= Session
->findSymbolByRVA(RVA
, EnumVal
, &Symbol
))
217 auto RawSymbol
= std::make_unique
<DIARawSymbol
>(*this, Symbol
);
218 return PDBSymbol::create(*this, std::move(RawSymbol
));
221 std::unique_ptr
<PDBSymbol
>
222 DIASession::findSymbolBySectOffset(uint32_t Sect
, uint32_t Offset
,
223 PDB_SymType Type
) const {
224 enum SymTagEnum EnumVal
= static_cast<enum SymTagEnum
>(Type
);
226 CComPtr
<IDiaSymbol
> Symbol
;
227 if (S_OK
!= Session
->findSymbolByAddr(Sect
, Offset
, EnumVal
, &Symbol
))
230 auto RawSymbol
= std::make_unique
<DIARawSymbol
>(*this, Symbol
);
231 return PDBSymbol::create(*this, std::move(RawSymbol
));
234 std::unique_ptr
<IPDBEnumLineNumbers
>
235 DIASession::findLineNumbers(const PDBSymbolCompiland
&Compiland
,
236 const IPDBSourceFile
&File
) const {
237 const DIARawSymbol
&RawCompiland
=
238 static_cast<const DIARawSymbol
&>(Compiland
.getRawSymbol());
239 const DIASourceFile
&RawFile
= static_cast<const DIASourceFile
&>(File
);
241 CComPtr
<IDiaEnumLineNumbers
> LineNumbers
;
242 if (S_OK
!= Session
->findLines(RawCompiland
.getDiaSymbol(),
243 RawFile
.getDiaFile(), &LineNumbers
))
246 return std::make_unique
<DIAEnumLineNumbers
>(LineNumbers
);
249 std::unique_ptr
<IPDBEnumLineNumbers
>
250 DIASession::findLineNumbersByAddress(uint64_t Address
, uint32_t Length
) const {
251 CComPtr
<IDiaEnumLineNumbers
> LineNumbers
;
252 if (S_OK
!= Session
->findLinesByVA(Address
, Length
, &LineNumbers
)) {
253 ULONGLONG LoadAddr
= 0;
254 if (S_OK
!= Session
->get_loadAddress(&LoadAddr
))
256 DWORD RVA
= static_cast<DWORD
>(Address
- LoadAddr
);
257 if (S_OK
!= Session
->findLinesByRVA(RVA
, Length
, &LineNumbers
))
260 return std::make_unique
<DIAEnumLineNumbers
>(LineNumbers
);
263 std::unique_ptr
<IPDBEnumLineNumbers
>
264 DIASession::findLineNumbersByRVA(uint32_t RVA
, uint32_t Length
) const {
265 CComPtr
<IDiaEnumLineNumbers
> LineNumbers
;
266 if (S_OK
!= Session
->findLinesByRVA(RVA
, Length
, &LineNumbers
))
269 return std::make_unique
<DIAEnumLineNumbers
>(LineNumbers
);
272 std::unique_ptr
<IPDBEnumLineNumbers
>
273 DIASession::findLineNumbersBySectOffset(uint32_t Section
, uint32_t Offset
,
274 uint32_t Length
) const {
275 CComPtr
<IDiaEnumLineNumbers
> LineNumbers
;
276 if (S_OK
!= Session
->findLinesByAddr(Section
, Offset
, Length
, &LineNumbers
))
279 return std::make_unique
<DIAEnumLineNumbers
>(LineNumbers
);
282 std::unique_ptr
<IPDBEnumSourceFiles
>
283 DIASession::findSourceFiles(const PDBSymbolCompiland
*Compiland
,
284 llvm::StringRef Pattern
,
285 PDB_NameSearchFlags Flags
) const {
286 IDiaSymbol
*DiaCompiland
= nullptr;
287 CComBSTR Utf16Pattern
;
288 if (!Pattern
.empty())
289 Utf16Pattern
= CComBSTR(Pattern
.data());
292 DiaCompiland
= static_cast<const DIARawSymbol
&>(Compiland
->getRawSymbol())
295 Flags
= static_cast<PDB_NameSearchFlags
>(
296 Flags
| PDB_NameSearchFlags::NS_FileNameExtMatch
);
297 CComPtr
<IDiaEnumSourceFiles
> SourceFiles
;
299 Session
->findFile(DiaCompiland
, Utf16Pattern
.m_str
, Flags
, &SourceFiles
))
301 return std::make_unique
<DIAEnumSourceFiles
>(*this, SourceFiles
);
304 std::unique_ptr
<IPDBSourceFile
>
305 DIASession::findOneSourceFile(const PDBSymbolCompiland
*Compiland
,
306 llvm::StringRef Pattern
,
307 PDB_NameSearchFlags Flags
) const {
308 auto SourceFiles
= findSourceFiles(Compiland
, Pattern
, Flags
);
309 if (!SourceFiles
|| SourceFiles
->getChildCount() == 0)
311 return SourceFiles
->getNext();
314 std::unique_ptr
<IPDBEnumChildren
<PDBSymbolCompiland
>>
315 DIASession::findCompilandsForSourceFile(llvm::StringRef Pattern
,
316 PDB_NameSearchFlags Flags
) const {
317 auto File
= findOneSourceFile(nullptr, Pattern
, Flags
);
320 return File
->getCompilands();
323 std::unique_ptr
<PDBSymbolCompiland
>
324 DIASession::findOneCompilandForSourceFile(llvm::StringRef Pattern
,
325 PDB_NameSearchFlags Flags
) const {
326 auto Compilands
= findCompilandsForSourceFile(Pattern
, Flags
);
327 if (!Compilands
|| Compilands
->getChildCount() == 0)
329 return Compilands
->getNext();
332 std::unique_ptr
<IPDBEnumSourceFiles
> DIASession::getAllSourceFiles() const {
333 CComPtr
<IDiaEnumSourceFiles
> Files
;
334 if (S_OK
!= Session
->findFile(nullptr, nullptr, nsNone
, &Files
))
337 return std::make_unique
<DIAEnumSourceFiles
>(*this, Files
);
340 std::unique_ptr
<IPDBEnumSourceFiles
> DIASession::getSourceFilesForCompiland(
341 const PDBSymbolCompiland
&Compiland
) const {
342 CComPtr
<IDiaEnumSourceFiles
> Files
;
344 const DIARawSymbol
&RawSymbol
=
345 static_cast<const DIARawSymbol
&>(Compiland
.getRawSymbol());
347 Session
->findFile(RawSymbol
.getDiaSymbol(), nullptr, nsNone
, &Files
))
350 return std::make_unique
<DIAEnumSourceFiles
>(*this, Files
);
353 std::unique_ptr
<IPDBSourceFile
>
354 DIASession::getSourceFileById(uint32_t FileId
) const {
355 CComPtr
<IDiaSourceFile
> LocatedFile
;
356 if (S_OK
!= Session
->findFileById(FileId
, &LocatedFile
))
359 return std::make_unique
<DIASourceFile
>(*this, LocatedFile
);
362 std::unique_ptr
<IPDBEnumDataStreams
> DIASession::getDebugStreams() const {
363 CComPtr
<IDiaEnumDebugStreams
> DiaEnumerator
;
364 if (S_OK
!= Session
->getEnumDebugStreams(&DiaEnumerator
))
367 return std::make_unique
<DIAEnumDebugStreams
>(DiaEnumerator
);
370 std::unique_ptr
<IPDBEnumTables
> DIASession::getEnumTables() const {
371 CComPtr
<IDiaEnumTables
> DiaEnumerator
;
372 if (S_OK
!= Session
->getEnumTables(&DiaEnumerator
))
375 return std::make_unique
<DIAEnumTables
>(DiaEnumerator
);
378 template <class T
> static CComPtr
<T
> getTableEnumerator(IDiaSession
&Session
) {
379 CComPtr
<T
> Enumerator
;
380 CComPtr
<IDiaEnumTables
> ET
;
381 CComPtr
<IDiaTable
> Table
;
384 if (Session
.getEnumTables(&ET
) != S_OK
)
387 while (ET
->Next(1, &Table
, &Count
) == S_OK
&& Count
== 1) {
388 // There is only one table that matches the given iid
389 if (S_OK
== Table
->QueryInterface(__uuidof(T
), (void **)&Enumerator
))
395 std::unique_ptr
<IPDBEnumInjectedSources
>
396 DIASession::getInjectedSources() const {
397 CComPtr
<IDiaEnumInjectedSources
> Files
=
398 getTableEnumerator
<IDiaEnumInjectedSources
>(*Session
);
402 return std::make_unique
<DIAEnumInjectedSources
>(Files
);
405 std::unique_ptr
<IPDBEnumSectionContribs
>
406 DIASession::getSectionContribs() const {
407 CComPtr
<IDiaEnumSectionContribs
> Sections
=
408 getTableEnumerator
<IDiaEnumSectionContribs
>(*Session
);
412 return std::make_unique
<DIAEnumSectionContribs
>(*this, Sections
);
415 std::unique_ptr
<IPDBEnumFrameData
>
416 DIASession::getFrameData() const {
417 CComPtr
<IDiaEnumFrameData
> FD
=
418 getTableEnumerator
<IDiaEnumFrameData
>(*Session
);
422 return std::make_unique
<DIAEnumFrameData
>(FD
);