aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/SymbolFile/NativePDB
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/SymbolFile/NativePDB')
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp19
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h13
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp4
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h1
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp521
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h33
6 files changed, 496 insertions, 95 deletions
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
index 9f09c0accc87..d8f737612c25 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
@@ -106,6 +106,24 @@ static void ParseExtendedInfo(PdbIndex &index, CompilandIndexItem &item) {
}
}
+static void ParseInlineeLineTableForCompileUnit(CompilandIndexItem &item) {
+ for (const auto &ss : item.m_debug_stream.getSubsectionsArray()) {
+ if (ss.kind() != DebugSubsectionKind::InlineeLines)
+ continue;
+
+ DebugInlineeLinesSubsectionRef inlinee_lines;
+ llvm::BinaryStreamReader reader(ss.getRecordData());
+ if (llvm::Error error = inlinee_lines.initialize(reader)) {
+ consumeError(std::move(error));
+ continue;
+ }
+
+ for (const InlineeSourceLine &Line : inlinee_lines) {
+ item.m_inline_map[Line.Header->Inlinee] = Line;
+ }
+ }
+}
+
CompilandIndexItem::CompilandIndexItem(
PdbCompilandId id, llvm::pdb::ModuleDebugStreamRef debug_stream,
llvm::pdb::DbiModuleDescriptor descriptor)
@@ -142,6 +160,7 @@ CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) {
cci = std::make_unique<CompilandIndexItem>(
PdbCompilandId{modi}, std::move(debug_stream), std::move(descriptor));
ParseExtendedInfo(m_index, *cci);
+ ParseInlineeLineTableForCompileUnit(*cci);
cci->m_strings.initialize(debug_stream.getSubsectionsArray());
PDBStringTable &strings = cantFail(m_index.pdb().getStringTable());
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
index 088de970cbf3..4ad27de98695 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
@@ -9,10 +9,12 @@
#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_COMPILEUNITINDEX_H
#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_COMPILEUNITINDEX_H
+#include "lldb/Utility/RangeMap.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/IntervalMap.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
@@ -69,6 +71,17 @@ struct CompilandIndexItem {
// command line, etc. This usually contains exactly 5 items which
// are references to other strings.
llvm::SmallVector<llvm::codeview::TypeIndex, 5> m_build_info;
+
+ // Inlinee lines table in this compile unit.
+ std::map<llvm::codeview::TypeIndex, llvm::codeview::InlineeSourceLine>
+ m_inline_map;
+
+ // It's the line table parsed from DEBUG_S_LINES sections, mapping the file
+ // address range to file index and source line number.
+ using GlobalLineTable =
+ lldb_private::RangeDataVector<lldb::addr_t, uint32_t,
+ std::pair<uint32_t, uint32_t>>;
+ GlobalLineTable m_global_line_table;
};
/// Indexes information about all compile units. This is really just a map of
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index 9473befa6cc3..dc0969a0ce7c 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -1081,7 +1081,7 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
clang::FunctionDecl *function_decl = nullptr;
if (parent->isRecord()) {
- clang::QualType parent_qt = llvm::dyn_cast<clang::TypeDecl>(parent)
+ clang::QualType parent_qt = llvm::cast<clang::TypeDecl>(parent)
->getTypeForDecl()
->getCanonicalTypeInternal();
lldb::opaque_compiler_type_t parent_opaque_ty =
@@ -1318,7 +1318,7 @@ void PdbAstBuilder::ParseAllNamespacesPlusChildrenOf(
if (!context->isNamespace())
continue;
- clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(context);
+ clang::NamespaceDecl *ns = llvm::cast<clang::NamespaceDecl>(context);
std::string actual_ns = ns->getQualifiedNameAsString();
if (llvm::StringRef(actual_ns).startswith(*parent)) {
clang::QualType qt = GetOrCreateType(tid);
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
index 1b382e5263c1..edbdd9ee290b 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
@@ -25,7 +25,6 @@ namespace llvm {
namespace pdb {
class DbiStream;
class TpiStream;
-class TpiStream;
class InfoStream;
class PublicsStream;
class GlobalsStream;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index e859b1d5a86c..a035a791f868 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -330,31 +330,65 @@ uint32_t SymbolFileNativePDB::CalculateNumCompileUnits() {
Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) {
CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi);
CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset);
+ CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
+ lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id);
+ BlockSP child_block = std::make_shared<Block>(opaque_block_uid);
- if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32) {
- // This is a function. It must be global. Creating the Function entry for
- // it automatically creates a block for it.
- CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
- return GetOrCreateFunction(block_id, *comp_unit)->GetBlock(false);
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32: {
+ // This is a function. It must be global. Creating the Function entry
+ // for it automatically creates a block for it.
+ FunctionSP func = GetOrCreateFunction(block_id, *comp_unit);
+ Block &block = func->GetBlock(false);
+ if (block.GetNumRanges() == 0)
+ block.AddRange(Block::Range(0, func->GetAddressRange().GetByteSize()));
+ return block;
+ }
+ case S_BLOCK32: {
+ // This is a block. Its parent is either a function or another block. In
+ // either case, its parent can be viewed as a block (e.g. a function
+ // contains 1 big block. So just get the parent block and add this block
+ // to it.
+ BlockSym block(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<BlockSym>(sym, block));
+ lldbassert(block.Parent != 0);
+ PdbCompilandSymId parent_id(block_id.modi, block.Parent);
+ Block &parent_block = GetOrCreateBlock(parent_id);
+ parent_block.AddChild(child_block);
+ m_ast->GetOrCreateBlockDecl(block_id);
+ m_blocks.insert({opaque_block_uid, child_block});
+ break;
}
+ case S_INLINESITE: {
+ // This ensures line table is parsed first so we have inline sites info.
+ comp_unit->GetLineTable();
- lldbassert(sym.kind() == S_BLOCK32);
+ std::shared_ptr<InlineSite> inline_site = m_inline_sites[opaque_block_uid];
+ Block &parent_block = GetOrCreateBlock(inline_site->parent_id);
+ parent_block.AddChild(child_block);
- // This is a block. Its parent is either a function or another block. In
- // either case, its parent can be viewed as a block (e.g. a function contains
- // 1 big block. So just get the parent block and add this block to it.
- BlockSym block(static_cast<SymbolRecordKind>(sym.kind()));
- cantFail(SymbolDeserializer::deserializeAs<BlockSym>(sym, block));
- lldbassert(block.Parent != 0);
- PdbCompilandSymId parent_id(block_id.modi, block.Parent);
- Block &parent_block = GetOrCreateBlock(parent_id);
- lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id);
- BlockSP child_block = std::make_shared<Block>(opaque_block_uid);
- parent_block.AddChild(child_block);
+ // Copy ranges from InlineSite to Block.
+ for (size_t i = 0; i < inline_site->ranges.GetSize(); ++i) {
+ auto *entry = inline_site->ranges.GetEntryAtIndex(i);
+ child_block->AddRange(
+ Block::Range(entry->GetRangeBase(), entry->GetByteSize()));
+ }
+ child_block->FinalizeRanges();
- m_ast->GetOrCreateBlockDecl(block_id);
+ // Get the inlined function callsite info.
+ Declaration &decl = inline_site->inline_function_info->GetDeclaration();
+ Declaration &callsite = inline_site->inline_function_info->GetCallSite();
+ child_block->SetInlinedFunctionInfo(
+ inline_site->inline_function_info->GetName().GetCString(), nullptr,
+ &decl, &callsite);
+ m_blocks.insert({opaque_block_uid, child_block});
+ break;
+ }
+ default:
+ lldbassert(false && "Symbol is not a block!");
+ }
- m_blocks.insert({opaque_block_uid, child_block});
return *child_block;
}
@@ -971,16 +1005,22 @@ uint32_t SymbolFileNativePDB::ResolveSymbolContext(
continue;
if (type == PDB_SymType::Function) {
sc.function = GetOrCreateFunction(csid, *sc.comp_unit).get();
- sc.block = sc.GetFunctionBlock();
+ Block &block = sc.function->GetBlock(true);
+ addr_t func_base =
+ sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+ addr_t offset = file_addr - func_base;
+ sc.block = block.FindInnermostBlockByOffset(offset);
}
if (type == PDB_SymType::Block) {
sc.block = &GetOrCreateBlock(csid);
sc.function = sc.block->CalculateSymbolContextFunction();
}
- resolved_flags |= eSymbolContextFunction;
- resolved_flags |= eSymbolContextBlock;
- break;
+ if (sc.function)
+ resolved_flags |= eSymbolContextFunction;
+ if (sc.block)
+ resolved_flags |= eSymbolContextBlock;
+ break;
}
}
@@ -998,43 +1038,24 @@ uint32_t SymbolFileNativePDB::ResolveSymbolContext(
uint32_t SymbolFileNativePDB::ResolveSymbolContext(
const SourceLocationSpec &src_location_spec,
lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
- return 0;
-}
-
-static void AppendLineEntryToSequence(LineTable &table, LineSequence &sequence,
- const CompilandIndexItem &cci,
- lldb::addr_t base_addr,
- uint32_t file_number,
- const LineFragmentHeader &block,
- const LineNumberEntry &cur) {
- LineInfo cur_info(cur.Flags);
-
- if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto())
- return;
-
- uint64_t addr = base_addr + cur.Offset;
-
- bool is_statement = cur_info.isStatement();
- bool is_prologue = IsFunctionPrologue(cci, addr);
- bool is_epilogue = IsFunctionEpilogue(cci, addr);
-
- uint32_t lno = cur_info.getStartLine();
-
- table.AppendLineEntryToSequence(&sequence, addr, lno, 0, file_number,
- is_statement, false, is_prologue, is_epilogue,
- false);
-}
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ const uint32_t prev_size = sc_list.GetSize();
+ if (resolve_scope & eSymbolContextCompUnit) {
+ for (uint32_t cu_idx = 0, num_cus = GetNumCompileUnits(); cu_idx < num_cus;
+ ++cu_idx) {
+ CompileUnit *cu = ParseCompileUnitAtIndex(cu_idx).get();
+ if (!cu)
+ continue;
-static void TerminateLineSequence(LineTable &table,
- const LineFragmentHeader &block,
- lldb::addr_t base_addr, uint32_t file_number,
- uint32_t last_line,
- std::unique_ptr<LineSequence> seq) {
- // The end is always a terminal entry, so insert it regardless.
- table.AppendLineEntryToSequence(seq.get(), base_addr + block.CodeSize,
- last_line, 0, file_number, false, false,
- false, false, true);
- table.InsertSequence(seq.get());
+ bool file_spec_matches_cu_file_spec = FileSpec::Match(
+ src_location_spec.GetFileSpec(), cu->GetPrimaryFile());
+ if (file_spec_matches_cu_file_spec) {
+ cu->ResolveSymbolContext(src_location_spec, resolve_scope, sc_list);
+ break;
+ }
+ }
+ }
+ return sc_list.GetSize() - prev_size;
}
bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {
@@ -1045,16 +1066,21 @@ bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
PdbSymUid cu_id(comp_unit.GetID());
lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);
- CompilandIndexItem *cci =
- m_index->compilands().GetCompiland(cu_id.asCompiland().modi);
- lldbassert(cci);
- auto line_table = std::make_unique<LineTable>(&comp_unit);
+ uint16_t modi = cu_id.asCompiland().modi;
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(modi);
+ lldbassert(cii);
+
+ // Parse DEBUG_S_LINES subsections first, then parse all S_INLINESITE records
+ // in this CU. Add line entries into the set first so that if there are line
+ // entries with same addres, the later is always more accurate than the
+ // former.
+ std::set<LineTable::Entry, LineTableEntryComparator> line_set;
// This is basically a copy of the .debug$S subsections from all original COFF
// object files merged together with address relocations applied. We are
// looking for all DEBUG_S_LINES subsections.
for (const DebugSubsectionRecord &dssr :
- cci->m_debug_stream.getSubsectionsArray()) {
+ cii->m_debug_stream.getSubsectionsArray()) {
if (dssr.kind() != DebugSubsectionKind::Lines)
continue;
@@ -1069,41 +1095,110 @@ bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {
uint64_t virtual_addr =
m_index->MakeVirtualAddress(lfh->RelocSegment, lfh->RelocOffset);
- const auto &checksums = cci->m_strings.checksums().getArray();
- const auto &strings = cci->m_strings.strings();
for (const LineColumnEntry &group : lines) {
- // Indices in this structure are actually offsets of records in the
- // DEBUG_S_FILECHECKSUMS subsection. Those entries then have an index
- // into the global PDB string table.
- auto iter = checksums.at(group.NameIndex);
- if (iter == checksums.end())
+ llvm::Expected<uint32_t> file_index_or_err =
+ GetFileIndex(*cii, group.NameIndex);
+ if (!file_index_or_err)
continue;
+ uint32_t file_index = file_index_or_err.get();
+ lldbassert(!group.LineNumbers.empty());
+ CompilandIndexItem::GlobalLineTable::Entry line_entry(
+ LLDB_INVALID_ADDRESS, 0);
+ for (const LineNumberEntry &entry : group.LineNumbers) {
+ LineInfo cur_info(entry.Flags);
- llvm::Expected<llvm::StringRef> efn =
- strings.getString(iter->FileNameOffset);
- if (!efn) {
- llvm::consumeError(efn.takeError());
- continue;
- }
+ if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto())
+ continue;
- // LLDB wants the index of the file in the list of support files.
- auto fn_iter = llvm::find(cci->m_file_list, *efn);
- lldbassert(fn_iter != cci->m_file_list.end());
- uint32_t file_index = std::distance(cci->m_file_list.begin(), fn_iter);
+ uint64_t addr = virtual_addr + entry.Offset;
- std::unique_ptr<LineSequence> sequence(
- line_table->CreateLineSequenceContainer());
- lldbassert(!group.LineNumbers.empty());
+ bool is_statement = cur_info.isStatement();
+ bool is_prologue = IsFunctionPrologue(*cii, addr);
+ bool is_epilogue = IsFunctionEpilogue(*cii, addr);
- for (const LineNumberEntry &entry : group.LineNumbers) {
- AppendLineEntryToSequence(*line_table, *sequence, *cci, virtual_addr,
- file_index, *lfh, entry);
+ uint32_t lno = cur_info.getStartLine();
+
+ line_set.emplace(addr, lno, 0, file_index, is_statement, false,
+ is_prologue, is_epilogue, false);
+
+ if (line_entry.GetRangeBase() != LLDB_INVALID_ADDRESS) {
+ line_entry.SetRangeEnd(addr);
+ cii->m_global_line_table.Append(line_entry);
+ }
+ line_entry.SetRangeBase(addr);
+ line_entry.data = {file_index, lno};
}
LineInfo last_line(group.LineNumbers.back().Flags);
- TerminateLineSequence(*line_table, *lfh, virtual_addr, file_index,
- last_line.getEndLine(), std::move(sequence));
+ line_set.emplace(virtual_addr + lfh->CodeSize, last_line.getEndLine(), 0,
+ file_index, false, false, false, false, true);
+
+ if (line_entry.GetRangeBase() != LLDB_INVALID_ADDRESS) {
+ line_entry.SetRangeEnd(virtual_addr + lfh->CodeSize);
+ cii->m_global_line_table.Append(line_entry);
+ }
+ }
+ }
+
+ cii->m_global_line_table.Sort();
+
+ // Parse all S_INLINESITE in this CU.
+ const CVSymbolArray &syms = cii->m_debug_stream.getSymbolArray();
+ for (auto iter = syms.begin(); iter != syms.end();) {
+ if (iter->kind() != S_LPROC32 && iter->kind() != S_GPROC32) {
+ ++iter;
+ continue;
}
+
+ uint32_t record_offset = iter.offset();
+ CVSymbol func_record =
+ cii->m_debug_stream.readSymbolAtOffset(record_offset);
+ SegmentOffsetLength sol = GetSegmentOffsetAndLength(func_record);
+ addr_t file_vm_addr = m_index->MakeVirtualAddress(sol.so);
+ AddressRange func_range(file_vm_addr, sol.length,
+ comp_unit.GetModule()->GetSectionList());
+ Address func_base = func_range.GetBaseAddress();
+ PdbCompilandSymId func_id{modi, record_offset};
+
+ // Iterate all S_INLINESITEs in the function.
+ auto parse_inline_sites = [&](SymbolKind kind, PdbCompilandSymId id) {
+ if (kind != S_INLINESITE)
+ return false;
+
+ ParseInlineSite(id, func_base);
+
+ for (const auto &line_entry :
+ m_inline_sites[toOpaqueUid(id)]->line_entries) {
+ // If line_entry is not terminal entry, remove previous line entry at
+ // the same address and insert new one. Terminal entry inside an inline
+ // site might not be terminal entry for its parent.
+ if (!line_entry.is_terminal_entry)
+ line_set.erase(line_entry);
+ line_set.insert(line_entry);
+ }
+ // No longer useful after adding to line_set.
+ m_inline_sites[toOpaqueUid(id)]->line_entries.clear();
+ return true;
+ };
+ ParseSymbolArrayInScope(func_id, parse_inline_sites);
+ // Jump to the end of the function record.
+ iter = syms.at(getScopeEndOffset(func_record));
+ }
+
+ cii->m_global_line_table.Clear();
+
+ // Add line entries in line_set to line_table.
+ auto line_table = std::make_unique<LineTable>(&comp_unit);
+ std::unique_ptr<LineSequence> sequence(
+ line_table->CreateLineSequenceContainer());
+ for (const auto &line_entry : line_set) {
+ line_table->AppendLineEntryToSequence(
+ sequence.get(), line_entry.file_addr, line_entry.line,
+ line_entry.column, line_entry.file_idx,
+ line_entry.is_start_of_statement, line_entry.is_start_of_basic_block,
+ line_entry.is_prologue_end, line_entry.is_epilogue_begin,
+ line_entry.is_terminal_entry);
}
+ line_table->InsertSequence(sequence.get());
if (line_table->GetSize() == 0)
return false;
@@ -1117,6 +1212,33 @@ bool SymbolFileNativePDB::ParseDebugMacros(CompileUnit &comp_unit) {
return false;
}
+llvm::Expected<uint32_t>
+SymbolFileNativePDB::GetFileIndex(const CompilandIndexItem &cii,
+ uint32_t file_id) {
+ auto index_iter = m_file_indexes.find(file_id);
+ if (index_iter != m_file_indexes.end())
+ return index_iter->getSecond();
+ const auto &checksums = cii.m_strings.checksums().getArray();
+ const auto &strings = cii.m_strings.strings();
+ // Indices in this structure are actually offsets of records in the
+ // DEBUG_S_FILECHECKSUMS subsection. Those entries then have an index
+ // into the global PDB string table.
+ auto iter = checksums.at(file_id);
+ if (iter == checksums.end())
+ return llvm::make_error<RawError>(raw_error_code::no_entry);
+
+ llvm::Expected<llvm::StringRef> efn = strings.getString(iter->FileNameOffset);
+ if (!efn) {
+ return efn.takeError();
+ }
+
+ // LLDB wants the index of the file in the list of support files.
+ auto fn_iter = llvm::find(cii.m_file_list, *efn);
+ lldbassert(fn_iter != cii.m_file_list.end());
+ m_file_indexes[file_id] = std::distance(cii.m_file_list.begin(), fn_iter);
+ return m_file_indexes[file_id];
+}
+
bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
@@ -1141,11 +1263,223 @@ bool SymbolFileNativePDB::ParseImportedModules(
return false;
}
+void SymbolFileNativePDB::ParseInlineSite(PdbCompilandSymId id,
+ Address func_addr) {
+ lldb::user_id_t opaque_uid = toOpaqueUid(id);
+ if (m_inline_sites.find(opaque_uid) != m_inline_sites.end())
+ return;
+
+ addr_t func_base = func_addr.GetFileAddress();
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(id.modi);
+ CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(id.offset);
+ CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
+
+ InlineSiteSym inline_site(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(sym, inline_site));
+ PdbCompilandSymId parent_id(id.modi, inline_site.Parent);
+
+ std::shared_ptr<InlineSite> inline_site_sp =
+ std::make_shared<InlineSite>(parent_id);
+
+ // Get the inlined function declaration info.
+ auto iter = cii->m_inline_map.find(inline_site.Inlinee);
+ if (iter == cii->m_inline_map.end())
+ return;
+ InlineeSourceLine inlinee_line = iter->second;
+
+ const FileSpecList &files = comp_unit->GetSupportFiles();
+ FileSpec decl_file;
+ llvm::Expected<uint32_t> file_index_or_err =
+ GetFileIndex(*cii, inlinee_line.Header->FileID);
+ if (!file_index_or_err)
+ return;
+ uint32_t decl_file_idx = file_index_or_err.get();
+ decl_file = files.GetFileSpecAtIndex(decl_file_idx);
+ uint32_t decl_line = inlinee_line.Header->SourceLineNum;
+ std::unique_ptr<Declaration> decl_up =
+ std::make_unique<Declaration>(decl_file, decl_line);
+
+ // Parse range and line info.
+ uint32_t code_offset = 0;
+ int32_t line_offset = 0;
+ bool has_base = false;
+ bool is_new_line_offset = false;
+
+ bool is_start_of_statement = false;
+ // The first instruction is the prologue end.
+ bool is_prologue_end = true;
+
+ auto change_code_offset = [&](uint32_t code_delta) {
+ if (has_base) {
+ inline_site_sp->ranges.Append(RangeSourceLineVector::Entry(
+ code_offset, code_delta, decl_line + line_offset));
+ is_prologue_end = false;
+ is_start_of_statement = false;
+ } else {
+ is_start_of_statement = true;
+ }
+ has_base = true;
+ code_offset += code_delta;
+
+ if (is_new_line_offset) {
+ LineTable::Entry line_entry(func_base + code_offset,
+ decl_line + line_offset, 0, decl_file_idx,
+ true, false, is_prologue_end, false, false);
+ inline_site_sp->line_entries.push_back(line_entry);
+ is_new_line_offset = false;
+ }
+ };
+ auto change_code_length = [&](uint32_t length) {
+ inline_site_sp->ranges.Append(RangeSourceLineVector::Entry(
+ code_offset, length, decl_line + line_offset));
+ has_base = false;
+
+ LineTable::Entry end_line_entry(func_base + code_offset + length,
+ decl_line + line_offset, 0, decl_file_idx,
+ false, false, false, false, true);
+ inline_site_sp->line_entries.push_back(end_line_entry);
+ };
+ auto change_line_offset = [&](int32_t line_delta) {
+ line_offset += line_delta;
+ if (has_base) {
+ LineTable::Entry line_entry(
+ func_base + code_offset, decl_line + line_offset, 0, decl_file_idx,
+ is_start_of_statement, false, is_prologue_end, false, false);
+ inline_site_sp->line_entries.push_back(line_entry);
+ } else {
+ // Add line entry in next call to change_code_offset.
+ is_new_line_offset = true;
+ }
+ };
+
+ for (auto &annot : inline_site.annotations()) {
+ switch (annot.OpCode) {
+ case BinaryAnnotationsOpCode::CodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
+ change_code_offset(annot.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeLineOffset:
+ change_line_offset(annot.S1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeLength:
+ change_code_length(annot.U1);
+ code_offset += annot.U1;
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
+ change_code_offset(annot.U1);
+ change_line_offset(annot.S1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
+ change_code_offset(annot.U2);
+ change_code_length(annot.U1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ inline_site_sp->ranges.Sort();
+ inline_site_sp->ranges.CombineConsecutiveEntriesWithEqualData();
+
+ // Get the inlined function callsite info.
+ std::unique_ptr<Declaration> callsite_up;
+ if (!inline_site_sp->ranges.IsEmpty()) {
+ auto *entry = inline_site_sp->ranges.GetEntryAtIndex(0);
+ addr_t base_offset = entry->GetRangeBase();
+ if (cii->m_debug_stream.readSymbolAtOffset(parent_id.offset).kind() ==
+ S_INLINESITE) {
+ // Its parent is another inline site, lookup parent site's range vector
+ // for callsite line.
+ ParseInlineSite(parent_id, func_base);
+ std::shared_ptr<InlineSite> parent_site =
+ m_inline_sites[toOpaqueUid(parent_id)];
+ FileSpec &parent_decl_file =
+ parent_site->inline_function_info->GetDeclaration().GetFile();
+ if (auto *parent_entry =
+ parent_site->ranges.FindEntryThatContains(base_offset)) {
+ callsite_up =
+ std::make_unique<Declaration>(parent_decl_file, parent_entry->data);
+ }
+ } else {
+ // Its parent is a function, lookup global line table for callsite.
+ if (auto *entry = cii->m_global_line_table.FindEntryThatContains(
+ func_base + base_offset)) {
+ const FileSpec &callsite_file =
+ files.GetFileSpecAtIndex(entry->data.first);
+ callsite_up =
+ std::make_unique<Declaration>(callsite_file, entry->data.second);
+ }
+ }
+ }
+
+ // Get the inlined function name.
+ CVType inlinee_cvt = m_index->ipi().getType(inline_site.Inlinee);
+ std::string inlinee_name;
+ if (inlinee_cvt.kind() == LF_MFUNC_ID) {
+ MemberFuncIdRecord mfr;
+ cantFail(
+ TypeDeserializer::deserializeAs<MemberFuncIdRecord>(inlinee_cvt, mfr));
+ LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
+ inlinee_name.append(std::string(types.getTypeName(mfr.ClassType)));
+ inlinee_name.append("::");
+ inlinee_name.append(mfr.getName().str());
+ } else if (inlinee_cvt.kind() == LF_FUNC_ID) {
+ FuncIdRecord fir;
+ cantFail(TypeDeserializer::deserializeAs<FuncIdRecord>(inlinee_cvt, fir));
+ TypeIndex parent_idx = fir.getParentScope();
+ if (!parent_idx.isNoneType()) {
+ LazyRandomTypeCollection &ids = m_index->ipi().typeCollection();
+ inlinee_name.append(std::string(ids.getTypeName(parent_idx)));
+ inlinee_name.append("::");
+ }
+ inlinee_name.append(fir.getName().str());
+ }
+ inline_site_sp->inline_function_info = std::make_shared<InlineFunctionInfo>(
+ inlinee_name.c_str(), llvm::StringRef(), decl_up.get(),
+ callsite_up.get());
+
+ m_inline_sites[opaque_uid] = inline_site_sp;
+}
+
size_t SymbolFileNativePDB::ParseBlocksRecursive(Function &func) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
- GetOrCreateBlock(PdbSymUid(func.GetID()).asCompilandSym());
- // FIXME: Parse child blocks
- return 1;
+ PdbCompilandSymId func_id = PdbSymUid(func.GetID()).asCompilandSym();
+ // After we iterate through inline sites inside the function, we already get
+ // all the info needed, removing from the map to save memory.
+ std::set<uint64_t> remove_uids;
+ auto parse_blocks = [&](SymbolKind kind, PdbCompilandSymId id) {
+ if (kind == S_GPROC32 || kind == S_LPROC32 || kind == S_BLOCK32 ||
+ kind == S_INLINESITE) {
+ GetOrCreateBlock(id);
+ if (kind == S_INLINESITE)
+ remove_uids.insert(toOpaqueUid(id));
+ return true;
+ }
+ return false;
+ };
+ size_t count = ParseSymbolArrayInScope(func_id, parse_blocks);
+ for (uint64_t uid : remove_uids) {
+ m_inline_sites.erase(uid);
+ }
+ return count;
+}
+
+size_t SymbolFileNativePDB::ParseSymbolArrayInScope(
+ PdbCompilandSymId parent_id,
+ llvm::function_ref<bool(SymbolKind, PdbCompilandSymId)> fn) {
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(parent_id.modi);
+ CVSymbolArray syms =
+ cii->m_debug_stream.getSymbolArrayForScope(parent_id.offset);
+
+ size_t count = 1;
+ for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
+ PdbCompilandSymId child_id(parent_id.modi, iter.offset());
+ if (fn(iter->kind(), child_id))
+ ++count;
+ }
+
+ return count;
}
void SymbolFileNativePDB::DumpClangAST(Stream &s) { m_ast->Dump(s); }
@@ -1396,6 +1730,9 @@ size_t SymbolFileNativePDB::ParseVariablesForBlock(PdbCompilandSymId block_id) {
}
case S_BLOCK32:
break;
+ case S_INLINESITE:
+ // TODO: Handle inline site case.
+ return 0;
default:
lldbassert(false && "Symbol is not a block!");
return 0;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index 56a5ec0a464d..f1b6e34ca346 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -9,6 +9,7 @@
#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
+#include "lldb/Symbol/LineTable.h"
#include "lldb/Symbol/SymbolFile.h"
#include "llvm/ADT/DenseMap.h"
@@ -161,6 +162,25 @@ public:
void DumpClangAST(Stream &s) override;
private:
+ struct LineTableEntryComparator {
+ bool operator()(const lldb_private::LineTable::Entry &lhs,
+ const lldb_private::LineTable::Entry &rhs) const {
+ return lhs.file_addr < rhs.file_addr;
+ }
+ };
+
+ // From address range relative to function base to source line number.
+ using RangeSourceLineVector =
+ lldb_private::RangeDataVector<uint32_t, uint32_t, int32_t>;
+ // InlineSite contains information in a S_INLINESITE record.
+ struct InlineSite {
+ PdbCompilandSymId parent_id;
+ std::shared_ptr<InlineFunctionInfo> inline_function_info;
+ RangeSourceLineVector ranges;
+ std::vector<lldb_private::LineTable::Entry> line_entries;
+ InlineSite(PdbCompilandSymId parent_id) : parent_id(parent_id){};
+ };
+
uint32_t CalculateNumCompileUnits() override;
lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
@@ -225,6 +245,16 @@ private:
VariableList &variables);
size_t ParseVariablesForBlock(PdbCompilandSymId block_id);
+ llvm::Expected<uint32_t> GetFileIndex(const CompilandIndexItem &cii,
+ uint32_t file_id);
+
+ size_t ParseSymbolArrayInScope(
+ PdbCompilandSymId parent,
+ llvm::function_ref<bool(llvm::codeview::SymbolKind, PdbCompilandSymId)>
+ fn);
+
+ void ParseInlineSite(PdbCompilandSymId inline_site_id, Address func_addr);
+
llvm::BumpPtrAllocator m_allocator;
lldb::addr_t m_obj_load_address = 0;
@@ -241,6 +271,9 @@ private:
llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions;
llvm::DenseMap<lldb::user_id_t, lldb::CompUnitSP> m_compilands;
llvm::DenseMap<lldb::user_id_t, lldb::TypeSP> m_types;
+ llvm::DenseMap<lldb::user_id_t, std::shared_ptr<InlineSite>> m_inline_sites;
+ // A map from file id in records to file index in support files.
+ llvm::DenseMap<uint32_t, uint32_t> m_file_indexes;
};
} // namespace npdb