blob: 4b19b56aa9a19aefa8e38157240f6123548c520a [file] [log] [blame]
Zachary Turner74e08ca2016-03-02 22:05:52 +00001//===-- SymbolFilePDB.cpp ---------------------------------------*- 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//===----------------------------------------------------------------------===//
9
10#include "SymbolFilePDB.h"
11
Zachary Turner42dff792016-04-15 00:21:26 +000012#include "clang/Lex/Lexer.h"
13
Zachary Turner74e08ca2016-03-02 22:05:52 +000014#include "lldb/Core/Module.h"
15#include "lldb/Core/PluginManager.h"
Zachary Turner42dff792016-04-15 00:21:26 +000016#include "lldb/Symbol/ClangASTContext.h"
Zachary Turner74e08ca2016-03-02 22:05:52 +000017#include "lldb/Symbol/CompileUnit.h"
18#include "lldb/Symbol/LineTable.h"
19#include "lldb/Symbol/ObjectFile.h"
20#include "lldb/Symbol/SymbolContext.h"
Zachary Turner42dff792016-04-15 00:21:26 +000021#include "lldb/Symbol/TypeMap.h"
Zachary Turner74e08ca2016-03-02 22:05:52 +000022
23#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
24#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
25#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
26#include "llvm/DebugInfo/PDB/PDBSymbol.h"
27#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
28#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h"
29#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
30#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
31#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
32#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
Zachary Turner42dff792016-04-15 00:21:26 +000033#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
34#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
35#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
36
37#include "Plugins/SymbolFile/PDB/PDBASTParser.h"
38
39#include <regex>
Zachary Turner74e08ca2016-03-02 22:05:52 +000040
41using namespace lldb_private;
Zachary Turner54fd7ff2016-05-04 20:33:53 +000042using namespace llvm::pdb;
Zachary Turner74e08ca2016-03-02 22:05:52 +000043
44namespace
45{
Zachary Turner54fd7ff2016-05-04 20:33:53 +000046lldb::LanguageType
47TranslateLanguage(PDB_Lang lang)
48{
49 switch (lang)
Zachary Turner74e08ca2016-03-02 22:05:52 +000050 {
Zachary Turner54fd7ff2016-05-04 20:33:53 +000051 case PDB_Lang::Cpp:
Zachary Turner74e08ca2016-03-02 22:05:52 +000052 return lldb::LanguageType::eLanguageTypeC_plus_plus;
Zachary Turner54fd7ff2016-05-04 20:33:53 +000053 case PDB_Lang::C:
Zachary Turner74e08ca2016-03-02 22:05:52 +000054 return lldb::LanguageType::eLanguageTypeC;
55 default:
56 return lldb::LanguageType::eLanguageTypeUnknown;
57 }
58 }
Zachary Turner7e8c7be2016-03-10 00:06:26 +000059
60 bool
61 ShouldAddLine(uint32_t requested_line, uint32_t actual_line, uint32_t addr_length)
62 {
63 return ((requested_line == 0 || actual_line == requested_line) && addr_length > 0);
64 }
Zachary Turner74e08ca2016-03-02 22:05:52 +000065}
66
67void
68SymbolFilePDB::Initialize()
69{
70 PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
71 DebuggerInitialize);
72}
73
74void
75SymbolFilePDB::Terminate()
76{
77 PluginManager::UnregisterPlugin(CreateInstance);
78}
79
80void
81SymbolFilePDB::DebuggerInitialize(lldb_private::Debugger &debugger)
82{
83}
84
85lldb_private::ConstString
86SymbolFilePDB::GetPluginNameStatic()
87{
88 static ConstString g_name("pdb");
89 return g_name;
90}
91
92const char *
93SymbolFilePDB::GetPluginDescriptionStatic()
94{
95 return "Microsoft PDB debug symbol file reader.";
96}
97
98lldb_private::SymbolFile *
99SymbolFilePDB::CreateInstance(lldb_private::ObjectFile *obj_file)
100{
101 return new SymbolFilePDB(obj_file);
102}
103
104SymbolFilePDB::SymbolFilePDB(lldb_private::ObjectFile *object_file)
105 : SymbolFile(object_file), m_cached_compile_unit_count(0)
106{
107}
108
109SymbolFilePDB::~SymbolFilePDB()
110{
111}
112
113uint32_t
114SymbolFilePDB::CalculateAbilities()
115{
116 if (!m_session_up)
117 {
118 // Lazily load and match the PDB file, but only do this once.
119 std::string exePath = m_obj_file->GetFileSpec().GetPath();
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000120 auto error = loadDataForEXE(PDB_ReaderType::DIA, llvm::StringRef(exePath), m_session_up);
Zachary Turner50c58c02016-05-06 21:35:47 +0000121 if (error)
Zachary Turner74e08ca2016-03-02 22:05:52 +0000122 return 0;
123 }
124 return CompileUnits | LineTables;
125}
126
127void
128SymbolFilePDB::InitializeObject()
129{
130 lldb::addr_t obj_load_address = m_obj_file->GetFileOffset();
131 m_session_up->setLoadAddress(obj_load_address);
Zachary Turner42dff792016-04-15 00:21:26 +0000132
133 TypeSystem *type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
134 ClangASTContext *clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system);
135 m_tu_decl_ctx_up = llvm::make_unique<CompilerDeclContext>(type_system, clang_type_system->GetTranslationUnitDecl());
Zachary Turner74e08ca2016-03-02 22:05:52 +0000136}
137
138uint32_t
139SymbolFilePDB::GetNumCompileUnits()
140{
141 if (m_cached_compile_unit_count == 0)
142 {
143 auto global = m_session_up->getGlobalScope();
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000144 auto compilands = global->findAllChildren<PDBSymbolCompiland>();
Zachary Turner74e08ca2016-03-02 22:05:52 +0000145 m_cached_compile_unit_count = compilands->getChildCount();
146
147 // The linker can inject an additional "dummy" compilation unit into the PDB.
148 // Ignore this special compile unit for our purposes, if it is there. It is
149 // always the last one.
150 auto last_cu = compilands->getChildAtIndex(m_cached_compile_unit_count - 1);
151 std::string name = last_cu->getName();
152 if (name == "* Linker *")
153 --m_cached_compile_unit_count;
154 }
155 return m_cached_compile_unit_count;
156}
157
158lldb::CompUnitSP
159SymbolFilePDB::ParseCompileUnitAtIndex(uint32_t index)
160{
161 auto global = m_session_up->getGlobalScope();
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000162 auto compilands = global->findAllChildren<PDBSymbolCompiland>();
Zachary Turner74e08ca2016-03-02 22:05:52 +0000163 auto cu = compilands->getChildAtIndex(index);
164
165 uint32_t id = cu->getSymIndexId();
166
167 return ParseCompileUnitForSymIndex(id);
168}
169
170lldb::LanguageType
171SymbolFilePDB::ParseCompileUnitLanguage(const lldb_private::SymbolContext &sc)
172{
173 // What fields should I expect to be filled out on the SymbolContext? Is it
174 // safe to assume that `sc.comp_unit` is valid?
175 if (!sc.comp_unit)
176 return lldb::eLanguageTypeUnknown;
177
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000178 auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(sc.comp_unit->GetID());
Zachary Turner74e08ca2016-03-02 22:05:52 +0000179 if (!cu)
180 return lldb::eLanguageTypeUnknown;
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000181 auto details = cu->findOneChild<PDBSymbolCompilandDetails>();
Zachary Turner74e08ca2016-03-02 22:05:52 +0000182 if (!details)
183 return lldb::eLanguageTypeUnknown;
184 return TranslateLanguage(details->getLanguage());
185}
186
187size_t
188SymbolFilePDB::ParseCompileUnitFunctions(const lldb_private::SymbolContext &sc)
189{
190 // TODO: Implement this
191 return size_t();
192}
193
194bool
195SymbolFilePDB::ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc)
196{
197 return ParseCompileUnitLineTable(sc, 0);
198}
199
200bool
201SymbolFilePDB::ParseCompileUnitDebugMacros(const lldb_private::SymbolContext &sc)
202{
203 // PDB doesn't contain information about macros
204 return false;
205}
206
207bool
208SymbolFilePDB::ParseCompileUnitSupportFiles(const lldb_private::SymbolContext &sc,
209 lldb_private::FileSpecList &support_files)
210{
211 if (!sc.comp_unit)
212 return false;
213
214 // In theory this is unnecessary work for us, because all of this information is easily
215 // (and quickly) accessible from DebugInfoPDB, so caching it a second time seems like a waste.
216 // Unfortunately, there's no good way around this short of a moderate refactor, since SymbolVendor
217 // depends on being able to cache this list.
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000218 auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(sc.comp_unit->GetID());
Zachary Turner74e08ca2016-03-02 22:05:52 +0000219 if (!cu)
220 return false;
221 auto files = m_session_up->getSourceFilesForCompiland(*cu);
222 if (!files || files->getChildCount() == 0)
223 return false;
224
225 while (auto file = files->getNext())
226 {
227 FileSpec spec(file->getFileName(), false);
228 support_files.Append(spec);
229 }
230 return true;
231}
232
233bool
234SymbolFilePDB::ParseImportedModules(const lldb_private::SymbolContext &sc,
235 std::vector<lldb_private::ConstString> &imported_modules)
236{
237 // PDB does not yet support module debug info
238 return false;
239}
240
241size_t
242SymbolFilePDB::ParseFunctionBlocks(const lldb_private::SymbolContext &sc)
243{
244 // TODO: Implement this
245 return size_t();
246}
247
248size_t
249SymbolFilePDB::ParseTypes(const lldb_private::SymbolContext &sc)
250{
251 // TODO: Implement this
252 return size_t();
253}
254
255size_t
256SymbolFilePDB::ParseVariablesForContext(const lldb_private::SymbolContext &sc)
257{
258 // TODO: Implement this
259 return size_t();
260}
261
262lldb_private::Type *
263SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid)
264{
Zachary Turner42dff792016-04-15 00:21:26 +0000265 auto find_result = m_types.find(type_uid);
266 if (find_result != m_types.end())
267 return find_result->second.get();
268
269 TypeSystem *type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
270 ClangASTContext *clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system);
271 if (!clang_type_system)
272 return nullptr;
273 PDBASTParser *pdb = llvm::dyn_cast<PDBASTParser>(clang_type_system->GetPDBParser());
274 if (!pdb)
275 return nullptr;
276
277 auto pdb_type = m_session_up->getSymbolById(type_uid);
278 if (pdb_type == nullptr)
279 return nullptr;
280
281 lldb::TypeSP result = pdb->CreateLLDBTypeFromPDBType(*pdb_type);
282 m_types.insert(std::make_pair(type_uid, result));
283 return result.get();
Zachary Turner74e08ca2016-03-02 22:05:52 +0000284}
285
286bool
287SymbolFilePDB::CompleteType(lldb_private::CompilerType &compiler_type)
288{
289 // TODO: Implement this
290 return false;
291}
292
293lldb_private::CompilerDecl
294SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid)
295{
296 return lldb_private::CompilerDecl();
297}
298
299lldb_private::CompilerDeclContext
300SymbolFilePDB::GetDeclContextForUID(lldb::user_id_t uid)
301{
Zachary Turner42dff792016-04-15 00:21:26 +0000302 // PDB always uses the translation unit decl context for everything. We can improve this later
303 // but it's not easy because PDB doesn't provide a high enough level of type fidelity in this area.
304 return *m_tu_decl_ctx_up;
Zachary Turner74e08ca2016-03-02 22:05:52 +0000305}
306
307lldb_private::CompilerDeclContext
308SymbolFilePDB::GetDeclContextContainingUID(lldb::user_id_t uid)
309{
Zachary Turner42dff792016-04-15 00:21:26 +0000310 return *m_tu_decl_ctx_up;
Zachary Turner74e08ca2016-03-02 22:05:52 +0000311}
312
313void
314SymbolFilePDB::ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx)
315{
316}
317
318uint32_t
319SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr, uint32_t resolve_scope,
320 lldb_private::SymbolContext &sc)
321{
322 return uint32_t();
323}
324
325uint32_t
326SymbolFilePDB::ResolveSymbolContext(const lldb_private::FileSpec &file_spec, uint32_t line, bool check_inlines,
327 uint32_t resolve_scope, lldb_private::SymbolContextList &sc_list)
328{
329 if (resolve_scope & lldb::eSymbolContextCompUnit)
330 {
331 // Locate all compilation units with line numbers referencing the specified file. For example, if
332 // `file_spec` is <vector>, then this should return all source files and header files that reference
333 // <vector>, either directly or indirectly.
334 auto compilands =
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000335 m_session_up->findCompilandsForSourceFile(file_spec.GetPath(), PDB_NameSearchFlags::NS_CaseInsensitive);
Zachary Turner74e08ca2016-03-02 22:05:52 +0000336
337 // For each one, either find get its previously parsed data, or parse it afresh and add it to
338 // the symbol context list.
339 while (auto compiland = compilands->getNext())
340 {
341 // If we're not checking inlines, then don't add line information for this file unless the FileSpec
342 // matches.
343 if (!check_inlines)
344 {
345 // `getSourceFileName` returns the basename of the original source file used to generate this compiland.
346 // It does not return the full path. Currently the only way to get that is to do a basename lookup to
347 // get the IPDBSourceFile, but this is ambiguous in the case of two source files with the same name
348 // contributing to the same compiland. This is a moderately extreme edge case, so we consider this ok
349 // for now, although we need to find a long term solution.
350 std::string source_file = compiland->getSourceFileName();
351 auto pdb_file = m_session_up->findOneSourceFile(compiland.get(), source_file,
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000352 PDB_NameSearchFlags::NS_CaseInsensitive);
Zachary Turner74e08ca2016-03-02 22:05:52 +0000353 source_file = pdb_file->getFileName();
354 FileSpec this_spec(source_file, false, FileSpec::ePathSyntaxWindows);
355 if (!file_spec.FileEquals(this_spec))
356 continue;
357 }
358
359 SymbolContext sc;
360 auto cu = ParseCompileUnitForSymIndex(compiland->getSymIndexId());
361 sc.comp_unit = cu.get();
362 sc.module_sp = cu->GetModule();
363 sc_list.Append(sc);
364
365 // If we were asked to resolve line entries, add all entries to the line table that match the requested
366 // line (or all lines if `line` == 0)
367 if (resolve_scope & lldb::eSymbolContextLineEntry)
368 ParseCompileUnitLineTable(sc, line);
369 }
370 }
371 return sc_list.GetSize();
372}
373
374uint32_t
375SymbolFilePDB::FindGlobalVariables(const lldb_private::ConstString &name,
376 const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append,
377 uint32_t max_matches, lldb_private::VariableList &variables)
378{
379 return uint32_t();
380}
381
382uint32_t
383SymbolFilePDB::FindGlobalVariables(const lldb_private::RegularExpression &regex, bool append, uint32_t max_matches,
384 lldb_private::VariableList &variables)
385{
386 return uint32_t();
387}
388
389uint32_t
390SymbolFilePDB::FindFunctions(const lldb_private::ConstString &name,
391 const lldb_private::CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask,
392 bool include_inlines, bool append, lldb_private::SymbolContextList &sc_list)
393{
394 return uint32_t();
395}
396
397uint32_t
398SymbolFilePDB::FindFunctions(const lldb_private::RegularExpression &regex, bool include_inlines, bool append,
399 lldb_private::SymbolContextList &sc_list)
400{
401 return uint32_t();
402}
403
404void
405SymbolFilePDB::GetMangledNamesForFunction(const std::string &scope_qualified_name,
406 std::vector<lldb_private::ConstString> &mangled_names)
407{
408}
409
410uint32_t
411SymbolFilePDB::FindTypes(const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name,
412 const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches,
413 llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
414 lldb_private::TypeMap &types)
415{
Zachary Turner42dff792016-04-15 00:21:26 +0000416 if (!append)
417 types.Clear();
418 if (!name)
419 return 0;
420
421 searched_symbol_files.clear();
422 searched_symbol_files.insert(this);
423
424 std::string name_str = name.AsCString();
425
426 // If this might be a regex, we have to return EVERY symbol and process them one by one, which is going
427 // to destroy performance on large PDB files. So try really hard not to use a regex match.
428 if (name_str.find_first_of("[]?*.-+\\") != std::string::npos)
429 FindTypesByRegex(name_str, max_matches, types);
430 else
431 FindTypesByName(name_str, max_matches, types);
432 return types.GetSize();
433}
434
435void
436SymbolFilePDB::FindTypesByRegex(const std::string &regex, uint32_t max_matches, lldb_private::TypeMap &types)
437{
438 // When searching by regex, we need to go out of our way to limit the search space as much as possible, since
439 // the way this is implemented is by searching EVERYTHING in the PDB and manually doing a regex compare. PDB
440 // library isn't optimized for regex searches or searches across multiple symbol types at the same time, so the
441 // best we can do is to search enums, then typedefs, then classes one by one, and do a regex compare against all
442 // of them.
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000443 PDB_SymType tags_to_search[] = {PDB_SymType::Enum, PDB_SymType::Typedef, PDB_SymType::UDT};
Zachary Turner42dff792016-04-15 00:21:26 +0000444 auto global = m_session_up->getGlobalScope();
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000445 std::unique_ptr<IPDBEnumSymbols> results;
Zachary Turner42dff792016-04-15 00:21:26 +0000446
447 std::regex re(regex);
448
449 uint32_t matches = 0;
450
451 for (auto tag : tags_to_search)
452 {
453 results = global->findAllChildren(tag);
454 while (auto result = results->getNext())
455 {
456 if (max_matches > 0 && matches >= max_matches)
457 break;
458
459 std::string type_name;
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000460 if (auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(result.get()))
Zachary Turner42dff792016-04-15 00:21:26 +0000461 type_name = enum_type->getName();
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000462 else if (auto typedef_type = llvm::dyn_cast<PDBSymbolTypeTypedef>(result.get()))
Zachary Turner42dff792016-04-15 00:21:26 +0000463 type_name = typedef_type->getName();
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000464 else if (auto class_type = llvm::dyn_cast<PDBSymbolTypeUDT>(result.get()))
Zachary Turner42dff792016-04-15 00:21:26 +0000465 type_name = class_type->getName();
466 else
467 {
468 // We're only looking for types that have names. Skip symbols, as well as
469 // unnamed types such as arrays, pointers, etc.
470 continue;
471 }
472
473 if (!std::regex_match(type_name, re))
474 continue;
475
476 // This should cause the type to get cached and stored in the `m_types` lookup.
477 if (!ResolveTypeUID(result->getSymIndexId()))
478 continue;
479
480 auto iter = m_types.find(result->getSymIndexId());
481 if (iter == m_types.end())
482 continue;
483 types.Insert(iter->second);
484 ++matches;
485 }
486 }
487}
488
489void
490SymbolFilePDB::FindTypesByName(const std::string &name, uint32_t max_matches, lldb_private::TypeMap &types)
491{
492 auto global = m_session_up->getGlobalScope();
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000493 std::unique_ptr<IPDBEnumSymbols> results;
494 results = global->findChildren(PDB_SymType::None, name.c_str(), PDB_NameSearchFlags::NS_Default);
Zachary Turner42dff792016-04-15 00:21:26 +0000495
496 uint32_t matches = 0;
497
498 while (auto result = results->getNext())
499 {
500 if (max_matches > 0 && matches >= max_matches)
501 break;
502 switch (result->getSymTag())
503 {
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000504 case PDB_SymType::Enum:
505 case PDB_SymType::UDT:
506 case PDB_SymType::Typedef:
Zachary Turner42dff792016-04-15 00:21:26 +0000507 break;
508 default:
509 // We're only looking for types that have names. Skip symbols, as well as
510 // unnamed types such as arrays, pointers, etc.
511 continue;
512 }
513
514 // This should cause the type to get cached and stored in the `m_types` lookup.
515 if (!ResolveTypeUID(result->getSymIndexId()))
516 continue;
517
518 auto iter = m_types.find(result->getSymIndexId());
519 if (iter == m_types.end())
520 continue;
521 types.Insert(iter->second);
522 ++matches;
523 }
Zachary Turner74e08ca2016-03-02 22:05:52 +0000524}
525
526size_t
Zachary Turner42dff792016-04-15 00:21:26 +0000527SymbolFilePDB::FindTypes(const std::vector<lldb_private::CompilerContext> &contexts, bool append,
Zachary Turner74e08ca2016-03-02 22:05:52 +0000528 lldb_private::TypeMap &types)
529{
Zachary Turner42dff792016-04-15 00:21:26 +0000530 return 0;
Zachary Turner74e08ca2016-03-02 22:05:52 +0000531}
532
533lldb_private::TypeList *
534SymbolFilePDB::GetTypeList()
535{
536 return nullptr;
537}
538
539size_t
540SymbolFilePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope, uint32_t type_mask,
541 lldb_private::TypeList &type_list)
542{
543 return size_t();
544}
545
546lldb_private::TypeSystem *
547SymbolFilePDB::GetTypeSystemForLanguage(lldb::LanguageType language)
548{
549 auto type_system = m_obj_file->GetModule()->GetTypeSystemForLanguage(language);
550 if (type_system)
551 type_system->SetSymbolFile(this);
552 return type_system;
553}
554
555lldb_private::CompilerDeclContext
556SymbolFilePDB::FindNamespace(const lldb_private::SymbolContext &sc, const lldb_private::ConstString &name,
557 const lldb_private::CompilerDeclContext *parent_decl_ctx)
558{
559 return lldb_private::CompilerDeclContext();
560}
561
562lldb_private::ConstString
563SymbolFilePDB::GetPluginName()
564{
565 static ConstString g_name("pdb");
566 return g_name;
567}
568
569uint32_t
570SymbolFilePDB::GetPluginVersion()
571{
572 return 1;
573}
574
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000575IPDBSession &
Zachary Turner42dff792016-04-15 00:21:26 +0000576SymbolFilePDB::GetPDBSession()
577{
578 return *m_session_up;
579}
580
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000581const IPDBSession &
Zachary Turner42dff792016-04-15 00:21:26 +0000582SymbolFilePDB::GetPDBSession() const
583{
584 return *m_session_up;
585}
586
Zachary Turner74e08ca2016-03-02 22:05:52 +0000587lldb::CompUnitSP
588SymbolFilePDB::ParseCompileUnitForSymIndex(uint32_t id)
589{
590 auto found_cu = m_comp_units.find(id);
591 if (found_cu != m_comp_units.end())
592 return found_cu->second;
593
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000594 auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(id);
Zachary Turner74e08ca2016-03-02 22:05:52 +0000595
596 // `getSourceFileName` returns the basename of the original source file used to generate this compiland. It does
597 // not return the full path. Currently the only way to get that is to do a basename lookup to get the
598 // IPDBSourceFile, but this is ambiguous in the case of two source files with the same name contributing to the
599 // same compiland. This is a moderately extreme edge case, so we consider this ok for now, although we need to find
600 // a long term solution.
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000601 auto file =
602 m_session_up->findOneSourceFile(cu.get(), cu->getSourceFileName(), PDB_NameSearchFlags::NS_CaseInsensitive);
Zachary Turner74e08ca2016-03-02 22:05:52 +0000603 std::string path = file->getFileName();
604
605 lldb::LanguageType lang;
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000606 auto details = cu->findOneChild<PDBSymbolCompilandDetails>();
Zachary Turner74e08ca2016-03-02 22:05:52 +0000607 if (!details)
608 lang = lldb::eLanguageTypeC_plus_plus;
609 else
610 lang = TranslateLanguage(details->getLanguage());
611
612 // Don't support optimized code for now, DebugInfoPDB does not return this information.
613 bool optimized = false;
614 auto result = std::make_shared<CompileUnit>(m_obj_file->GetModule(), nullptr, path.c_str(), id, lang, optimized);
615 m_comp_units.insert(std::make_pair(id, result));
616 return result;
617}
618
619bool
620SymbolFilePDB::ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc, uint32_t match_line)
621{
622 auto global = m_session_up->getGlobalScope();
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000623 auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(sc.comp_unit->GetID());
Zachary Turner74e08ca2016-03-02 22:05:52 +0000624
625 // LineEntry needs the *index* of the file into the list of support files returned by
626 // ParseCompileUnitSupportFiles. But the underlying SDK gives us a globally unique
627 // idenfitifier in the namespace of the PDB. So, we have to do a mapping so that we
628 // can hand out indices.
Zachary Turner42dff792016-04-15 00:21:26 +0000629 llvm::DenseMap<uint32_t, uint32_t> index_map;
Zachary Turner74e08ca2016-03-02 22:05:52 +0000630 BuildSupportFileIdToSupportFileIndexMap(*cu, index_map);
631 auto line_table = llvm::make_unique<LineTable>(sc.comp_unit);
632
633 // Find contributions to `cu` from all source and header files.
634 std::string path = sc.comp_unit->GetPath();
635 auto files = m_session_up->getSourceFilesForCompiland(*cu);
636
637 // For each source and header file, create a LineSequence for contributions to the cu
638 // from that file, and add the sequence.
639 while (auto file = files->getNext())
640 {
641 std::unique_ptr<LineSequence> sequence(line_table->CreateLineSequenceContainer());
642 auto lines = m_session_up->findLineNumbers(*cu, *file);
643 int entry_count = lines->getChildCount();
644
Zachary Turner7e8c7be2016-03-10 00:06:26 +0000645 uint64_t prev_addr;
646 uint32_t prev_length;
647 uint32_t prev_line;
648 uint32_t prev_source_idx;
649
Zachary Turner74e08ca2016-03-02 22:05:52 +0000650 for (int i = 0; i < entry_count; ++i)
651 {
652 auto line = lines->getChildAtIndex(i);
Zachary Turner74e08ca2016-03-02 22:05:52 +0000653
Zachary Turner7e8c7be2016-03-10 00:06:26 +0000654 uint64_t lno = line->getLineNumber();
655 uint64_t addr = line->getVirtualAddress();
656 uint32_t length = line->getLength();
Zachary Turner74e08ca2016-03-02 22:05:52 +0000657 uint32_t source_id = line->getSourceFileId();
Zachary Turner7e8c7be2016-03-10 00:06:26 +0000658 uint32_t col = line->getColumnNumber();
Zachary Turner74e08ca2016-03-02 22:05:52 +0000659 uint32_t source_idx = index_map[source_id];
660
Zachary Turner7e8c7be2016-03-10 00:06:26 +0000661 // There was a gap between the current entry and the previous entry if the addresses don't perfectly line
662 // up.
663 bool is_gap = (i > 0) && (prev_addr + prev_length < addr);
664
665 // Before inserting the current entry, insert a terminal entry at the end of the previous entry's address
666 // range if the current entry resulted in a gap from the previous entry.
667 if (is_gap && ShouldAddLine(match_line, prev_line, prev_length))
Zachary Turner74e08ca2016-03-02 22:05:52 +0000668 {
Zachary Turner7e8c7be2016-03-10 00:06:26 +0000669 line_table->AppendLineEntryToSequence(sequence.get(), prev_addr + prev_length, prev_line, 0,
670 prev_source_idx, false, false, false, false, true);
Zachary Turner74e08ca2016-03-02 22:05:52 +0000671 }
672
Zachary Turner7e8c7be2016-03-10 00:06:26 +0000673 if (ShouldAddLine(match_line, lno, length))
674 {
675 bool is_statement = line->isStatement();
676 bool is_prologue = false;
677 bool is_epilogue = false;
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000678 auto func = m_session_up->findSymbolByAddress(addr, PDB_SymType::Function);
Zachary Turner7e8c7be2016-03-10 00:06:26 +0000679 if (func)
680 {
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000681 auto prologue = func->findOneChild<PDBSymbolFuncDebugStart>();
Zachary Turner7e8c7be2016-03-10 00:06:26 +0000682 is_prologue = (addr == prologue->getVirtualAddress());
683
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000684 auto epilogue = func->findOneChild<PDBSymbolFuncDebugEnd>();
Zachary Turner7e8c7be2016-03-10 00:06:26 +0000685 is_epilogue = (addr == epilogue->getVirtualAddress());
686 }
687
688 line_table->AppendLineEntryToSequence(sequence.get(), addr, lno, col, source_idx, is_statement, false,
689 is_prologue, is_epilogue, false);
690 }
691
692 prev_addr = addr;
693 prev_length = length;
694 prev_line = lno;
695 prev_source_idx = source_idx;
Zachary Turner74e08ca2016-03-02 22:05:52 +0000696 }
Zachary Turner7e8c7be2016-03-10 00:06:26 +0000697
698 if (entry_count > 0 && ShouldAddLine(match_line, prev_line, prev_length))
699 {
700 // The end is always a terminal entry, so insert it regardless.
701 line_table->AppendLineEntryToSequence(sequence.get(), prev_addr + prev_length, prev_line, 0,
702 prev_source_idx, false, false, false, false, true);
703 }
704
705 line_table->InsertSequence(sequence.release());
Zachary Turner74e08ca2016-03-02 22:05:52 +0000706 }
707
708 sc.comp_unit->SetLineTable(line_table.release());
709 return true;
710}
711
712void
Zachary Turner54fd7ff2016-05-04 20:33:53 +0000713SymbolFilePDB::BuildSupportFileIdToSupportFileIndexMap(const PDBSymbolCompiland &cu,
Zachary Turner42dff792016-04-15 00:21:26 +0000714 llvm::DenseMap<uint32_t, uint32_t> &index_map) const
Zachary Turner74e08ca2016-03-02 22:05:52 +0000715{
716 // This is a hack, but we need to convert the source id into an index into the support
717 // files array. We don't want to do path comparisons to avoid basename / full path
718 // issues that may or may not even be a problem, so we use the globally unique source
719 // file identifiers. Ideally we could use the global identifiers everywhere, but LineEntry
720 // currently assumes indices.
721 auto source_files = m_session_up->getSourceFilesForCompiland(cu);
722 int index = 0;
723
724 while (auto file = source_files->getNext())
725 {
726 uint32_t source_id = file->getUniqueId();
727 index_map[source_id] = index++;
728 }
729}