blob: dcf29a56b9d3cafae28fa3e4745c4193b217a2bd [file] [log] [blame]
Zachary Turnercffff262015-02-10 21:17:52 +00001//===- DIASession.cpp - DIA implementation of IPDBSession -------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
Zachary Turner819e77d2016-05-06 20:51:57 +00009#include "llvm/DebugInfo/PDB/DIA/DIASession.h"
Zachary Turnerbe6d1e42015-02-10 23:46:48 +000010#include "llvm/ADT/STLExtras.h"
Zachary Turnercffff262015-02-10 21:17:52 +000011#include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h"
Zachary Turner4b083542015-04-17 22:40:36 +000012#include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h"
Zachary Turnera5549172015-02-10 22:43:25 +000013#include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h"
Aaron Smith89bca9e2017-11-16 14:33:09 +000014#include "llvm/DebugInfo/PDB/DIA/DIAEnumTables.h"
Zachary Turner819e77d2016-05-06 20:51:57 +000015#include "llvm/DebugInfo/PDB/DIA/DIAError.h"
Zachary Turnercffff262015-02-10 21:17:52 +000016#include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h"
Zachary Turnercffff262015-02-10 21:17:52 +000017#include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h"
Zachary Turner819e77d2016-05-06 20:51:57 +000018#include "llvm/DebugInfo/PDB/DIA/DIASupport.h"
19#include "llvm/DebugInfo/PDB/GenericError.h"
20#include "llvm/DebugInfo/PDB/PDB.h"
Chandler Carruth71f308a2015-02-13 09:09:03 +000021#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
22#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
Zachary Turnercffff262015-02-10 21:17:52 +000023#include "llvm/Support/ConvertUTF.h"
Zachary Turner38380322016-10-19 16:42:20 +000024#include "llvm/Support/Format.h"
Zachary Turner16901642017-04-24 17:47:24 +000025#include "llvm/Support/FormatVariadic.h"
Zachary Turner38380322016-10-19 16:42:20 +000026#include "llvm/Support/raw_ostream.h"
Zachary Turnercffff262015-02-10 21:17:52 +000027
28using namespace llvm;
Zachary Turnerec28fc32016-05-04 20:32:13 +000029using namespace llvm::pdb;
Zachary Turnercffff262015-02-10 21:17:52 +000030
Zachary Turner16901642017-04-24 17:47:24 +000031template <typename... Ts>
32static Error ErrorFromHResult(HRESULT Result, const char *Str, Ts &&... Args) {
33 SmallString<64> MessageStorage;
34 StringRef Context;
35 if (sizeof...(Args) > 0) {
36 MessageStorage = formatv(Str, std::forward<Ts>(Args)...).str();
37 Context = MessageStorage;
38 } else
39 Context = Str;
40
Zachary Turner819e77d2016-05-06 20:51:57 +000041 switch (Result) {
42 case E_PDB_NOT_FOUND:
Zachary Turner38380322016-10-19 16:42:20 +000043 return make_error<GenericError>(generic_error_code::invalid_path, Context);
Zachary Turner819e77d2016-05-06 20:51:57 +000044 case E_PDB_FORMAT:
Zachary Turner38380322016-10-19 16:42:20 +000045 return make_error<DIAError>(dia_error_code::invalid_file_format, Context);
Zachary Turner819e77d2016-05-06 20:51:57 +000046 case E_INVALIDARG:
Zachary Turner38380322016-10-19 16:42:20 +000047 return make_error<DIAError>(dia_error_code::invalid_parameter, Context);
Zachary Turner819e77d2016-05-06 20:51:57 +000048 case E_UNEXPECTED:
Zachary Turner38380322016-10-19 16:42:20 +000049 return make_error<DIAError>(dia_error_code::already_loaded, Context);
Zachary Turner819e77d2016-05-06 20:51:57 +000050 case E_PDB_INVALID_SIG:
51 case E_PDB_INVALID_AGE:
Zachary Turner38380322016-10-19 16:42:20 +000052 return make_error<DIAError>(dia_error_code::debug_info_mismatch, Context);
53 default: {
54 std::string S;
55 raw_string_ostream OS(S);
56 OS << "HRESULT: " << format_hex(static_cast<DWORD>(Result), 10, true)
57 << ": " << Context;
58 return make_error<DIAError>(dia_error_code::unspecified, OS.str());
59 }
Zachary Turner819e77d2016-05-06 20:51:57 +000060 }
61}
62
Reid Klecknerfb58be82016-10-12 21:51:14 +000063static Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) {
Nico Weber73853ab2016-04-01 22:21:51 +000064 if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER,
65 IID_IDiaDataSource,
66 reinterpret_cast<LPVOID *>(&DiaDataSource))))
Zachary Turner819e77d2016-05-06 20:51:57 +000067 return Error::success();
Nico Weber73853ab2016-04-01 22:21:51 +000068
Zachary Turner819e77d2016-05-06 20:51:57 +000069// If the CoCreateInstance call above failed, msdia*.dll is not registered.
70// Try loading the DLL corresponding to the #included DIA SDK.
Nico Weber73853ab2016-04-01 22:21:51 +000071#if !defined(_MSC_VER)
Zachary Turner819e77d2016-05-06 20:51:57 +000072 return llvm::make_error<GenericError>(
73 "DIA is only supported when using MSVC.");
Reid Klecknerfb58be82016-10-12 21:51:14 +000074#else
Nico Weber73853ab2016-04-01 22:21:51 +000075 const wchar_t *msdia_dll = nullptr;
Reid Klecknerfb58be82016-10-12 21:51:14 +000076#if _MSC_VER >= 1900 && _MSC_VER < 2000
Nico Weber73853ab2016-04-01 22:21:51 +000077 msdia_dll = L"msdia140.dll"; // VS2015
Reid Klecknerfb58be82016-10-12 21:51:14 +000078#elif _MSC_VER >= 1800
Nico Weber73853ab2016-04-01 22:21:51 +000079 msdia_dll = L"msdia120.dll"; // VS2013
80#else
81#error "Unknown Visual Studio version."
82#endif
Zachary Turner23ee87b2016-04-19 17:36:58 +000083
Zachary Turner819e77d2016-05-06 20:51:57 +000084 HRESULT HR;
85 if (FAILED(HR = NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource,
86 reinterpret_cast<LPVOID *>(&DiaDataSource))))
Zachary Turner38380322016-10-19 16:42:20 +000087 return ErrorFromHResult(HR, "Calling NoRegCoCreate");
Zachary Turner819e77d2016-05-06 20:51:57 +000088 return Error::success();
Reid Klecknerfb58be82016-10-12 21:51:14 +000089#endif
Nico Weber73853ab2016-04-01 22:21:51 +000090}
Zachary Turnercffff262015-02-10 21:17:52 +000091
92DIASession::DIASession(CComPtr<IDiaSession> DiaSession) : Session(DiaSession) {}
93
Zachary Turner819e77d2016-05-06 20:51:57 +000094Error DIASession::createFromPdb(StringRef Path,
95 std::unique_ptr<IPDBSession> &Session) {
Zachary Turnerccf04152015-02-28 20:23:18 +000096 CComPtr<IDiaDataSource> DiaDataSource;
97 CComPtr<IDiaSession> DiaSession;
Zachary Turnercffff262015-02-10 21:17:52 +000098
99 // We assume that CoInitializeEx has already been called by the executable.
Zachary Turner819e77d2016-05-06 20:51:57 +0000100 if (auto E = LoadDIA(DiaDataSource))
101 return E;
Zachary Turnercffff262015-02-10 21:17:52 +0000102
103 llvm::SmallVector<UTF16, 128> Path16;
104 if (!llvm::convertUTF8ToUTF16String(Path, Path16))
Zachary Turner819e77d2016-05-06 20:51:57 +0000105 return make_error<GenericError>(generic_error_code::invalid_path);
Zachary Turnercffff262015-02-10 21:17:52 +0000106
107 const wchar_t *Path16Str = reinterpret_cast<const wchar_t*>(Path16.data());
Zachary Turner819e77d2016-05-06 20:51:57 +0000108 HRESULT HR;
Zachary Turner16901642017-04-24 17:47:24 +0000109 if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str))) {
110 return ErrorFromHResult(HR, "Calling loadDataFromPdb {0}", Path);
111 }
Zachary Turnercffff262015-02-10 21:17:52 +0000112
Zachary Turner819e77d2016-05-06 20:51:57 +0000113 if (FAILED(HR = DiaDataSource->openSession(&DiaSession)))
Zachary Turner38380322016-10-19 16:42:20 +0000114 return ErrorFromHResult(HR, "Calling openSession");
Zachary Turnerccf04152015-02-28 20:23:18 +0000115
116 Session.reset(new DIASession(DiaSession));
Zachary Turner819e77d2016-05-06 20:51:57 +0000117 return Error::success();
Zachary Turnercffff262015-02-10 21:17:52 +0000118}
119
Zachary Turner819e77d2016-05-06 20:51:57 +0000120Error DIASession::createFromExe(StringRef Path,
121 std::unique_ptr<IPDBSession> &Session) {
Zachary Turner4b083542015-04-17 22:40:36 +0000122 CComPtr<IDiaDataSource> DiaDataSource;
123 CComPtr<IDiaSession> DiaSession;
124
125 // We assume that CoInitializeEx has already been called by the executable.
Zachary Turner819e77d2016-05-06 20:51:57 +0000126 if (auto EC = LoadDIA(DiaDataSource))
127 return EC;
Zachary Turner4b083542015-04-17 22:40:36 +0000128
129 llvm::SmallVector<UTF16, 128> Path16;
130 if (!llvm::convertUTF8ToUTF16String(Path, Path16))
Zachary Turner819e77d2016-05-06 20:51:57 +0000131 return make_error<GenericError>(generic_error_code::invalid_path, Path);
Zachary Turner4b083542015-04-17 22:40:36 +0000132
133 const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data());
Zachary Turner819e77d2016-05-06 20:51:57 +0000134 HRESULT HR;
135 if (FAILED(HR = DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr)))
Zachary Turner38380322016-10-19 16:42:20 +0000136 return ErrorFromHResult(HR, "Calling loadDataForExe");
Zachary Turner4b083542015-04-17 22:40:36 +0000137
Zachary Turner819e77d2016-05-06 20:51:57 +0000138 if (FAILED(HR = DiaDataSource->openSession(&DiaSession)))
Zachary Turner38380322016-10-19 16:42:20 +0000139 return ErrorFromHResult(HR, "Calling openSession");
Zachary Turner4b083542015-04-17 22:40:36 +0000140
141 Session.reset(new DIASession(DiaSession));
Zachary Turner819e77d2016-05-06 20:51:57 +0000142 return Error::success();
Zachary Turner4b083542015-04-17 22:40:36 +0000143}
144
Zachary Turnercffff262015-02-10 21:17:52 +0000145uint64_t DIASession::getLoadAddress() const {
146 uint64_t LoadAddress;
147 bool success = (S_OK == Session->get_loadAddress(&LoadAddress));
148 return (success) ? LoadAddress : 0;
149}
150
Aaron Smith89a19ac2018-02-23 00:02:27 +0000151bool DIASession::setLoadAddress(uint64_t Address) {
152 return (S_OK == Session->put_loadAddress(Address));
Zachary Turnercffff262015-02-10 21:17:52 +0000153}
154
Adrian McCarthy6a4b0802017-06-22 18:42:23 +0000155std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() {
Zachary Turnercffff262015-02-10 21:17:52 +0000156 CComPtr<IDiaSymbol> GlobalScope;
157 if (S_OK != Session->get_globalScope(&GlobalScope))
158 return nullptr;
159
Zachary Turnerbe6d1e42015-02-10 23:46:48 +0000160 auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, GlobalScope);
Zachary Turnercffff262015-02-10 21:17:52 +0000161 auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol)));
162 std::unique_ptr<PDBSymbolExe> ExeSymbol(
163 static_cast<PDBSymbolExe *>(PdbSymbol.release()));
164 return ExeSymbol;
165}
166
167std::unique_ptr<PDBSymbol> DIASession::getSymbolById(uint32_t SymbolId) const {
168 CComPtr<IDiaSymbol> LocatedSymbol;
169 if (S_OK != Session->symbolById(SymbolId, &LocatedSymbol))
170 return nullptr;
171
Zachary Turnerbe6d1e42015-02-10 23:46:48 +0000172 auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, LocatedSymbol);
Zachary Turnercffff262015-02-10 21:17:52 +0000173 return PDBSymbol::create(*this, std::move(RawSymbol));
174}
175
Zachary Turner4b083542015-04-17 22:40:36 +0000176std::unique_ptr<PDBSymbol>
Zachary Turnere5cb2692015-05-01 20:24:26 +0000177DIASession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const {
178 enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type);
179
Zachary Turner4b083542015-04-17 22:40:36 +0000180 CComPtr<IDiaSymbol> Symbol;
Zachary Turnere5cb2692015-05-01 20:24:26 +0000181 if (S_OK != Session->findSymbolByVA(Address, EnumVal, &Symbol)) {
182 ULONGLONG LoadAddr = 0;
183 if (S_OK != Session->get_loadAddress(&LoadAddr))
184 return nullptr;
185 DWORD RVA = static_cast<DWORD>(Address - LoadAddr);
186 if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol))
187 return nullptr;
188 }
Zachary Turner4b083542015-04-17 22:40:36 +0000189 auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, Symbol);
190 return PDBSymbol::create(*this, std::move(RawSymbol));
191}
192
193std::unique_ptr<IPDBEnumLineNumbers>
Zachary Turner43ec3af2016-02-18 18:47:29 +0000194DIASession::findLineNumbers(const PDBSymbolCompiland &Compiland,
195 const IPDBSourceFile &File) const {
196 const DIARawSymbol &RawCompiland =
197 static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());
198 const DIASourceFile &RawFile = static_cast<const DIASourceFile &>(File);
199
200 CComPtr<IDiaEnumLineNumbers> LineNumbers;
201 if (S_OK !=
202 Session->findLines(RawCompiland.getDiaSymbol(), RawFile.getDiaFile(),
203 &LineNumbers))
204 return nullptr;
205
206 return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers);
207}
208
209std::unique_ptr<IPDBEnumLineNumbers>
Zachary Turner4b083542015-04-17 22:40:36 +0000210DIASession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const {
211 CComPtr<IDiaEnumLineNumbers> LineNumbers;
212 if (S_OK != Session->findLinesByVA(Address, Length, &LineNumbers))
213 return nullptr;
214
215 return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers);
216}
217
Zachary Turner43ec3af2016-02-18 18:47:29 +0000218std::unique_ptr<IPDBEnumSourceFiles>
219DIASession::findSourceFiles(const PDBSymbolCompiland *Compiland,
220 llvm::StringRef Pattern,
221 PDB_NameSearchFlags Flags) const {
222 IDiaSymbol *DiaCompiland = nullptr;
223 CComBSTR Utf16Pattern;
224 if (!Pattern.empty())
225 Utf16Pattern = CComBSTR(Pattern.data());
226
227 if (Compiland)
228 DiaCompiland = static_cast<const DIARawSymbol &>(Compiland->getRawSymbol())
229 .getDiaSymbol();
230
231 Flags = static_cast<PDB_NameSearchFlags>(
232 Flags | PDB_NameSearchFlags::NS_FileNameExtMatch);
233 CComPtr<IDiaEnumSourceFiles> SourceFiles;
234 if (S_OK !=
235 Session->findFile(DiaCompiland, Utf16Pattern.m_str, Flags, &SourceFiles))
236 return nullptr;
237 return llvm::make_unique<DIAEnumSourceFiles>(*this, SourceFiles);
238}
239
240std::unique_ptr<IPDBSourceFile>
241DIASession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
242 llvm::StringRef Pattern,
243 PDB_NameSearchFlags Flags) const {
244 auto SourceFiles = findSourceFiles(Compiland, Pattern, Flags);
245 if (!SourceFiles || SourceFiles->getChildCount() == 0)
246 return nullptr;
247 return SourceFiles->getNext();
248}
249
250std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
251DIASession::findCompilandsForSourceFile(llvm::StringRef Pattern,
252 PDB_NameSearchFlags Flags) const {
253 auto File = findOneSourceFile(nullptr, Pattern, Flags);
254 if (!File)
255 return nullptr;
256 return File->getCompilands();
257}
258
259std::unique_ptr<PDBSymbolCompiland>
260DIASession::findOneCompilandForSourceFile(llvm::StringRef Pattern,
261 PDB_NameSearchFlags Flags) const {
262 auto Compilands = findCompilandsForSourceFile(Pattern, Flags);
263 if (!Compilands || Compilands->getChildCount() == 0)
264 return nullptr;
265 return Compilands->getNext();
266}
267
Zachary Turnera5549172015-02-10 22:43:25 +0000268std::unique_ptr<IPDBEnumSourceFiles> DIASession::getAllSourceFiles() const {
269 CComPtr<IDiaEnumSourceFiles> Files;
270 if (S_OK != Session->findFile(nullptr, nullptr, nsNone, &Files))
271 return nullptr;
272
Zachary Turnerbe6d1e42015-02-10 23:46:48 +0000273 return llvm::make_unique<DIAEnumSourceFiles>(*this, Files);
Zachary Turnera5549172015-02-10 22:43:25 +0000274}
275
276std::unique_ptr<IPDBEnumSourceFiles> DIASession::getSourceFilesForCompiland(
277 const PDBSymbolCompiland &Compiland) const {
278 CComPtr<IDiaEnumSourceFiles> Files;
279
280 const DIARawSymbol &RawSymbol =
281 static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());
282 if (S_OK !=
283 Session->findFile(RawSymbol.getDiaSymbol(), nullptr, nsNone, &Files))
284 return nullptr;
285
Zachary Turnerbe6d1e42015-02-10 23:46:48 +0000286 return llvm::make_unique<DIAEnumSourceFiles>(*this, Files);
Zachary Turnera5549172015-02-10 22:43:25 +0000287}
288
Zachary Turnercffff262015-02-10 21:17:52 +0000289std::unique_ptr<IPDBSourceFile>
290DIASession::getSourceFileById(uint32_t FileId) const {
291 CComPtr<IDiaSourceFile> LocatedFile;
292 if (S_OK != Session->findFileById(FileId, &LocatedFile))
293 return nullptr;
294
Zachary Turnerbe6d1e42015-02-10 23:46:48 +0000295 return llvm::make_unique<DIASourceFile>(*this, LocatedFile);
Zachary Turnercffff262015-02-10 21:17:52 +0000296}
297
298std::unique_ptr<IPDBEnumDataStreams> DIASession::getDebugStreams() const {
299 CComPtr<IDiaEnumDebugStreams> DiaEnumerator;
300 if (S_OK != Session->getEnumDebugStreams(&DiaEnumerator))
301 return nullptr;
302
Zachary Turnerbe6d1e42015-02-10 23:46:48 +0000303 return llvm::make_unique<DIAEnumDebugStreams>(DiaEnumerator);
Zachary Turnercffff262015-02-10 21:17:52 +0000304}
Aaron Smith89bca9e2017-11-16 14:33:09 +0000305
306std::unique_ptr<IPDBEnumTables> DIASession::getEnumTables() const {
307 CComPtr<IDiaEnumTables> DiaEnumerator;
308 if (S_OK != Session->getEnumTables(&DiaEnumerator))
309 return nullptr;
310
311 return llvm::make_unique<DIAEnumTables>(DiaEnumerator);
312}