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