diff --git a/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/CMakeLists.txt --- a/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(Breakpad) add_subdirectory(ELF) add_subdirectory(Mach-O) +add_subdirectory(PDB) add_subdirectory(PECOFF) add_subdirectory(JIT) add_subdirectory(wasm) diff --git a/lldb/source/Plugins/ObjectFile/PDB/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/PDB/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/PDB/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginObjectFilePDB PLUGIN + ObjectFilePDB.cpp + + LINK_LIBS + lldbCore + lldbSymbol + lldbUtility + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.h b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.h @@ -0,0 +1,107 @@ +//===-- ObjectFilePDB.h --------------------------------------- -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_PDB_OBJECTFILEPDB_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_PDB_OBJECTFILEPDB_H + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +namespace lldb_private { + +class ObjectFilePDB : public ObjectFile { +public: + // Static Functions + static void Initialize(); + static void Terminate(); + + static ConstString GetPluginNameStatic(); + static const char *GetPluginDescriptionStatic() { + return "PDB object file reader."; + } + + static std::unique_ptr + loadPDBFile(std::string PdbPath, llvm::BumpPtrAllocator &Allocator); + + static ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static ObjectFile *CreateMemoryInstance(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + ModuleSpecList &specs); + + // PluginInterface protocol + ConstString GetPluginName() override { return GetPluginNameStatic(); } + + uint32_t GetPluginVersion() override { return 1; } + + // LLVM RTTI support + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + + // ObjectFile Protocol. + uint32_t GetAddressByteSize() const override { return 8; } + + lldb::ByteOrder GetByteOrder() const override { + return lldb::eByteOrderLittle; + } + + bool ParseHeader() override { return true; } + + bool IsExecutable() const override { return false; } + + Symtab *GetSymtab() override { return nullptr; } + + bool IsStripped() override { return false; } + + // No section in PDB file. + void CreateSections(SectionList &unified_section_list) override {} + + void Dump(Stream *s) override {} + + ArchSpec GetArchitecture() override; + + UUID GetUUID() override { return m_uuid; } + + uint32_t GetDependentModules(FileSpecList &files) override { return 0; } + + Type CalculateType() override { return eTypeDebugInfo; } + + Strata CalculateStrata() override { return eStrataUser; } + + llvm::pdb::PDBFile &GetPDBFile() { return *m_file_up; } + + ObjectFilePDB(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + +private: + UUID m_uuid; + llvm::BumpPtrAllocator m_allocator; + std::unique_ptr m_file_up; + + bool initPDBFile(); +}; + +} // namespace lldb_private +#endif // LLDB_PLUGINS_OBJECTFILE_PDB_OBJECTFILEPDB_H diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -0,0 +1,229 @@ +//===-- ObjectFilePDB.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ObjectFilePDB.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Utility/StreamString.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/Support/BinaryByteStream.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm::pdb; +using namespace llvm::codeview; + +LLDB_PLUGIN_DEFINE(ObjectFilePDB) + +struct CVInfoPdb70 { + // 16-byte GUID + struct _Guid { + llvm::support::ulittle32_t Data1; + llvm::support::ulittle16_t Data2; + llvm::support::ulittle16_t Data3; + uint8_t Data4[8]; + } Guid; + + llvm::support::ulittle32_t Age; +}; + +static UUID GetPDBUUID(InfoStream &IS) { + // This part is similar with what has done in ObjectFilePECOFF. + using llvm::support::endian::read16be; + using llvm::support::endian::read32; + using llvm::support::endian::read32be; + + GUID guid = IS.getGuid(); + const uint8_t *guid_p = guid.Guid; + struct CVInfoPdb70 info; + info.Guid.Data1 = read32be(guid_p); + guid_p += 4; + info.Guid.Data2 = read16be(guid_p); + guid_p += 2; + info.Guid.Data3 = read16be(guid_p); + guid_p += 2; + memcpy(info.Guid.Data4, guid_p, 8); + + // Return 20-byte UUID if the Age is not zero + uint32_t age = IS.getAge(); + if (age) { + info.Age = read32(&age, llvm::support::big); + return UUID::fromOptionalData(&info, sizeof(info)); + } + // Otherwise return 16-byte GUID + return UUID::fromOptionalData(&info.Guid, sizeof(info.Guid)); +} + +char ObjectFilePDB::ID; + +void ObjectFilePDB::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFilePDB::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString ObjectFilePDB::GetPluginNameStatic() { + static ConstString g_name("pdb"); + return g_name; +} + +ArchSpec ObjectFilePDB::GetArchitecture() { + auto dbi_stream = m_file_up->getPDBDbiStream(); + if (!dbi_stream) { + llvm::consumeError(dbi_stream.takeError()); + return ArchSpec(); + } + + PDB_Machine machine = dbi_stream->getMachineType(); + switch (machine) { + default: + break; + case PDB_Machine::Amd64: + case PDB_Machine::x86: + case PDB_Machine::PowerPC: + case PDB_Machine::PowerPCFP: + case PDB_Machine::Arm: + case PDB_Machine::ArmNT: + case PDB_Machine::Thumb: + case PDB_Machine::Arm64: + ArchSpec arch; + arch.SetArchitecture(eArchTypeCOFF, static_cast(machine), + LLDB_INVALID_CPUTYPE); + return arch; + } + return ArchSpec(); +} + +bool ObjectFilePDB::initPDBFile() { + m_file_up = loadPDBFile(m_file.GetPath(), m_allocator); + if (!m_file_up) + return false; + auto info_stream = m_file_up->getPDBInfoStream(); + if (!info_stream) { + llvm::consumeError(info_stream.takeError()); + return false; + } + m_uuid = GetPDBUUID(*info_stream); + return true; +} + +ObjectFile * +ObjectFilePDB::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp, + offset_t data_offset, const FileSpec *file, + offset_t file_offset, offset_t length) { + auto objfile_up = std::make_unique( + module_sp, data_sp, data_offset, file, file_offset, length); + if (!objfile_up->initPDBFile()) + return nullptr; + return objfile_up.release(); +} + +ObjectFile *ObjectFilePDB::CreateMemoryInstance(const ModuleSP &module_sp, + DataBufferSP &data_sp, + const ProcessSP &process_sp, + addr_t header_addr) { + return nullptr; +} + +size_t ObjectFilePDB::GetModuleSpecifications( + const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, + offset_t file_offset, offset_t length, ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + ModuleSpec module_spec(file); + llvm::BumpPtrAllocator allocator; + std::unique_ptr pdb_file = loadPDBFile(file.GetPath(), allocator); + if (!pdb_file) + return initial_count; + + auto info_stream = pdb_file->getPDBInfoStream(); + if (!info_stream) { + llvm::consumeError(info_stream.takeError()); + return initial_count; + } + auto dbi_stream = pdb_file->getPDBDbiStream(); + if (!dbi_stream) { + llvm::consumeError(dbi_stream.takeError()); + return initial_count; + } + + lldb_private::UUID &uuid = module_spec.GetUUID(); + uuid = GetPDBUUID(*info_stream); + + ArchSpec &module_arch = module_spec.GetArchitecture(); + switch (dbi_stream->getMachineType()) { + case PDB_Machine::Amd64: + module_arch.SetTriple("x86_64-pc-windows"); + specs.Append(module_spec); + break; + case PDB_Machine::x86: + module_arch.SetTriple("i386-pc-windows"); + specs.Append(module_spec); + module_arch.SetTriple("i686-pc-windows"); + specs.Append(module_spec); + break; + case PDB_Machine::ArmNT: + module_arch.SetTriple("armv7-pc-windows"); + specs.Append(module_spec); + break; + case PDB_Machine::Arm64: + module_arch.SetTriple("aarch64-pc-windows"); + specs.Append(module_spec); + break; + default: + break; + } + + return specs.GetSize() - initial_count; +} + +ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, DataBufferSP &data_sp, + offset_t data_offset, const FileSpec *file, + offset_t offset, offset_t length) + : ObjectFile(module_sp, file, offset, length, data_sp, data_offset) {} + +std::unique_ptr +ObjectFilePDB::loadPDBFile(std::string PdbPath, + llvm::BumpPtrAllocator &Allocator) { + llvm::file_magic magic; + auto ec = llvm::identify_magic(PdbPath, magic); + if (ec || magic != llvm::file_magic::pdb) + return nullptr; + llvm::ErrorOr> ErrorOrBuffer = + llvm::MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); + if (!ErrorOrBuffer) + return nullptr; + std::unique_ptr Buffer = std::move(*ErrorOrBuffer); + + llvm::StringRef Path = Buffer->getBufferIdentifier(); + auto Stream = std::make_unique( + std::move(Buffer), llvm::support::little); + + auto File = std::make_unique(Path, std::move(Stream), Allocator); + if (auto EC = File->parseFileHeaders()) { + llvm::consumeError(std::move(EC)); + return nullptr; + } + if (auto EC = File->parseStreamData()) { + llvm::consumeError(std::move(EC)); + return nullptr; + } + + return File; +} diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -142,7 +142,6 @@ // Cache coff binary. if (!objfile_up->CreateBinary()) return nullptr; - return objfile_up.release(); } @@ -852,7 +851,6 @@ if (m_sections_up) return; m_sections_up = std::make_unique(); - ModuleSP module_sp(GetModule()); if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt --- a/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt +++ b/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt @@ -15,6 +15,7 @@ lldbSymbol lldbUtility lldbPluginTypeSystemClang + lldbPluginObjectFilePDB CLANG_LIBS clangAST clangLex diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h @@ -48,7 +48,7 @@ class PdbIndex { /// The underlying PDB file. - std::unique_ptr m_file; + llvm::pdb::PDBFile *m_file = nullptr; /// The DBI stream. This contains general high level information about the /// features present in the PDB file, compile units (such as the information @@ -110,8 +110,7 @@ void BuildAddrToSymbolMap(CompilandIndexItem &cci); public: - static llvm::Expected> - create(std::unique_ptr); + static llvm::Expected> create(llvm::pdb::PDBFile *); void SetLoadAddress(lldb::addr_t addr) { m_load_address = addr; } lldb::addr_t GetLoadAddress() const { return m_load_address; } diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp @@ -39,7 +39,7 @@ } llvm::Expected> -PdbIndex::create(std::unique_ptr file) { +PdbIndex::create(llvm::pdb::PDBFile *file) { lldbassert(file); std::unique_ptr result(new PdbIndex()); @@ -53,7 +53,7 @@ result->m_tpi->buildHashMap(); - result->m_file = std::move(file); + result->m_file = file; return std::move(result); } diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -231,6 +231,7 @@ lldb::addr_t m_obj_load_address = 0; bool m_done_full_type_scan = false; + std::unique_ptr m_file_up; std::unique_ptr m_index; std::unique_ptr m_ast; diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -16,6 +16,7 @@ #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" +#include "Plugins/ObjectFile/PDB/ObjectFilePDB.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" @@ -42,9 +43,11 @@ #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/Demangle/MicrosoftDemangle.h" #include "llvm/Object/COFF.h" @@ -81,32 +84,6 @@ } } -static std::unique_ptr loadPDBFile(std::string PdbPath, - llvm::BumpPtrAllocator &Allocator) { - llvm::ErrorOr> ErrorOrBuffer = - llvm::MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1, - /*RequiresNullTerminator=*/false); - if (!ErrorOrBuffer) - return nullptr; - std::unique_ptr Buffer = std::move(*ErrorOrBuffer); - - llvm::StringRef Path = Buffer->getBufferIdentifier(); - auto Stream = std::make_unique( - std::move(Buffer), llvm::support::little); - - auto File = std::make_unique(Path, std::move(Stream), Allocator); - if (auto EC = File->parseFileHeaders()) { - llvm::consumeError(std::move(EC)); - return nullptr; - } - if (auto EC = File->parseStreamData()) { - llvm::consumeError(std::move(EC)); - return nullptr; - } - - return File; -} - static std::unique_ptr loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) { // Try to find a matching PDB for an EXE. @@ -144,11 +121,7 @@ } // If the file is not a PDB or if it doesn't have a matching GUID, fail. - llvm::file_magic magic; - auto ec = llvm::identify_magic(pdb_file, magic); - if (ec || magic != llvm::file_magic::pdb) - return nullptr; - std::unique_ptr pdb = loadPDBFile(std::string(pdb_file), allocator); + auto pdb = ObjectFilePDB::loadPDBFile(std::string(pdb_file), allocator); if (!pdb) return nullptr; @@ -292,24 +265,19 @@ if (!m_index) { // Lazily load and match the PDB file, but only do this once. - std::unique_ptr file_up = - loadMatchingPDBFile(m_objfile_sp->GetFileSpec().GetPath(), m_allocator); - - if (!file_up) { - auto module_sp = m_objfile_sp->GetModule(); - if (!module_sp) - return 0; - // See if any symbol file is specified through `--symfile` option. - FileSpec symfile = module_sp->GetSymbolFileFileSpec(); - if (!symfile) - return 0; - file_up = loadPDBFile(symfile.GetPath(), m_allocator); + PDBFile *pdb_file; + if (auto *pdb = llvm::dyn_cast(m_objfile_sp.get())) { + pdb_file = &pdb->GetPDBFile(); + } else { + m_file_up = loadMatchingPDBFile(m_objfile_sp->GetFileSpec().GetPath(), + m_allocator); + pdb_file = m_file_up.get(); } - if (!file_up) + if (!pdb_file) return 0; - auto expected_index = PdbIndex::create(std::move(file_up)); + auto expected_index = PdbIndex::create(pdb_file); if (!expected_index) { llvm::consumeError(expected_index.takeError()); return 0; @@ -329,7 +297,10 @@ } void SymbolFileNativePDB::InitializeObject() { - m_obj_load_address = m_objfile_sp->GetBaseAddress().GetFileAddress(); + m_obj_load_address = m_objfile_sp->GetModule() + ->GetObjectFile() + ->GetBaseAddress() + .GetFileAddress(); m_index->SetLoadAddress(m_obj_load_address); m_index->ParseSectionContribs(); diff --git a/lldb/test/Shell/ObjectFile/PDB/object.test b/lldb/test/Shell/ObjectFile/PDB/object.test new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/ObjectFile/PDB/object.test @@ -0,0 +1,280 @@ +# RUN: llvm-pdbutil yaml2pdb %s -pdb=%t.pdb +# RUN: lldb-test object-file %t.pdb | FileCheck %s + +# CHECK: Plugin name: pdb +# CHECK: Architecture: x86_64-pc-windows-msvc +# CHECK: UUID: 3F58AF61-A829-6C7A-4C4C-44205044422E-00000001 +# CHECK: Executable: false +# CHECK: Stripped: false +# CHECK: Type: debug info +# CHECK: Strata: user +# CHECK: Base VM address: 0xffffffffffffffff +# CHECK: There are no sections + +--- +MSF: + SuperBlock: + BlockSize: 4096 + FreeBlockMap: 2 + NumBlocks: 18 + NumDirectoryBytes: 116 + Unknown1: 0 + BlockMapAddr: 3 + NumDirectoryBlocks: 1 + DirectoryBlocks: [ 17 ] + NumStreams: 15 + FileSize: 73728 +StreamSizes: [ 0, 93, 100, 550, 136, 0, 544, 576, 40, 20, 120, 368, + 336, 49, 24 ] +StreamMap: + - Stream: [ ] + - Stream: [ 16 ] + - Stream: [ 7 ] + - Stream: [ 12 ] + - Stream: [ 14 ] + - Stream: [ ] + - Stream: [ 4 ] + - Stream: [ 5 ] + - Stream: [ 6 ] + - Stream: [ 8 ] + - Stream: [ 9 ] + - Stream: [ 10 ] + - Stream: [ 11 ] + - Stream: [ 13 ] + - Stream: [ 15 ] +StringTable: + - '/tmp/a.cpp' +PdbStream: + Age: 1 + Guid: '{61AF583F-29A8-7A6C-4C4C-44205044422E}' + Signature: 1062776673 + Features: [ VC140 ] + Version: VC70 +DbiStream: + VerHeader: V70 + Age: 1 + BuildNumber: 36363 + PdbDllVersion: 0 + PdbDllRbld: 0 + Flags: 0 + MachineType: Amd64 + Modules: + - Module: '/tmp/pdb.obj' + ObjFile: '/tmp/pdb.obj' + SourceFiles: + - '/tmp/a.cpp' + Subsections: + - !Lines + CodeSize: 28 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 1 + Blocks: + - FileName: '/tmp/a.cpp' + Lines: + - Offset: 0 + LineStart: 1 + IsStatement: false + EndDelta: 0 + - Offset: 23 + LineStart: 2 + IsStatement: false + EndDelta: 0 + Columns: [] + - !FileChecksums + Checksums: + - FileName: '/tmp/a.cpp' + Kind: MD5 + Checksum: DA1F9D293B90B487ADB2C711137770D3 + Modi: + Signature: 4 + Records: + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ ] + Machine: X64 + FrontendMajor: 12 + FrontendMinor: 0 + FrontendBuild: 0 + FrontendQFE: 0 + BackendMajor: 12000 + BackendMinor: 0 + BackendBuild: 0 + BackendQFE: 0 + Version: 'clang version 12.0.0 (git@github.com:llvm/llvm-project.git 8a08e08db6c2e4a5db485253f3186b0f9e739e15)' + - Kind: S_GPROC32 + ProcSym: + PtrParent: 0 + PtrEnd: 272 + PtrNext: 0 + CodeSize: 28 + DbgStart: 0 + DbgEnd: 0 + FunctionType: 4098 + Offset: 0 + Segment: 1 + Flags: [ ] + DisplayName: main + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 24 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ ] + - Kind: S_LOCAL + LocalSym: + Type: 116 + Flags: [ IsParameter ] + VarName: argc + - Kind: S_DEFRANGE_FRAMEPOINTER_REL + DefRangeFramePointerRelSym: + Offset: 4 + Range: + OffsetStart: 23 + ISectStart: 1 + Range: 5 + Gaps: [] + - Kind: S_LOCAL + LocalSym: + Type: 4096 + Flags: [ IsParameter ] + VarName: argv + - Kind: S_DEFRANGE_FRAMEPOINTER_REL + DefRangeFramePointerRelSym: + Offset: 8 + Range: + OffsetStart: 23 + ISectStart: 1 + Range: 5 + Gaps: [] + - Kind: S_END + ScopeEndSym: {} + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4099 + - Module: '* Linker *' + ObjFile: '' + Modi: + Signature: 4 + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: '* Linker *' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ ] + Machine: X64 + FrontendMajor: 0 + FrontendMinor: 0 + FrontendBuild: 0 + FrontendQFE: 0 + BackendMajor: 14 + BackendMinor: 10 + BackendBuild: 25019 + BackendQFE: 0 + Version: LLVM Linker + - Kind: S_ENVBLOCK + EnvBlockSym: + Entries: + - cwd + - '/tmp' + - exe + - '/tmp/lld-link' + - pdb + - '/tmp/a.pdb' + - cmd + - '/out:a.exe -debug pdb.obj /nodefaultlib /entry:main' + - Kind: S_SECTION + SectionSym: + SectionNumber: 1 + Alignment: 12 + Rva: 4096 + Length: 28 + Characteristics: 1610612768 + Name: .text + - Kind: S_COFFGROUP + CoffGroupSym: + Size: 28 + Characteristics: 1610612768 + Offset: 0 + Segment: 1 + Name: .text + - Kind: S_SECTION + SectionSym: + SectionNumber: 2 + Alignment: 12 + Rva: 8192 + Length: 72 + Characteristics: 1073741888 + Name: .rdata + - Kind: S_COFFGROUP + CoffGroupSym: + Size: 8 + Characteristics: 1073741888 + Offset: 64 + Segment: 2 + Name: .xdata + - Kind: S_SECTION + SectionSym: + SectionNumber: 3 + Alignment: 12 + Rva: 12288 + Length: 12 + Characteristics: 1073741888 + Name: .pdata + - Kind: S_COFFGROUP + CoffGroupSym: + Size: 12 + Characteristics: 1073741888 + Offset: 0 + Segment: 3 + Name: .pdata +TpiStream: + Version: VC80 + Records: + - Kind: LF_POINTER + Pointer: + ReferentType: 1648 + Attrs: 65548 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116, 4096 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 2 + ArgumentList: 4097 +IpiStream: + Version: VC80 + Records: + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4098 + Name: main + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '/tmp' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: a.cpp + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4097, 0, 4098, 0, 0 ] +PublicsStream: + Records: + - Kind: S_PUB32 + PublicSym32: + Flags: [ Function ] + Offset: 0 + Segment: 1 + Name: main +... diff --git a/lldb/test/Shell/SymbolFile/NativePDB/load-pdb.cpp b/lldb/test/Shell/SymbolFile/NativePDB/load-pdb.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/NativePDB/load-pdb.cpp @@ -0,0 +1,32 @@ +// clang-format off +// REQUIRES: lld, x86 + +// Test that lldb load PDB file by command `target symbols add` + +// RUN: mkdir -p %t/executable +// RUN: rm -f %t/executable/foo.exe %t/executable/bar.pdb +// RUN: %clang_cl --target=x86_64-windows-msvc -Od -Z7 -c /Fo%t/executable/foo.obj -- %s +// RUN: lld-link -debug:full -nodefaultlib -entry:main %t/executable/foo.obj \ +// RUN: -out:%t/executable/foo.exe -pdb:%t/executable/foo.pdb +// Rename the PDB file so that the name is different from the name inside the executable (foo.exe). +// RUN: mv %t/executable/foo.pdb %t/executable/bar.pdb +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb %t/executable/foo.exe \ +// RUN: -o "target symbols add %t/executable/bar.pdb" \ +// RUN: -o "b main" \ +// RUN: -o "image dump symfile" -o "quit" | FileCheck %s + +int main(int argc, char** argv) { + return 0; +} + +// CHECK: (lldb) target symbols add {{.*}}bar.pdb +// CHECK: symbol file '{{.*}}/bar.pdb' has been added to '{{.*}}/foo.exe' +// CHECK: (lldb) b main +// CHECK: Breakpoint 1: where = foo.exe`main + 23 at load-pdb.cpp:19, address = 0x0000000140001017 +// CHECK: (lldb) image dump symfile +// CHECK: Types: +// CHECK: {{.*}}: Type{0x00010024} , size = 0, compiler_type = {{.*}} int (int, char **) +// CHECK: Compile units: +// CHECK: {{.*}}: CompileUnit{0x00000000}, language = "c++", file = '{{.*}}/load-pdb.cpp' +// CHECK: {{.*}}: Function{0x08400001}, demangled = main, type = {{.*}} +// CHECK: {{.*}}: Block{0x08400001}