1307f5ae8SZachary Turner //===-- SymbolFileNativePDB.cpp ---------------------------------*- C++ -*-===//
2307f5ae8SZachary Turner //
3307f5ae8SZachary Turner //                     The LLVM Compiler Infrastructure
4307f5ae8SZachary Turner //
5307f5ae8SZachary Turner // This file is distributed under the University of Illinois Open Source
6307f5ae8SZachary Turner // License. See LICENSE.TXT for details.
7307f5ae8SZachary Turner //
8307f5ae8SZachary Turner //===----------------------------------------------------------------------===//
9307f5ae8SZachary Turner 
10307f5ae8SZachary Turner #include "SymbolFileNativePDB.h"
11307f5ae8SZachary Turner 
12307f5ae8SZachary Turner #include "clang/Lex/Lexer.h"
13307f5ae8SZachary Turner 
14307f5ae8SZachary Turner #include "lldb/Core/Module.h"
15307f5ae8SZachary Turner #include "lldb/Core/PluginManager.h"
16307f5ae8SZachary Turner #include "lldb/Symbol/CompileUnit.h"
17307f5ae8SZachary Turner #include "lldb/Symbol/LineTable.h"
18307f5ae8SZachary Turner #include "lldb/Symbol/ObjectFile.h"
19307f5ae8SZachary Turner #include "lldb/Symbol/SymbolContext.h"
20307f5ae8SZachary Turner #include "lldb/Symbol/SymbolVendor.h"
21307f5ae8SZachary Turner 
22307f5ae8SZachary Turner #include "llvm/DebugInfo/CodeView/CVRecord.h"
23307f5ae8SZachary Turner #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
24307f5ae8SZachary Turner #include "llvm/DebugInfo/CodeView/RecordName.h"
25307f5ae8SZachary Turner #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
26307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
27307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
28307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
29307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
30307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
31307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
32307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/PDBTypes.h"
33307f5ae8SZachary Turner #include "llvm/Object/COFF.h"
34307f5ae8SZachary Turner #include "llvm/Support/Allocator.h"
35307f5ae8SZachary Turner #include "llvm/Support/BinaryStreamReader.h"
36307f5ae8SZachary Turner #include "llvm/Support/ErrorOr.h"
37307f5ae8SZachary Turner #include "llvm/Support/MemoryBuffer.h"
38307f5ae8SZachary Turner 
39307f5ae8SZachary Turner #include "PdbSymUid.h"
40307f5ae8SZachary Turner #include "PdbUtil.h"
41307f5ae8SZachary Turner 
42307f5ae8SZachary Turner using namespace lldb;
43307f5ae8SZachary Turner using namespace lldb_private;
44307f5ae8SZachary Turner using namespace lldb_private::npdb;
45307f5ae8SZachary Turner using namespace llvm::codeview;
46307f5ae8SZachary Turner using namespace llvm::pdb;
47307f5ae8SZachary Turner 
48307f5ae8SZachary Turner static lldb::LanguageType TranslateLanguage(PDB_Lang lang) {
49307f5ae8SZachary Turner   switch (lang) {
50307f5ae8SZachary Turner   case PDB_Lang::Cpp:
51307f5ae8SZachary Turner     return lldb::LanguageType::eLanguageTypeC_plus_plus;
52307f5ae8SZachary Turner   case PDB_Lang::C:
53307f5ae8SZachary Turner     return lldb::LanguageType::eLanguageTypeC;
54307f5ae8SZachary Turner   default:
55307f5ae8SZachary Turner     return lldb::LanguageType::eLanguageTypeUnknown;
56307f5ae8SZachary Turner   }
57307f5ae8SZachary Turner }
58307f5ae8SZachary Turner 
59307f5ae8SZachary Turner static std::unique_ptr<PDBFile> loadPDBFile(std::string PdbPath,
60307f5ae8SZachary Turner                                             llvm::BumpPtrAllocator &Allocator) {
61307f5ae8SZachary Turner   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer =
62307f5ae8SZachary Turner       llvm::MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1,
63307f5ae8SZachary Turner                                   /*RequiresNullTerminator=*/false);
64307f5ae8SZachary Turner   if (!ErrorOrBuffer)
65307f5ae8SZachary Turner     return nullptr;
66307f5ae8SZachary Turner   std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
67307f5ae8SZachary Turner 
68307f5ae8SZachary Turner   llvm::StringRef Path = Buffer->getBufferIdentifier();
69307f5ae8SZachary Turner   auto Stream = llvm::make_unique<llvm::MemoryBufferByteStream>(
70307f5ae8SZachary Turner       std::move(Buffer), llvm::support::little);
71307f5ae8SZachary Turner 
72307f5ae8SZachary Turner   auto File = llvm::make_unique<PDBFile>(Path, std::move(Stream), Allocator);
73*8040eea9SZachary Turner   if (auto EC = File->parseFileHeaders()) {
74*8040eea9SZachary Turner     llvm::consumeError(std::move(EC));
75307f5ae8SZachary Turner     return nullptr;
76*8040eea9SZachary Turner   }
77*8040eea9SZachary Turner   if (auto EC = File->parseStreamData()) {
78*8040eea9SZachary Turner     llvm::consumeError(std::move(EC));
79307f5ae8SZachary Turner     return nullptr;
80*8040eea9SZachary Turner   }
81307f5ae8SZachary Turner 
82307f5ae8SZachary Turner   return File;
83307f5ae8SZachary Turner }
84307f5ae8SZachary Turner 
85307f5ae8SZachary Turner static std::unique_ptr<PDBFile>
86307f5ae8SZachary Turner loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
87307f5ae8SZachary Turner   // Try to find a matching PDB for an EXE.
88307f5ae8SZachary Turner   using namespace llvm::object;
89307f5ae8SZachary Turner   auto expected_binary = createBinary(exe_path);
90307f5ae8SZachary Turner 
91307f5ae8SZachary Turner   // If the file isn't a PE/COFF executable, fail.
92307f5ae8SZachary Turner   if (!expected_binary) {
93307f5ae8SZachary Turner     llvm::consumeError(expected_binary.takeError());
94307f5ae8SZachary Turner     return nullptr;
95307f5ae8SZachary Turner   }
96307f5ae8SZachary Turner   OwningBinary<Binary> binary = std::move(*expected_binary);
97307f5ae8SZachary Turner 
98307f5ae8SZachary Turner   auto *obj = llvm::dyn_cast<llvm::object::COFFObjectFile>(binary.getBinary());
99307f5ae8SZachary Turner   if (!obj)
100307f5ae8SZachary Turner     return nullptr;
101307f5ae8SZachary Turner   const llvm::codeview::DebugInfo *pdb_info = nullptr;
102307f5ae8SZachary Turner 
103307f5ae8SZachary Turner   // If it doesn't have a debug directory, fail.
104307f5ae8SZachary Turner   llvm::StringRef pdb_file;
105307f5ae8SZachary Turner   auto ec = obj->getDebugPDBInfo(pdb_info, pdb_file);
106307f5ae8SZachary Turner   if (ec)
107307f5ae8SZachary Turner     return nullptr;
108307f5ae8SZachary Turner 
109307f5ae8SZachary Turner   // if the file doesn't exist, is not a pdb, or doesn't have a matching guid,
110307f5ae8SZachary Turner   // fail.
111307f5ae8SZachary Turner   llvm::file_magic magic;
112307f5ae8SZachary Turner   ec = llvm::identify_magic(pdb_file, magic);
113307f5ae8SZachary Turner   if (ec || magic != llvm::file_magic::pdb)
114307f5ae8SZachary Turner     return nullptr;
115307f5ae8SZachary Turner   std::unique_ptr<PDBFile> pdb = loadPDBFile(pdb_file, allocator);
116*8040eea9SZachary Turner   if (!pdb)
117*8040eea9SZachary Turner     return nullptr;
118*8040eea9SZachary Turner 
119307f5ae8SZachary Turner   auto expected_info = pdb->getPDBInfoStream();
120307f5ae8SZachary Turner   if (!expected_info) {
121307f5ae8SZachary Turner     llvm::consumeError(expected_info.takeError());
122307f5ae8SZachary Turner     return nullptr;
123307f5ae8SZachary Turner   }
124307f5ae8SZachary Turner   llvm::codeview::GUID guid;
125307f5ae8SZachary Turner   memcpy(&guid, pdb_info->PDB70.Signature, 16);
126307f5ae8SZachary Turner 
127307f5ae8SZachary Turner   if (expected_info->getGuid() != guid)
128307f5ae8SZachary Turner     return nullptr;
129307f5ae8SZachary Turner   return pdb;
130307f5ae8SZachary Turner }
131307f5ae8SZachary Turner 
132307f5ae8SZachary Turner static bool IsFunctionPrologue(const CompilandIndexItem &cci,
133307f5ae8SZachary Turner                                lldb::addr_t addr) {
134307f5ae8SZachary Turner   // FIXME: Implement this.
135307f5ae8SZachary Turner   return false;
136307f5ae8SZachary Turner }
137307f5ae8SZachary Turner 
138307f5ae8SZachary Turner static bool IsFunctionEpilogue(const CompilandIndexItem &cci,
139307f5ae8SZachary Turner                                lldb::addr_t addr) {
140307f5ae8SZachary Turner   // FIXME: Implement this.
141307f5ae8SZachary Turner   return false;
142307f5ae8SZachary Turner }
143307f5ae8SZachary Turner 
144307f5ae8SZachary Turner void SymbolFileNativePDB::Initialize() {
145307f5ae8SZachary Turner   PluginManager::RegisterPlugin(GetPluginNameStatic(),
146307f5ae8SZachary Turner                                 GetPluginDescriptionStatic(), CreateInstance,
147307f5ae8SZachary Turner                                 DebuggerInitialize);
148307f5ae8SZachary Turner }
149307f5ae8SZachary Turner 
150307f5ae8SZachary Turner void SymbolFileNativePDB::Terminate() {
151307f5ae8SZachary Turner   PluginManager::UnregisterPlugin(CreateInstance);
152307f5ae8SZachary Turner }
153307f5ae8SZachary Turner 
154307f5ae8SZachary Turner void SymbolFileNativePDB::DebuggerInitialize(lldb_private::Debugger &debugger) {
155307f5ae8SZachary Turner }
156307f5ae8SZachary Turner 
157307f5ae8SZachary Turner lldb_private::ConstString SymbolFileNativePDB::GetPluginNameStatic() {
158307f5ae8SZachary Turner   static ConstString g_name("native-pdb");
159307f5ae8SZachary Turner   return g_name;
160307f5ae8SZachary Turner }
161307f5ae8SZachary Turner 
162307f5ae8SZachary Turner const char *SymbolFileNativePDB::GetPluginDescriptionStatic() {
163307f5ae8SZachary Turner   return "Microsoft PDB debug symbol cross-platform file reader.";
164307f5ae8SZachary Turner }
165307f5ae8SZachary Turner 
166307f5ae8SZachary Turner lldb_private::SymbolFile *
167307f5ae8SZachary Turner SymbolFileNativePDB::CreateInstance(lldb_private::ObjectFile *obj_file) {
168307f5ae8SZachary Turner   return new SymbolFileNativePDB(obj_file);
169307f5ae8SZachary Turner }
170307f5ae8SZachary Turner 
171307f5ae8SZachary Turner SymbolFileNativePDB::SymbolFileNativePDB(lldb_private::ObjectFile *object_file)
172307f5ae8SZachary Turner     : SymbolFile(object_file) {}
173307f5ae8SZachary Turner 
174307f5ae8SZachary Turner SymbolFileNativePDB::~SymbolFileNativePDB() {}
175307f5ae8SZachary Turner 
176307f5ae8SZachary Turner uint32_t SymbolFileNativePDB::CalculateAbilities() {
177307f5ae8SZachary Turner   uint32_t abilities = 0;
178307f5ae8SZachary Turner   if (!m_obj_file)
179307f5ae8SZachary Turner     return 0;
180307f5ae8SZachary Turner 
181307f5ae8SZachary Turner   if (!m_index) {
182307f5ae8SZachary Turner     // Lazily load and match the PDB file, but only do this once.
183307f5ae8SZachary Turner     std::unique_ptr<PDBFile> file_up =
184307f5ae8SZachary Turner         loadMatchingPDBFile(m_obj_file->GetFileSpec().GetPath(), m_allocator);
185307f5ae8SZachary Turner 
186307f5ae8SZachary Turner     if (!file_up) {
187307f5ae8SZachary Turner       auto module_sp = m_obj_file->GetModule();
188307f5ae8SZachary Turner       if (!module_sp)
189307f5ae8SZachary Turner         return 0;
190307f5ae8SZachary Turner       // See if any symbol file is specified through `--symfile` option.
191307f5ae8SZachary Turner       FileSpec symfile = module_sp->GetSymbolFileFileSpec();
192307f5ae8SZachary Turner       if (!symfile)
193307f5ae8SZachary Turner         return 0;
194307f5ae8SZachary Turner       file_up = loadPDBFile(symfile.GetPath(), m_allocator);
195307f5ae8SZachary Turner     }
196307f5ae8SZachary Turner 
197307f5ae8SZachary Turner     if (!file_up)
198307f5ae8SZachary Turner       return 0;
199307f5ae8SZachary Turner 
200307f5ae8SZachary Turner     auto expected_index = PdbIndex::create(std::move(file_up));
201307f5ae8SZachary Turner     if (!expected_index) {
202307f5ae8SZachary Turner       llvm::consumeError(expected_index.takeError());
203307f5ae8SZachary Turner       return 0;
204307f5ae8SZachary Turner     }
205307f5ae8SZachary Turner     m_index = std::move(*expected_index);
206307f5ae8SZachary Turner   }
207307f5ae8SZachary Turner   if (!m_index)
208307f5ae8SZachary Turner     return 0;
209307f5ae8SZachary Turner 
210307f5ae8SZachary Turner   // We don't especially have to be precise here.  We only distinguish between
211307f5ae8SZachary Turner   // stripped and not stripped.
212307f5ae8SZachary Turner   abilities = kAllAbilities;
213307f5ae8SZachary Turner 
214307f5ae8SZachary Turner   if (m_index->dbi().isStripped())
215307f5ae8SZachary Turner     abilities &= ~(Blocks | LocalVariables);
216307f5ae8SZachary Turner   return abilities;
217307f5ae8SZachary Turner }
218307f5ae8SZachary Turner 
219307f5ae8SZachary Turner void SymbolFileNativePDB::InitializeObject() {
220307f5ae8SZachary Turner   m_obj_load_address = m_obj_file->GetFileOffset();
221307f5ae8SZachary Turner   m_index->SetLoadAddress(m_obj_load_address);
222307f5ae8SZachary Turner   m_index->ParseSectionContribs();
223307f5ae8SZachary Turner }
224307f5ae8SZachary Turner 
225307f5ae8SZachary Turner uint32_t SymbolFileNativePDB::GetNumCompileUnits() {
226307f5ae8SZachary Turner   const DbiModuleList &modules = m_index->dbi().modules();
227307f5ae8SZachary Turner   uint32_t count = modules.getModuleCount();
228307f5ae8SZachary Turner   if (count == 0)
229307f5ae8SZachary Turner     return count;
230307f5ae8SZachary Turner 
231307f5ae8SZachary Turner   // The linker can inject an additional "dummy" compilation unit into the
232307f5ae8SZachary Turner   // PDB. Ignore this special compile unit for our purposes, if it is there.
233307f5ae8SZachary Turner   // It is always the last one.
234307f5ae8SZachary Turner   DbiModuleDescriptor last = modules.getModuleDescriptor(count - 1);
235307f5ae8SZachary Turner   if (last.getModuleName() == "* Linker *")
236307f5ae8SZachary Turner     --count;
237307f5ae8SZachary Turner   return count;
238307f5ae8SZachary Turner }
239307f5ae8SZachary Turner 
240307f5ae8SZachary Turner lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbSymUid func_uid,
241307f5ae8SZachary Turner                                                      const SymbolContext &sc) {
242307f5ae8SZachary Turner   lldbassert(func_uid.tag() == PDB_SymType::Function);
243307f5ae8SZachary Turner 
244307f5ae8SZachary Turner   PdbSymUid cuid = PdbSymUid::makeCompilandId(func_uid.asCuSym().modi);
245307f5ae8SZachary Turner 
246307f5ae8SZachary Turner   const CompilandIndexItem *cci = m_index->compilands().GetCompiland(cuid);
247307f5ae8SZachary Turner   lldbassert(cci);
248307f5ae8SZachary Turner   CVSymbol sym_record =
249307f5ae8SZachary Turner       cci->m_debug_stream.readSymbolAtOffset(func_uid.asCuSym().offset);
250307f5ae8SZachary Turner 
251307f5ae8SZachary Turner   lldbassert(sym_record.kind() == S_LPROC32 || sym_record.kind() == S_GPROC32);
252307f5ae8SZachary Turner   SegmentOffsetLength sol = GetSegmentOffsetAndLength(sym_record);
253307f5ae8SZachary Turner 
254307f5ae8SZachary Turner   auto file_vm_addr = m_index->MakeVirtualAddress(sol.so);
255307f5ae8SZachary Turner   if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0)
256307f5ae8SZachary Turner     return nullptr;
257307f5ae8SZachary Turner 
258307f5ae8SZachary Turner   AddressRange func_range(file_vm_addr, sol.length,
259307f5ae8SZachary Turner                           sc.module_sp->GetSectionList());
260307f5ae8SZachary Turner   if (!func_range.GetBaseAddress().IsValid())
261307f5ae8SZachary Turner     return nullptr;
262307f5ae8SZachary Turner 
263307f5ae8SZachary Turner   lldb_private::Type *func_type = nullptr;
264307f5ae8SZachary Turner 
265307f5ae8SZachary Turner   // FIXME: Resolve types and mangled names.
266307f5ae8SZachary Turner   PdbSymUid sig_uid =
267307f5ae8SZachary Turner       PdbSymUid::makeTypeSymId(PDB_SymType::FunctionSig, TypeIndex{0}, false);
268307f5ae8SZachary Turner   Mangled mangled(getSymbolName(sym_record));
269307f5ae8SZachary Turner 
270307f5ae8SZachary Turner   FunctionSP func_sp = std::make_shared<Function>(
271307f5ae8SZachary Turner       sc.comp_unit, func_uid.toOpaqueId(), sig_uid.toOpaqueId(), mangled,
272307f5ae8SZachary Turner       func_type, func_range);
273307f5ae8SZachary Turner 
274307f5ae8SZachary Turner   sc.comp_unit->AddFunction(func_sp);
275307f5ae8SZachary Turner   return func_sp;
276307f5ae8SZachary Turner }
277307f5ae8SZachary Turner 
278307f5ae8SZachary Turner CompUnitSP
279307f5ae8SZachary Turner SymbolFileNativePDB::CreateCompileUnit(const CompilandIndexItem &cci) {
280307f5ae8SZachary Turner   lldb::LanguageType lang =
281307f5ae8SZachary Turner       cci.m_compile_opts ? TranslateLanguage(cci.m_compile_opts->getLanguage())
282307f5ae8SZachary Turner                          : lldb::eLanguageTypeUnknown;
283307f5ae8SZachary Turner 
284307f5ae8SZachary Turner   LazyBool optimized = eLazyBoolNo;
285307f5ae8SZachary Turner   if (cci.m_compile_opts && cci.m_compile_opts->hasOptimizations())
286307f5ae8SZachary Turner     optimized = eLazyBoolYes;
287307f5ae8SZachary Turner 
288307f5ae8SZachary Turner   llvm::StringRef source_file_name =
289307f5ae8SZachary Turner       m_index->compilands().GetMainSourceFile(cci);
290307f5ae8SZachary Turner   lldb_private::FileSpec fs(source_file_name, false);
291307f5ae8SZachary Turner 
292307f5ae8SZachary Turner   CompUnitSP cu_sp =
293307f5ae8SZachary Turner       std::make_shared<CompileUnit>(m_obj_file->GetModule(), nullptr, fs,
294307f5ae8SZachary Turner                                     cci.m_uid.toOpaqueId(), lang, optimized);
295307f5ae8SZachary Turner 
296307f5ae8SZachary Turner   const PdbCompilandId &cuid = cci.m_uid.asCompiland();
297307f5ae8SZachary Turner   m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(cuid.modi,
298307f5ae8SZachary Turner                                                                     cu_sp);
299307f5ae8SZachary Turner   return cu_sp;
300307f5ae8SZachary Turner }
301307f5ae8SZachary Turner 
302307f5ae8SZachary Turner FunctionSP SymbolFileNativePDB::GetOrCreateFunction(PdbSymUid func_uid,
303307f5ae8SZachary Turner                                                     const SymbolContext &sc) {
304307f5ae8SZachary Turner   lldbassert(func_uid.tag() == PDB_SymType::Function);
305307f5ae8SZachary Turner   auto emplace_result = m_functions.try_emplace(func_uid.toOpaqueId(), nullptr);
306307f5ae8SZachary Turner   if (emplace_result.second)
307307f5ae8SZachary Turner     emplace_result.first->second = CreateFunction(func_uid, sc);
308307f5ae8SZachary Turner 
309307f5ae8SZachary Turner   lldbassert(emplace_result.first->second);
310307f5ae8SZachary Turner   return emplace_result.first->second;
311307f5ae8SZachary Turner }
312307f5ae8SZachary Turner 
313307f5ae8SZachary Turner CompUnitSP
314307f5ae8SZachary Turner SymbolFileNativePDB::GetOrCreateCompileUnit(const CompilandIndexItem &cci) {
315307f5ae8SZachary Turner   auto emplace_result =
316307f5ae8SZachary Turner       m_compilands.try_emplace(cci.m_uid.toOpaqueId(), nullptr);
317307f5ae8SZachary Turner   if (emplace_result.second)
318307f5ae8SZachary Turner     emplace_result.first->second = CreateCompileUnit(cci);
319307f5ae8SZachary Turner 
320307f5ae8SZachary Turner   lldbassert(emplace_result.first->second);
321307f5ae8SZachary Turner   return emplace_result.first->second;
322307f5ae8SZachary Turner }
323307f5ae8SZachary Turner 
324307f5ae8SZachary Turner lldb::CompUnitSP SymbolFileNativePDB::ParseCompileUnitAtIndex(uint32_t index) {
325307f5ae8SZachary Turner   if (index >= GetNumCompileUnits())
326307f5ae8SZachary Turner     return CompUnitSP();
327307f5ae8SZachary Turner   lldbassert(index < UINT16_MAX);
328307f5ae8SZachary Turner   if (index >= UINT16_MAX)
329307f5ae8SZachary Turner     return nullptr;
330307f5ae8SZachary Turner 
331307f5ae8SZachary Turner   CompilandIndexItem &item = m_index->compilands().GetOrCreateCompiland(index);
332307f5ae8SZachary Turner 
333307f5ae8SZachary Turner   return GetOrCreateCompileUnit(item);
334307f5ae8SZachary Turner }
335307f5ae8SZachary Turner 
336307f5ae8SZachary Turner lldb::LanguageType SymbolFileNativePDB::ParseCompileUnitLanguage(
337307f5ae8SZachary Turner     const lldb_private::SymbolContext &sc) {
338307f5ae8SZachary Turner   // What fields should I expect to be filled out on the SymbolContext?  Is it
339307f5ae8SZachary Turner   // safe to assume that `sc.comp_unit` is valid?
340307f5ae8SZachary Turner   if (!sc.comp_unit)
341307f5ae8SZachary Turner     return lldb::eLanguageTypeUnknown;
342307f5ae8SZachary Turner   PdbSymUid uid = PdbSymUid::fromOpaqueId(sc.comp_unit->GetID());
343307f5ae8SZachary Turner   lldbassert(uid.tag() == PDB_SymType::Compiland);
344307f5ae8SZachary Turner 
345307f5ae8SZachary Turner   CompilandIndexItem *item = m_index->compilands().GetCompiland(uid);
346307f5ae8SZachary Turner   lldbassert(item);
347307f5ae8SZachary Turner   if (!item->m_compile_opts)
348307f5ae8SZachary Turner     return lldb::eLanguageTypeUnknown;
349307f5ae8SZachary Turner 
350307f5ae8SZachary Turner   return TranslateLanguage(item->m_compile_opts->getLanguage());
351307f5ae8SZachary Turner }
352307f5ae8SZachary Turner 
353307f5ae8SZachary Turner size_t SymbolFileNativePDB::ParseCompileUnitFunctions(
354307f5ae8SZachary Turner     const lldb_private::SymbolContext &sc) {
355307f5ae8SZachary Turner   lldbassert(sc.comp_unit);
356307f5ae8SZachary Turner   return false;
357307f5ae8SZachary Turner }
358307f5ae8SZachary Turner 
359307f5ae8SZachary Turner static bool NeedsResolvedCompileUnit(uint32_t resolve_scope) {
360307f5ae8SZachary Turner   // If any of these flags are set, we need to resolve the compile unit.
361307f5ae8SZachary Turner   uint32_t flags = eSymbolContextCompUnit;
362307f5ae8SZachary Turner   flags |= eSymbolContextVariable;
363307f5ae8SZachary Turner   flags |= eSymbolContextFunction;
364307f5ae8SZachary Turner   flags |= eSymbolContextBlock;
365307f5ae8SZachary Turner   flags |= eSymbolContextLineEntry;
366307f5ae8SZachary Turner   return (resolve_scope & flags) != 0;
367307f5ae8SZachary Turner }
368307f5ae8SZachary Turner 
369307f5ae8SZachary Turner uint32_t
370307f5ae8SZachary Turner SymbolFileNativePDB::ResolveSymbolContext(const lldb_private::Address &addr,
371307f5ae8SZachary Turner                                           uint32_t resolve_scope,
372307f5ae8SZachary Turner                                           lldb_private::SymbolContext &sc) {
373307f5ae8SZachary Turner   uint32_t resolved_flags = 0;
374307f5ae8SZachary Turner   lldb::addr_t file_addr = addr.GetFileAddress();
375307f5ae8SZachary Turner 
376307f5ae8SZachary Turner   if (NeedsResolvedCompileUnit(resolve_scope)) {
377307f5ae8SZachary Turner     llvm::Optional<uint16_t> modi = m_index->GetModuleIndexForVa(file_addr);
378307f5ae8SZachary Turner     if (!modi)
379307f5ae8SZachary Turner       return 0;
380307f5ae8SZachary Turner     PdbSymUid cuid = PdbSymUid::makeCompilandId(*modi);
381307f5ae8SZachary Turner     CompilandIndexItem *cci = m_index->compilands().GetCompiland(cuid);
382307f5ae8SZachary Turner     if (!cci)
383307f5ae8SZachary Turner       return 0;
384307f5ae8SZachary Turner 
385307f5ae8SZachary Turner     sc.comp_unit = GetOrCreateCompileUnit(*cci).get();
386307f5ae8SZachary Turner     resolved_flags |= eSymbolContextCompUnit;
387307f5ae8SZachary Turner   }
388307f5ae8SZachary Turner 
389307f5ae8SZachary Turner   if (resolve_scope & eSymbolContextFunction) {
390307f5ae8SZachary Turner     lldbassert(sc.comp_unit);
391307f5ae8SZachary Turner     std::vector<SymbolAndUid> matches = m_index->FindSymbolsByVa(file_addr);
392307f5ae8SZachary Turner     for (const auto &match : matches) {
393307f5ae8SZachary Turner       if (match.uid.tag() != PDB_SymType::Function)
394307f5ae8SZachary Turner         continue;
395307f5ae8SZachary Turner       sc.function = GetOrCreateFunction(match.uid, sc).get();
396307f5ae8SZachary Turner     }
397307f5ae8SZachary Turner     resolved_flags |= eSymbolContextFunction;
398307f5ae8SZachary Turner   }
399307f5ae8SZachary Turner 
400307f5ae8SZachary Turner   if (resolve_scope & eSymbolContextLineEntry) {
401307f5ae8SZachary Turner     lldbassert(sc.comp_unit);
402307f5ae8SZachary Turner     if (auto *line_table = sc.comp_unit->GetLineTable()) {
403307f5ae8SZachary Turner       if (line_table->FindLineEntryByAddress(addr, sc.line_entry))
404307f5ae8SZachary Turner         resolved_flags |= eSymbolContextLineEntry;
405307f5ae8SZachary Turner     }
406307f5ae8SZachary Turner   }
407307f5ae8SZachary Turner 
408307f5ae8SZachary Turner   return resolved_flags;
409307f5ae8SZachary Turner }
410307f5ae8SZachary Turner 
411307f5ae8SZachary Turner static void AppendLineEntryToSequence(LineTable &table, LineSequence &sequence,
412307f5ae8SZachary Turner                                       const CompilandIndexItem &cci,
413307f5ae8SZachary Turner                                       lldb::addr_t base_addr,
414307f5ae8SZachary Turner                                       uint32_t file_number,
415307f5ae8SZachary Turner                                       const LineFragmentHeader &block,
416307f5ae8SZachary Turner                                       const LineNumberEntry &cur) {
417307f5ae8SZachary Turner   LineInfo cur_info(cur.Flags);
418307f5ae8SZachary Turner 
419307f5ae8SZachary Turner   if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto())
420307f5ae8SZachary Turner     return;
421307f5ae8SZachary Turner 
422307f5ae8SZachary Turner   uint64_t addr = base_addr + cur.Offset;
423307f5ae8SZachary Turner 
424307f5ae8SZachary Turner   bool is_statement = cur_info.isStatement();
425307f5ae8SZachary Turner   bool is_prologue = IsFunctionPrologue(cci, addr);
426307f5ae8SZachary Turner   bool is_epilogue = IsFunctionEpilogue(cci, addr);
427307f5ae8SZachary Turner 
428307f5ae8SZachary Turner   uint32_t lno = cur_info.getStartLine();
429307f5ae8SZachary Turner 
430307f5ae8SZachary Turner   table.AppendLineEntryToSequence(&sequence, addr, lno, 0, file_number,
431307f5ae8SZachary Turner                                   is_statement, false, is_prologue, is_epilogue,
432307f5ae8SZachary Turner                                   false);
433307f5ae8SZachary Turner }
434307f5ae8SZachary Turner 
435307f5ae8SZachary Turner static void TerminateLineSequence(LineTable &table,
436307f5ae8SZachary Turner                                   const LineFragmentHeader &block,
437307f5ae8SZachary Turner                                   lldb::addr_t base_addr, uint32_t file_number,
438307f5ae8SZachary Turner                                   uint32_t last_line,
439307f5ae8SZachary Turner                                   std::unique_ptr<LineSequence> seq) {
440307f5ae8SZachary Turner   // The end is always a terminal entry, so insert it regardless.
441307f5ae8SZachary Turner   table.AppendLineEntryToSequence(seq.get(), base_addr + block.CodeSize,
442307f5ae8SZachary Turner                                   last_line, 0, file_number, false, false,
443307f5ae8SZachary Turner                                   false, false, true);
444307f5ae8SZachary Turner   table.InsertSequence(seq.release());
445307f5ae8SZachary Turner }
446307f5ae8SZachary Turner 
447307f5ae8SZachary Turner bool SymbolFileNativePDB::ParseCompileUnitLineTable(
448307f5ae8SZachary Turner     const lldb_private::SymbolContext &sc) {
449307f5ae8SZachary Turner   // Unfortunately LLDB is set up to parse the entire compile unit line table
450307f5ae8SZachary Turner   // all at once, even if all it really needs is line info for a specific
451307f5ae8SZachary Turner   // function.  In the future it would be nice if it could set the sc.m_function
452307f5ae8SZachary Turner   // member, and we could only get the line info for the function in question.
453307f5ae8SZachary Turner   lldbassert(sc.comp_unit);
454307f5ae8SZachary Turner   PdbSymUid cu_id = PdbSymUid::fromOpaqueId(sc.comp_unit->GetID());
455307f5ae8SZachary Turner   lldbassert(cu_id.isCompiland());
456307f5ae8SZachary Turner   CompilandIndexItem *cci = m_index->compilands().GetCompiland(cu_id);
457307f5ae8SZachary Turner   lldbassert(cci);
458307f5ae8SZachary Turner   auto line_table = llvm::make_unique<LineTable>(sc.comp_unit);
459307f5ae8SZachary Turner 
460307f5ae8SZachary Turner   // This is basically a copy of the .debug$S subsections from all original COFF
461307f5ae8SZachary Turner   // object files merged together with address relocations applied.  We are
462307f5ae8SZachary Turner   // looking for all DEBUG_S_LINES subsections.
463307f5ae8SZachary Turner   for (const DebugSubsectionRecord &dssr :
464307f5ae8SZachary Turner        cci->m_debug_stream.getSubsectionsArray()) {
465307f5ae8SZachary Turner     if (dssr.kind() != DebugSubsectionKind::Lines)
466307f5ae8SZachary Turner       continue;
467307f5ae8SZachary Turner 
468307f5ae8SZachary Turner     DebugLinesSubsectionRef lines;
469307f5ae8SZachary Turner     llvm::BinaryStreamReader reader(dssr.getRecordData());
470307f5ae8SZachary Turner     if (auto EC = lines.initialize(reader)) {
471307f5ae8SZachary Turner       llvm::consumeError(std::move(EC));
472307f5ae8SZachary Turner       return false;
473307f5ae8SZachary Turner     }
474307f5ae8SZachary Turner 
475307f5ae8SZachary Turner     const LineFragmentHeader *lfh = lines.header();
476307f5ae8SZachary Turner     uint64_t virtual_addr =
477307f5ae8SZachary Turner         m_index->MakeVirtualAddress(lfh->RelocSegment, lfh->RelocOffset);
478307f5ae8SZachary Turner 
479307f5ae8SZachary Turner     const auto &checksums = cci->m_strings.checksums().getArray();
480307f5ae8SZachary Turner     const auto &strings = cci->m_strings.strings();
481307f5ae8SZachary Turner     for (const LineColumnEntry &group : lines) {
482307f5ae8SZachary Turner       // Indices in this structure are actually offsets of records in the
483307f5ae8SZachary Turner       // DEBUG_S_FILECHECKSUMS subsection.  Those entries then have an index
484307f5ae8SZachary Turner       // into the global PDB string table.
485307f5ae8SZachary Turner       auto iter = checksums.at(group.NameIndex);
486307f5ae8SZachary Turner       if (iter == checksums.end())
487307f5ae8SZachary Turner         continue;
488307f5ae8SZachary Turner 
489307f5ae8SZachary Turner       llvm::Expected<llvm::StringRef> efn =
490307f5ae8SZachary Turner           strings.getString(iter->FileNameOffset);
491307f5ae8SZachary Turner       if (!efn) {
492307f5ae8SZachary Turner         llvm::consumeError(efn.takeError());
493307f5ae8SZachary Turner         continue;
494307f5ae8SZachary Turner       }
495307f5ae8SZachary Turner 
496307f5ae8SZachary Turner       // LLDB wants the index of the file in the list of support files.
497307f5ae8SZachary Turner       auto fn_iter = llvm::find(cci->m_file_list, *efn);
498307f5ae8SZachary Turner       lldbassert(fn_iter != cci->m_file_list.end());
499307f5ae8SZachary Turner       uint32_t file_index = std::distance(cci->m_file_list.begin(), fn_iter);
500307f5ae8SZachary Turner 
501307f5ae8SZachary Turner       std::unique_ptr<LineSequence> sequence(
502307f5ae8SZachary Turner           line_table->CreateLineSequenceContainer());
503307f5ae8SZachary Turner       lldbassert(!group.LineNumbers.empty());
504307f5ae8SZachary Turner 
505307f5ae8SZachary Turner       for (const LineNumberEntry &entry : group.LineNumbers) {
506307f5ae8SZachary Turner         AppendLineEntryToSequence(*line_table, *sequence, *cci, virtual_addr,
507307f5ae8SZachary Turner                                   file_index, *lfh, entry);
508307f5ae8SZachary Turner       }
509307f5ae8SZachary Turner       LineInfo last_line(group.LineNumbers.back().Flags);
510307f5ae8SZachary Turner       TerminateLineSequence(*line_table, *lfh, virtual_addr, file_index,
511307f5ae8SZachary Turner                             last_line.getEndLine(), std::move(sequence));
512307f5ae8SZachary Turner     }
513307f5ae8SZachary Turner   }
514307f5ae8SZachary Turner 
515307f5ae8SZachary Turner   if (line_table->GetSize() == 0)
516307f5ae8SZachary Turner     return false;
517307f5ae8SZachary Turner 
518307f5ae8SZachary Turner   sc.comp_unit->SetLineTable(line_table.release());
519307f5ae8SZachary Turner   return true;
520307f5ae8SZachary Turner }
521307f5ae8SZachary Turner 
522307f5ae8SZachary Turner bool SymbolFileNativePDB::ParseCompileUnitDebugMacros(
523307f5ae8SZachary Turner     const lldb_private::SymbolContext &sc) {
524307f5ae8SZachary Turner   // PDB doesn't contain information about macros
525307f5ae8SZachary Turner   return false;
526307f5ae8SZachary Turner }
527307f5ae8SZachary Turner 
528307f5ae8SZachary Turner bool SymbolFileNativePDB::ParseCompileUnitSupportFiles(
529307f5ae8SZachary Turner     const lldb_private::SymbolContext &sc,
530307f5ae8SZachary Turner     lldb_private::FileSpecList &support_files) {
531307f5ae8SZachary Turner   lldbassert(sc.comp_unit);
532307f5ae8SZachary Turner 
533307f5ae8SZachary Turner   PdbSymUid comp_uid = PdbSymUid::fromOpaqueId(sc.comp_unit->GetID());
534307f5ae8SZachary Turner   lldbassert(comp_uid.tag() == PDB_SymType::Compiland);
535307f5ae8SZachary Turner 
536307f5ae8SZachary Turner   const CompilandIndexItem *cci = m_index->compilands().GetCompiland(comp_uid);
537307f5ae8SZachary Turner   lldbassert(cci);
538307f5ae8SZachary Turner 
539307f5ae8SZachary Turner   for (llvm::StringRef f : cci->m_file_list) {
540307f5ae8SZachary Turner     FileSpec::Style style =
541307f5ae8SZachary Turner         f.startswith("/") ? FileSpec::Style::posix : FileSpec::Style::windows;
542307f5ae8SZachary Turner     FileSpec spec(f, false, style);
543307f5ae8SZachary Turner     support_files.Append(spec);
544307f5ae8SZachary Turner   }
545307f5ae8SZachary Turner 
546307f5ae8SZachary Turner   return true;
547307f5ae8SZachary Turner }
548307f5ae8SZachary Turner 
549307f5ae8SZachary Turner bool SymbolFileNativePDB::ParseImportedModules(
550307f5ae8SZachary Turner     const lldb_private::SymbolContext &sc,
551307f5ae8SZachary Turner     std::vector<lldb_private::ConstString> &imported_modules) {
552307f5ae8SZachary Turner   // PDB does not yet support module debug info
553307f5ae8SZachary Turner   return false;
554307f5ae8SZachary Turner }
555307f5ae8SZachary Turner 
556307f5ae8SZachary Turner size_t SymbolFileNativePDB::ParseFunctionBlocks(
557307f5ae8SZachary Turner     const lldb_private::SymbolContext &sc) {
558307f5ae8SZachary Turner   lldbassert(sc.comp_unit && sc.function);
559307f5ae8SZachary Turner   return 0;
560307f5ae8SZachary Turner }
561307f5ae8SZachary Turner 
562307f5ae8SZachary Turner uint32_t SymbolFileNativePDB::FindFunctions(
563307f5ae8SZachary Turner     const lldb_private::ConstString &name,
564307f5ae8SZachary Turner     const lldb_private::CompilerDeclContext *parent_decl_ctx,
565307f5ae8SZachary Turner     uint32_t name_type_mask, bool include_inlines, bool append,
566307f5ae8SZachary Turner     lldb_private::SymbolContextList &sc_list) {
567307f5ae8SZachary Turner   // For now we only support lookup by method name.
568307f5ae8SZachary Turner   if (!(name_type_mask & eFunctionNameTypeMethod))
569307f5ae8SZachary Turner     return 0;
570307f5ae8SZachary Turner 
571307f5ae8SZachary Turner   using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
572307f5ae8SZachary Turner 
573307f5ae8SZachary Turner   std::vector<SymbolAndOffset> matches = m_index->globals().findRecordsByName(
574307f5ae8SZachary Turner       name.GetStringRef(), m_index->symrecords());
575307f5ae8SZachary Turner   for (const SymbolAndOffset &match : matches) {
576307f5ae8SZachary Turner     if (match.second.kind() != S_PROCREF && match.second.kind() != S_LPROCREF)
577307f5ae8SZachary Turner       continue;
578307f5ae8SZachary Turner     ProcRefSym proc(match.second.kind());
579307f5ae8SZachary Turner     cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(match.second, proc));
580307f5ae8SZachary Turner 
581307f5ae8SZachary Turner     if (!IsValidRecord(proc))
582307f5ae8SZachary Turner       continue;
583307f5ae8SZachary Turner 
584307f5ae8SZachary Turner     PdbSymUid cuid = PdbSymUid::makeCompilandId(proc);
585307f5ae8SZachary Turner     CompilandIndexItem &cci = m_index->compilands().GetOrCreateCompiland(cuid);
586307f5ae8SZachary Turner     lldb_private::SymbolContext sc;
587307f5ae8SZachary Turner 
588307f5ae8SZachary Turner     sc.comp_unit = GetOrCreateCompileUnit(cci).get();
589307f5ae8SZachary Turner     sc.module_sp = sc.comp_unit->GetModule();
590307f5ae8SZachary Turner     PdbSymUid func_uid = PdbSymUid::makeCuSymId(proc);
591307f5ae8SZachary Turner     sc.function = GetOrCreateFunction(func_uid, sc).get();
592307f5ae8SZachary Turner 
593307f5ae8SZachary Turner     sc_list.Append(sc);
594307f5ae8SZachary Turner   }
595307f5ae8SZachary Turner 
596307f5ae8SZachary Turner   return sc_list.GetSize();
597307f5ae8SZachary Turner }
598307f5ae8SZachary Turner 
599307f5ae8SZachary Turner uint32_t
600307f5ae8SZachary Turner SymbolFileNativePDB::FindFunctions(const lldb_private::RegularExpression &regex,
601307f5ae8SZachary Turner                                    bool include_inlines, bool append,
602307f5ae8SZachary Turner                                    lldb_private::SymbolContextList &sc_list) {
603307f5ae8SZachary Turner   return 0;
604307f5ae8SZachary Turner }
605307f5ae8SZachary Turner 
606307f5ae8SZachary Turner lldb_private::CompilerDeclContext SymbolFileNativePDB::FindNamespace(
607307f5ae8SZachary Turner     const lldb_private::SymbolContext &sc,
608307f5ae8SZachary Turner     const lldb_private::ConstString &name,
609307f5ae8SZachary Turner     const lldb_private::CompilerDeclContext *parent_decl_ctx) {
610307f5ae8SZachary Turner   return {};
611307f5ae8SZachary Turner }
612307f5ae8SZachary Turner 
613307f5ae8SZachary Turner lldb_private::TypeSystem *
614307f5ae8SZachary Turner SymbolFileNativePDB::GetTypeSystemForLanguage(lldb::LanguageType language) {
615307f5ae8SZachary Turner   auto type_system =
616307f5ae8SZachary Turner       m_obj_file->GetModule()->GetTypeSystemForLanguage(language);
617307f5ae8SZachary Turner   if (type_system)
618307f5ae8SZachary Turner     type_system->SetSymbolFile(this);
619307f5ae8SZachary Turner   return type_system;
620307f5ae8SZachary Turner }
621307f5ae8SZachary Turner 
622307f5ae8SZachary Turner lldb_private::ConstString SymbolFileNativePDB::GetPluginName() {
623307f5ae8SZachary Turner   static ConstString g_name("pdb");
624307f5ae8SZachary Turner   return g_name;
625307f5ae8SZachary Turner }
626307f5ae8SZachary Turner 
627307f5ae8SZachary Turner uint32_t SymbolFileNativePDB::GetPluginVersion() { return 1; }
628