Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp
35294 views
1
//===- DIASession.cpp - DIA implementation of IPDBSession -------*- C++ -*-===//
2
//
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
6
//
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"
29
30
using namespace llvm;
31
using namespace llvm::pdb;
32
33
template <typename... Ts>
34
static Error ErrorFromHResult(HRESULT Result, const char *Str, Ts &&... Args) {
35
SmallString<64> MessageStorage;
36
StringRef Context;
37
if (sizeof...(Args) > 0) {
38
MessageStorage = formatv(Str, std::forward<Ts>(Args)...).str();
39
Context = MessageStorage;
40
} else
41
Context = Str;
42
43
switch (Result) {
44
case E_PDB_NOT_FOUND:
45
return errorCodeToError(std::error_code(ENOENT, std::generic_category()));
46
case E_PDB_FORMAT:
47
return make_error<DIAError>(dia_error_code::invalid_file_format, Context);
48
case E_INVALIDARG:
49
return make_error<DIAError>(dia_error_code::invalid_parameter, Context);
50
case E_UNEXPECTED:
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);
55
default: {
56
std::string S;
57
raw_string_ostream OS(S);
58
OS << "HRESULT: " << format_hex(static_cast<DWORD>(Result), 10, true)
59
<< ": " << Context;
60
return make_error<DIAError>(dia_error_code::unspecified, OS.str());
61
}
62
}
63
}
64
65
static Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) {
66
if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER,
67
IID_IDiaDataSource,
68
reinterpret_cast<LPVOID *>(&DiaDataSource))))
69
return Error::success();
70
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);
75
#else
76
const wchar_t *msdia_dll = L"msdia140.dll";
77
HRESULT HR;
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();
82
#endif
83
}
84
85
DIASession::DIASession(CComPtr<IDiaSession> DiaSession) : Session(DiaSession) {}
86
87
Error DIASession::createFromPdb(StringRef Path,
88
std::unique_ptr<IPDBSession> &Session) {
89
CComPtr<IDiaDataSource> DiaDataSource;
90
CComPtr<IDiaSession> DiaSession;
91
92
// We assume that CoInitializeEx has already been called by the executable.
93
if (auto E = LoadDIA(DiaDataSource))
94
return E;
95
96
llvm::SmallVector<UTF16, 128> Path16;
97
if (!llvm::convertUTF8ToUTF16String(Path, Path16))
98
return make_error<PDBError>(pdb_error_code::invalid_utf8_path, Path);
99
100
const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data());
101
HRESULT HR;
102
if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str))) {
103
return ErrorFromHResult(HR, "Calling loadDataFromPdb {0}", Path);
104
}
105
106
if (FAILED(HR = DiaDataSource->openSession(&DiaSession)))
107
return ErrorFromHResult(HR, "Calling openSession");
108
109
Session.reset(new DIASession(DiaSession));
110
return Error::success();
111
}
112
113
Error DIASession::createFromExe(StringRef Path,
114
std::unique_ptr<IPDBSession> &Session) {
115
CComPtr<IDiaDataSource> DiaDataSource;
116
CComPtr<IDiaSession> DiaSession;
117
118
// We assume that CoInitializeEx has already been called by the executable.
119
if (auto EC = LoadDIA(DiaDataSource))
120
return EC;
121
122
llvm::SmallVector<UTF16, 128> Path16;
123
if (!llvm::convertUTF8ToUTF16String(Path, Path16))
124
return make_error<PDBError>(pdb_error_code::invalid_utf8_path, Path);
125
126
const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data());
127
HRESULT HR;
128
if (FAILED(HR = DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr)))
129
return ErrorFromHResult(HR, "Calling loadDataForExe");
130
131
if (FAILED(HR = DiaDataSource->openSession(&DiaSession)))
132
return ErrorFromHResult(HR, "Calling openSession");
133
134
Session.reset(new DIASession(DiaSession));
135
return Error::success();
136
}
137
138
uint64_t DIASession::getLoadAddress() const {
139
uint64_t LoadAddress;
140
bool success = (S_OK == Session->get_loadAddress(&LoadAddress));
141
return (success) ? LoadAddress : 0;
142
}
143
144
bool DIASession::setLoadAddress(uint64_t Address) {
145
return (S_OK == Session->put_loadAddress(Address));
146
}
147
148
std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() {
149
CComPtr<IDiaSymbol> GlobalScope;
150
if (S_OK != Session->get_globalScope(&GlobalScope))
151
return nullptr;
152
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()));
157
return ExeSymbol;
158
}
159
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);
166
return true;
167
}
168
return false;
169
}
170
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);
177
return true;
178
}
179
return false;
180
}
181
182
std::unique_ptr<PDBSymbol>
183
DIASession::getSymbolById(SymIndexId SymbolId) const {
184
CComPtr<IDiaSymbol> LocatedSymbol;
185
if (S_OK != Session->symbolById(SymbolId, &LocatedSymbol))
186
return nullptr;
187
188
auto RawSymbol = std::make_unique<DIARawSymbol>(*this, LocatedSymbol);
189
return PDBSymbol::create(*this, std::move(RawSymbol));
190
}
191
192
std::unique_ptr<PDBSymbol> DIASession::findSymbolByAddress(uint64_t Address,
193
PDB_SymType Type) {
194
enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type);
195
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))
200
return nullptr;
201
DWORD RVA = static_cast<DWORD>(Address - LoadAddr);
202
if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol))
203
return nullptr;
204
}
205
auto RawSymbol = std::make_unique<DIARawSymbol>(*this, Symbol);
206
return PDBSymbol::create(*this, std::move(RawSymbol));
207
}
208
209
std::unique_ptr<PDBSymbol> DIASession::findSymbolByRVA(uint32_t RVA,
210
PDB_SymType Type) {
211
enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type);
212
213
CComPtr<IDiaSymbol> Symbol;
214
if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol))
215
return nullptr;
216
217
auto RawSymbol = std::make_unique<DIARawSymbol>(*this, Symbol);
218
return PDBSymbol::create(*this, std::move(RawSymbol));
219
}
220
221
std::unique_ptr<PDBSymbol>
222
DIASession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,
223
PDB_SymType Type) {
224
enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type);
225
226
CComPtr<IDiaSymbol> Symbol;
227
if (S_OK != Session->findSymbolByAddr(Sect, Offset, EnumVal, &Symbol))
228
return nullptr;
229
230
auto RawSymbol = std::make_unique<DIARawSymbol>(*this, Symbol);
231
return PDBSymbol::create(*this, std::move(RawSymbol));
232
}
233
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);
240
241
CComPtr<IDiaEnumLineNumbers> LineNumbers;
242
if (S_OK != Session->findLines(RawCompiland.getDiaSymbol(),
243
RawFile.getDiaFile(), &LineNumbers))
244
return nullptr;
245
246
return std::make_unique<DIAEnumLineNumbers>(LineNumbers);
247
}
248
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))
255
return nullptr;
256
DWORD RVA = static_cast<DWORD>(Address - LoadAddr);
257
if (S_OK != Session->findLinesByRVA(RVA, Length, &LineNumbers))
258
return nullptr;
259
}
260
return std::make_unique<DIAEnumLineNumbers>(LineNumbers);
261
}
262
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))
267
return nullptr;
268
269
return std::make_unique<DIAEnumLineNumbers>(LineNumbers);
270
}
271
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))
277
return nullptr;
278
279
return std::make_unique<DIAEnumLineNumbers>(LineNumbers);
280
}
281
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());
290
291
if (Compiland)
292
DiaCompiland = static_cast<const DIARawSymbol &>(Compiland->getRawSymbol())
293
.getDiaSymbol();
294
295
Flags = static_cast<PDB_NameSearchFlags>(
296
Flags | PDB_NameSearchFlags::NS_FileNameExtMatch);
297
CComPtr<IDiaEnumSourceFiles> SourceFiles;
298
if (S_OK !=
299
Session->findFile(DiaCompiland, Utf16Pattern.m_str, Flags, &SourceFiles))
300
return nullptr;
301
return std::make_unique<DIAEnumSourceFiles>(*this, SourceFiles);
302
}
303
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)
310
return nullptr;
311
return SourceFiles->getNext();
312
}
313
314
std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
315
DIASession::findCompilandsForSourceFile(llvm::StringRef Pattern,
316
PDB_NameSearchFlags Flags) const {
317
auto File = findOneSourceFile(nullptr, Pattern, Flags);
318
if (!File)
319
return nullptr;
320
return File->getCompilands();
321
}
322
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)
328
return nullptr;
329
return Compilands->getNext();
330
}
331
332
std::unique_ptr<IPDBEnumSourceFiles> DIASession::getAllSourceFiles() const {
333
CComPtr<IDiaEnumSourceFiles> Files;
334
if (S_OK != Session->findFile(nullptr, nullptr, nsNone, &Files))
335
return nullptr;
336
337
return std::make_unique<DIAEnumSourceFiles>(*this, Files);
338
}
339
340
std::unique_ptr<IPDBEnumSourceFiles> DIASession::getSourceFilesForCompiland(
341
const PDBSymbolCompiland &Compiland) const {
342
CComPtr<IDiaEnumSourceFiles> Files;
343
344
const DIARawSymbol &RawSymbol =
345
static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());
346
if (S_OK !=
347
Session->findFile(RawSymbol.getDiaSymbol(), nullptr, nsNone, &Files))
348
return nullptr;
349
350
return std::make_unique<DIAEnumSourceFiles>(*this, Files);
351
}
352
353
std::unique_ptr<IPDBSourceFile>
354
DIASession::getSourceFileById(uint32_t FileId) const {
355
CComPtr<IDiaSourceFile> LocatedFile;
356
if (S_OK != Session->findFileById(FileId, &LocatedFile))
357
return nullptr;
358
359
return std::make_unique<DIASourceFile>(*this, LocatedFile);
360
}
361
362
std::unique_ptr<IPDBEnumDataStreams> DIASession::getDebugStreams() const {
363
CComPtr<IDiaEnumDebugStreams> DiaEnumerator;
364
if (S_OK != Session->getEnumDebugStreams(&DiaEnumerator))
365
return nullptr;
366
367
return std::make_unique<DIAEnumDebugStreams>(DiaEnumerator);
368
}
369
370
std::unique_ptr<IPDBEnumTables> DIASession::getEnumTables() const {
371
CComPtr<IDiaEnumTables> DiaEnumerator;
372
if (S_OK != Session->getEnumTables(&DiaEnumerator))
373
return nullptr;
374
375
return std::make_unique<DIAEnumTables>(DiaEnumerator);
376
}
377
378
template <class T> static CComPtr<T> getTableEnumerator(IDiaSession &Session) {
379
CComPtr<T> Enumerator;
380
CComPtr<IDiaEnumTables> ET;
381
CComPtr<IDiaTable> Table;
382
ULONG Count = 0;
383
384
if (Session.getEnumTables(&ET) != S_OK)
385
return nullptr;
386
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))
390
break;
391
Table.Release();
392
}
393
return Enumerator;
394
}
395
std::unique_ptr<IPDBEnumInjectedSources>
396
DIASession::getInjectedSources() const {
397
CComPtr<IDiaEnumInjectedSources> Files =
398
getTableEnumerator<IDiaEnumInjectedSources>(*Session);
399
if (!Files)
400
return nullptr;
401
402
return std::make_unique<DIAEnumInjectedSources>(Files);
403
}
404
405
std::unique_ptr<IPDBEnumSectionContribs>
406
DIASession::getSectionContribs() const {
407
CComPtr<IDiaEnumSectionContribs> Sections =
408
getTableEnumerator<IDiaEnumSectionContribs>(*Session);
409
if (!Sections)
410
return nullptr;
411
412
return std::make_unique<DIAEnumSectionContribs>(*this, Sections);
413
}
414
415
std::unique_ptr<IPDBEnumFrameData>
416
DIASession::getFrameData() const {
417
CComPtr<IDiaEnumFrameData> FD =
418
getTableEnumerator<IDiaEnumFrameData>(*Session);
419
if (!FD)
420
return nullptr;
421
422
return std::make_unique<DIAEnumFrameData>(FD);
423
}
424
425