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(EC: std::error_code(ENOENT, std::generic_category())); |
46 | case E_PDB_FORMAT: |
47 | return make_error<DIAError>(Args: dia_error_code::invalid_file_format, Args&: Context); |
48 | case E_INVALIDARG: |
49 | return make_error<DIAError>(Args: dia_error_code::invalid_parameter, Args&: Context); |
50 | case E_UNEXPECTED: |
51 | return make_error<DIAError>(Args: dia_error_code::already_loaded, Args&: Context); |
52 | case E_PDB_INVALID_SIG: |
53 | case E_PDB_INVALID_AGE: |
54 | return make_error<DIAError>(Args: dia_error_code::debug_info_mismatch, Args&: 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>(Args: dia_error_code::unspecified, Args&: 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>(Args: 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(SrcUTF8: Path, DstUTF16&: Path16)) |
98 | return make_error<PDBError>(Args: pdb_error_code::invalid_utf8_path, Args&: 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(SrcUTF8: Path, DstUTF16&: Path16)) |
124 | return make_error<PDBError>(Args: pdb_error_code::invalid_utf8_path, Args&: 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(Compiland: 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 |
Definitions
- ErrorFromHResult
- LoadDIA
- createFromPdb
- createFromExe
- getLoadAddress
- setLoadAddress
- getGlobalScope
- addressForVA
- addressForRVA
- getSymbolById
- findSymbolByAddress
- findSymbolByRVA
- findSymbolBySectOffset
- findLineNumbers
- findLineNumbersByAddress
- findLineNumbersByRVA
- findLineNumbersBySectOffset
- findSourceFiles
- findOneSourceFile
- findCompilandsForSourceFile
- findOneCompilandForSourceFile
- getAllSourceFiles
- getSourceFilesForCompiland
- getSourceFileById
- getDebugStreams
- getEnumTables
- getTableEnumerator
- getInjectedSources
- getSectionContribs
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more