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