1b60736ecSDimitry Andric //===-- ObjectFilePDB.cpp -------------------------------------------------===//
2b60736ecSDimitry Andric //
3b60736ecSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b60736ecSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5b60736ecSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b60736ecSDimitry Andric //
7b60736ecSDimitry Andric //===----------------------------------------------------------------------===//
8b60736ecSDimitry Andric
9b60736ecSDimitry Andric #include "ObjectFilePDB.h"
10b60736ecSDimitry Andric #include "lldb/Core/Module.h"
11b60736ecSDimitry Andric #include "lldb/Core/ModuleSpec.h"
12b60736ecSDimitry Andric #include "lldb/Core/PluginManager.h"
13b60736ecSDimitry Andric #include "lldb/Core/Section.h"
14b60736ecSDimitry Andric #include "lldb/Utility/StreamString.h"
15b60736ecSDimitry Andric #include "llvm/BinaryFormat/Magic.h"
16b60736ecSDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
17b60736ecSDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
18b60736ecSDimitry Andric #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
19b60736ecSDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
20b60736ecSDimitry Andric #include "llvm/DebugInfo/PDB/PDB.h"
21b60736ecSDimitry Andric #include "llvm/Support/BinaryByteStream.h"
22b60736ecSDimitry Andric
23b60736ecSDimitry Andric using namespace lldb;
24b60736ecSDimitry Andric using namespace lldb_private;
25b60736ecSDimitry Andric using namespace llvm::pdb;
26b60736ecSDimitry Andric using namespace llvm::codeview;
27b60736ecSDimitry Andric
LLDB_PLUGIN_DEFINE(ObjectFilePDB)28b60736ecSDimitry Andric LLDB_PLUGIN_DEFINE(ObjectFilePDB)
29b60736ecSDimitry Andric
307fa27ce4SDimitry Andric static UUID GetPDBUUID(InfoStream &IS, DbiStream &DS) {
31b60736ecSDimitry Andric UUID::CvRecordPdb70 debug_info;
32b60736ecSDimitry Andric memcpy(&debug_info.Uuid, IS.getGuid().Guid, sizeof(debug_info.Uuid));
337fa27ce4SDimitry Andric debug_info.Age = DS.getAge();
34e3b55780SDimitry Andric return UUID(debug_info);
35b60736ecSDimitry Andric }
36b60736ecSDimitry Andric
37b60736ecSDimitry Andric char ObjectFilePDB::ID;
38b60736ecSDimitry Andric
Initialize()39b60736ecSDimitry Andric void ObjectFilePDB::Initialize() {
40b60736ecSDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(),
41b60736ecSDimitry Andric GetPluginDescriptionStatic(), CreateInstance,
42b60736ecSDimitry Andric CreateMemoryInstance, GetModuleSpecifications);
43b60736ecSDimitry Andric }
44b60736ecSDimitry Andric
Terminate()45b60736ecSDimitry Andric void ObjectFilePDB::Terminate() {
46b60736ecSDimitry Andric PluginManager::UnregisterPlugin(CreateInstance);
47b60736ecSDimitry Andric }
48b60736ecSDimitry Andric
GetArchitecture()49b60736ecSDimitry Andric ArchSpec ObjectFilePDB::GetArchitecture() {
50b60736ecSDimitry Andric auto dbi_stream = m_file_up->getPDBDbiStream();
51b60736ecSDimitry Andric if (!dbi_stream) {
52b60736ecSDimitry Andric llvm::consumeError(dbi_stream.takeError());
53b60736ecSDimitry Andric return ArchSpec();
54b60736ecSDimitry Andric }
55b60736ecSDimitry Andric
56b60736ecSDimitry Andric PDB_Machine machine = dbi_stream->getMachineType();
57b60736ecSDimitry Andric switch (machine) {
58b60736ecSDimitry Andric default:
59b60736ecSDimitry Andric break;
60b60736ecSDimitry Andric case PDB_Machine::Amd64:
61b60736ecSDimitry Andric case PDB_Machine::x86:
62b60736ecSDimitry Andric case PDB_Machine::PowerPC:
63b60736ecSDimitry Andric case PDB_Machine::PowerPCFP:
64b60736ecSDimitry Andric case PDB_Machine::Arm:
65b60736ecSDimitry Andric case PDB_Machine::ArmNT:
66b60736ecSDimitry Andric case PDB_Machine::Thumb:
67b60736ecSDimitry Andric case PDB_Machine::Arm64:
68b60736ecSDimitry Andric ArchSpec arch;
69b60736ecSDimitry Andric arch.SetArchitecture(eArchTypeCOFF, static_cast<int>(machine),
70b60736ecSDimitry Andric LLDB_INVALID_CPUTYPE);
71b60736ecSDimitry Andric return arch;
72b60736ecSDimitry Andric }
73b60736ecSDimitry Andric return ArchSpec();
74b60736ecSDimitry Andric }
75b60736ecSDimitry Andric
initPDBFile()76b60736ecSDimitry Andric bool ObjectFilePDB::initPDBFile() {
77b60736ecSDimitry Andric m_file_up = loadPDBFile(m_file.GetPath(), m_allocator);
78b60736ecSDimitry Andric if (!m_file_up)
79b60736ecSDimitry Andric return false;
80b60736ecSDimitry Andric auto info_stream = m_file_up->getPDBInfoStream();
81b60736ecSDimitry Andric if (!info_stream) {
82b60736ecSDimitry Andric llvm::consumeError(info_stream.takeError());
83b60736ecSDimitry Andric return false;
84b60736ecSDimitry Andric }
857fa27ce4SDimitry Andric auto dbi_stream = m_file_up->getPDBDbiStream();
867fa27ce4SDimitry Andric if (!dbi_stream) {
877fa27ce4SDimitry Andric llvm::consumeError(dbi_stream.takeError());
887fa27ce4SDimitry Andric return false;
897fa27ce4SDimitry Andric }
907fa27ce4SDimitry Andric m_uuid = GetPDBUUID(*info_stream, *dbi_stream);
91b60736ecSDimitry Andric return true;
92b60736ecSDimitry Andric }
93b60736ecSDimitry Andric
94b60736ecSDimitry Andric ObjectFile *
CreateInstance(const ModuleSP & module_sp,DataBufferSP data_sp,offset_t data_offset,const FileSpec * file,offset_t file_offset,offset_t length)95145449b1SDimitry Andric ObjectFilePDB::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp,
96b60736ecSDimitry Andric offset_t data_offset, const FileSpec *file,
97b60736ecSDimitry Andric offset_t file_offset, offset_t length) {
98b60736ecSDimitry Andric auto objfile_up = std::make_unique<ObjectFilePDB>(
99b60736ecSDimitry Andric module_sp, data_sp, data_offset, file, file_offset, length);
100b60736ecSDimitry Andric if (!objfile_up->initPDBFile())
101b60736ecSDimitry Andric return nullptr;
102b60736ecSDimitry Andric return objfile_up.release();
103b60736ecSDimitry Andric }
104b60736ecSDimitry Andric
CreateMemoryInstance(const ModuleSP & module_sp,WritableDataBufferSP data_sp,const ProcessSP & process_sp,addr_t header_addr)105b60736ecSDimitry Andric ObjectFile *ObjectFilePDB::CreateMemoryInstance(const ModuleSP &module_sp,
106145449b1SDimitry Andric WritableDataBufferSP data_sp,
107b60736ecSDimitry Andric const ProcessSP &process_sp,
108b60736ecSDimitry Andric addr_t header_addr) {
109b60736ecSDimitry Andric return nullptr;
110b60736ecSDimitry Andric }
111b60736ecSDimitry Andric
GetModuleSpecifications(const FileSpec & file,DataBufferSP & data_sp,offset_t data_offset,offset_t file_offset,offset_t length,ModuleSpecList & specs)112b60736ecSDimitry Andric size_t ObjectFilePDB::GetModuleSpecifications(
113b60736ecSDimitry Andric const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
114b60736ecSDimitry Andric offset_t file_offset, offset_t length, ModuleSpecList &specs) {
115b60736ecSDimitry Andric const size_t initial_count = specs.GetSize();
116b60736ecSDimitry Andric ModuleSpec module_spec(file);
117b60736ecSDimitry Andric llvm::BumpPtrAllocator allocator;
118b60736ecSDimitry Andric std::unique_ptr<PDBFile> pdb_file = loadPDBFile(file.GetPath(), allocator);
119b60736ecSDimitry Andric if (!pdb_file)
120b60736ecSDimitry Andric return initial_count;
121b60736ecSDimitry Andric
122b60736ecSDimitry Andric auto info_stream = pdb_file->getPDBInfoStream();
123b60736ecSDimitry Andric if (!info_stream) {
124b60736ecSDimitry Andric llvm::consumeError(info_stream.takeError());
125b60736ecSDimitry Andric return initial_count;
126b60736ecSDimitry Andric }
127b60736ecSDimitry Andric auto dbi_stream = pdb_file->getPDBDbiStream();
128b60736ecSDimitry Andric if (!dbi_stream) {
129b60736ecSDimitry Andric llvm::consumeError(dbi_stream.takeError());
130b60736ecSDimitry Andric return initial_count;
131b60736ecSDimitry Andric }
132b60736ecSDimitry Andric
133b60736ecSDimitry Andric lldb_private::UUID &uuid = module_spec.GetUUID();
1347fa27ce4SDimitry Andric uuid = GetPDBUUID(*info_stream, *dbi_stream);
135b60736ecSDimitry Andric
136b60736ecSDimitry Andric ArchSpec &module_arch = module_spec.GetArchitecture();
137b60736ecSDimitry Andric switch (dbi_stream->getMachineType()) {
138b60736ecSDimitry Andric case PDB_Machine::Amd64:
139b60736ecSDimitry Andric module_arch.SetTriple("x86_64-pc-windows");
140b60736ecSDimitry Andric specs.Append(module_spec);
141b60736ecSDimitry Andric break;
142b60736ecSDimitry Andric case PDB_Machine::x86:
143b60736ecSDimitry Andric module_arch.SetTriple("i386-pc-windows");
144b60736ecSDimitry Andric specs.Append(module_spec);
145b60736ecSDimitry Andric break;
146b60736ecSDimitry Andric case PDB_Machine::ArmNT:
147b60736ecSDimitry Andric module_arch.SetTriple("armv7-pc-windows");
148b60736ecSDimitry Andric specs.Append(module_spec);
149b60736ecSDimitry Andric break;
150b60736ecSDimitry Andric case PDB_Machine::Arm64:
151b60736ecSDimitry Andric module_arch.SetTriple("aarch64-pc-windows");
152b60736ecSDimitry Andric specs.Append(module_spec);
153b60736ecSDimitry Andric break;
154b60736ecSDimitry Andric default:
155b60736ecSDimitry Andric break;
156b60736ecSDimitry Andric }
157b60736ecSDimitry Andric
158b60736ecSDimitry Andric return specs.GetSize() - initial_count;
159b60736ecSDimitry Andric }
160b60736ecSDimitry Andric
ObjectFilePDB(const ModuleSP & module_sp,DataBufferSP & data_sp,offset_t data_offset,const FileSpec * file,offset_t offset,offset_t length)161b60736ecSDimitry Andric ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, DataBufferSP &data_sp,
162b60736ecSDimitry Andric offset_t data_offset, const FileSpec *file,
163b60736ecSDimitry Andric offset_t offset, offset_t length)
164b60736ecSDimitry Andric : ObjectFile(module_sp, file, offset, length, data_sp, data_offset) {}
165b60736ecSDimitry Andric
166b60736ecSDimitry Andric std::unique_ptr<PDBFile>
loadPDBFile(std::string PdbPath,llvm::BumpPtrAllocator & Allocator)167b60736ecSDimitry Andric ObjectFilePDB::loadPDBFile(std::string PdbPath,
168b60736ecSDimitry Andric llvm::BumpPtrAllocator &Allocator) {
169b60736ecSDimitry Andric llvm::file_magic magic;
170b60736ecSDimitry Andric auto ec = llvm::identify_magic(PdbPath, magic);
171b60736ecSDimitry Andric if (ec || magic != llvm::file_magic::pdb)
172b60736ecSDimitry Andric return nullptr;
173b60736ecSDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer =
174344a3780SDimitry Andric llvm::MemoryBuffer::getFile(PdbPath, /*IsText=*/false,
175b60736ecSDimitry Andric /*RequiresNullTerminator=*/false);
176b60736ecSDimitry Andric if (!ErrorOrBuffer)
177b60736ecSDimitry Andric return nullptr;
178b60736ecSDimitry Andric std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
179b60736ecSDimitry Andric
180b60736ecSDimitry Andric llvm::StringRef Path = Buffer->getBufferIdentifier();
181b60736ecSDimitry Andric auto Stream = std::make_unique<llvm::MemoryBufferByteStream>(
182b1c73532SDimitry Andric std::move(Buffer), llvm::endianness::little);
183b60736ecSDimitry Andric
184b60736ecSDimitry Andric auto File = std::make_unique<PDBFile>(Path, std::move(Stream), Allocator);
185b60736ecSDimitry Andric if (auto EC = File->parseFileHeaders()) {
186b60736ecSDimitry Andric llvm::consumeError(std::move(EC));
187b60736ecSDimitry Andric return nullptr;
188b60736ecSDimitry Andric }
189b60736ecSDimitry Andric if (auto EC = File->parseStreamData()) {
190b60736ecSDimitry Andric llvm::consumeError(std::move(EC));
191b60736ecSDimitry Andric return nullptr;
192b60736ecSDimitry Andric }
193b60736ecSDimitry Andric
194b60736ecSDimitry Andric return File;
195b60736ecSDimitry Andric }
196