diff options
Diffstat (limited to 'lldb/source/Plugins/SymbolFile/NativePDB')
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp | 122 | ||||
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp | 23 |
2 files changed, 117 insertions, 28 deletions
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index e76b7a3..3bf113a 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -86,6 +86,40 @@ static lldb::LanguageType TranslateLanguage(PDB_Lang lang) { } } +static std::optional<std::string> +findMatchingPDBFilePath(llvm::StringRef original_pdb_path, + llvm::StringRef exe_path) { + const FileSystem &fs = FileSystem::Instance(); + + if (fs.Exists(original_pdb_path)) + return std::string(original_pdb_path); + + const auto exe_dir = FileSpec(exe_path).CopyByRemovingLastPathComponent(); + // While the exe_path uses the native style, the exe might be compiled on a + // different OS, so try to guess the style used. + const FileSpec original_pdb_spec(original_pdb_path, + FileSpec::GuessPathStyle(original_pdb_path) + .value_or(FileSpec::Style::native)); + const llvm::StringRef pdb_filename = original_pdb_spec.GetFilename(); + + // If the file doesn't exist, perhaps the path specified at build time + // doesn't match the PDB's current location, so check the location of the + // executable. + const FileSpec local_pdb = exe_dir.CopyByAppendingPathComponent(pdb_filename); + if (fs.Exists(local_pdb)) + return local_pdb.GetPath(); + + // Otherwise, search for one in target.debug-file-search-paths + FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); + for (const FileSpec &search_dir : search_paths) { + FileSpec pdb_path = search_dir.CopyByAppendingPathComponent(pdb_filename); + if (fs.Exists(pdb_path)) + return pdb_path.GetPath(); + } + + return std::nullopt; +} + static std::unique_ptr<PDBFile> loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) { // Try to find a matching PDB for an EXE. @@ -113,17 +147,14 @@ loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) { return nullptr; } - // If the file doesn't exist, perhaps the path specified at build time - // doesn't match the PDB's current location, so check the location of the - // executable. - if (!FileSystem::Instance().Exists(pdb_file)) { - const auto exe_dir = FileSpec(exe_path).CopyByRemovingLastPathComponent(); - const auto pdb_name = FileSpec(pdb_file).GetFilename().GetCString(); - pdb_file = exe_dir.CopyByAppendingPathComponent(pdb_name).GetPathAsConstString().GetStringRef(); - } + std::optional<std::string> resolved_pdb_path = + findMatchingPDBFilePath(pdb_file, exe_path); + if (!resolved_pdb_path) + return nullptr; // If the file is not a PDB or if it doesn't have a matching GUID, fail. - auto pdb = ObjectFilePDB::loadPDBFile(std::string(pdb_file), allocator); + auto pdb = + ObjectFilePDB::loadPDBFile(*std::move(resolved_pdb_path), allocator); if (!pdb) return nullptr; @@ -137,6 +168,9 @@ loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) { if (expected_info->getGuid() != guid) return nullptr; + + LLDB_LOG(GetLog(LLDBLog::Symbols), "Loading {0} for {1}", pdb->getFilePath(), + exe_path); return pdb; } @@ -1126,11 +1160,40 @@ lldb::LanguageType SymbolFileNativePDB::ParseLanguage(CompileUnit &comp_unit) { } void SymbolFileNativePDB::AddSymbols(Symtab &symtab) { - auto *section_list = m_objfile_sp->GetSectionList(); + auto *section_list = + m_objfile_sp->GetModule()->GetObjectFile()->GetSectionList(); if (!section_list) return; - for (auto pid : m_index->publics().getPublicsTable()) { + PublicSym32 last_sym; + size_t last_sym_idx = 0; + lldb::SectionSP section_sp; + + // To estimate the size of a symbol, we use the difference to the next symbol. + // If there's no next symbol or the section/segment changed, the symbol will + // take the remaining space. The estimate can be too high in case there's + // padding between symbols. This similar to the algorithm used by the DIA + // SDK. + auto finish_last_symbol = [&](const PublicSym32 *next) { + if (!section_sp) + return; + Symbol *last = symtab.SymbolAtIndex(last_sym_idx); + if (!last) + return; + + if (next && last_sym.Segment == next->Segment) { + assert(last_sym.Offset <= next->Offset); + last->SetByteSize(next->Offset - last_sym.Offset); + } else { + // the last symbol was the last in its section + assert(section_sp->GetByteSize() >= last_sym.Offset); + assert(!next || next->Segment > last_sym.Segment); + last->SetByteSize(section_sp->GetByteSize() - last_sym.Offset); + } + }; + + // The address map is sorted by the address of a symbol. + for (auto pid : m_index->publics().getAddressMap()) { PdbGlobalSymId global{pid, true}; CVSymbol sym = m_index->ReadSymbolRecord(global); auto kind = sym.kind(); @@ -1138,8 +1201,11 @@ void SymbolFileNativePDB::AddSymbols(Symtab &symtab) { continue; PublicSym32 pub = llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(sym)); + finish_last_symbol(&pub); + + if (!section_sp || last_sym.Segment != pub.Segment) + section_sp = section_list->FindSectionByID(pub.Segment); - auto section_sp = section_list->FindSectionByID(pub.Segment); if (!section_sp) continue; @@ -1148,20 +1214,24 @@ void SymbolFileNativePDB::AddSymbols(Symtab &symtab) { (pub.Flags & PublicSymFlags::Code) != PublicSymFlags::None) type = eSymbolTypeCode; - symtab.AddSymbol(Symbol(/*symID=*/pid, - /*name=*/pub.Name, - /*type=*/type, - /*external=*/true, - /*is_debug=*/true, - /*is_trampoline=*/false, - /*is_artificial=*/false, - /*section_sp=*/section_sp, - /*value=*/pub.Offset, - /*size=*/0, - /*size_is_valid=*/false, - /*contains_linker_annotations=*/false, - /*flags=*/0)); - } + last_sym_idx = + symtab.AddSymbol(Symbol(/*symID=*/pid, + /*name=*/pub.Name, + /*type=*/type, + /*external=*/true, + /*is_debug=*/true, + /*is_trampoline=*/false, + /*is_artificial=*/false, + /*section_sp=*/section_sp, + /*value=*/pub.Offset, + /*size=*/0, + /*size_is_valid=*/false, + /*contains_linker_annotations=*/false, + /*flags=*/0)); + last_sym = pub; + } + + finish_last_symbol(nullptr); } size_t SymbolFileNativePDB::ParseFunctions(CompileUnit &comp_unit) { diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp index 1c575e9..46cf9b8 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -442,6 +442,10 @@ void UdtRecordCompleter::Record::ConstructRecord() { // The end offset to a vector of field/struct that ends at the offset. std::map<uint64_t, std::vector<Member *>> end_offset_map; + auto is_last_end_offset = [&](auto it) { + return it != end_offset_map.end() && ++it == end_offset_map.end(); + }; + for (auto &pair : fields_map) { uint64_t offset = pair.first; auto &fields = pair.second; @@ -462,8 +466,23 @@ void UdtRecordCompleter::Record::ConstructRecord() { } if (iter->second.empty()) continue; - parent = iter->second.back(); - iter->second.pop_back(); + + // If the new fields come after the already added ones + // without overlap, go back to the root. + if (iter->first <= offset && is_last_end_offset(iter)) { + if (record.kind == Member::Struct) { + parent = &record; + } else { + assert(record.kind == Member::Union && + "Current record must be a union"); + assert(!record.fields.empty()); + // For unions, append the field to the last struct + parent = record.fields.back().get(); + } + } else { + parent = iter->second.back(); + iter->second.pop_back(); + } } // If it's a field, then the field is inside a union, so we can safely // increase its size by converting it to a struct to hold multiple fields. |
