1242e1e99SZequan Wu //===-- ObjectFilePDB.cpp -------------------------------------------------===//
2242e1e99SZequan Wu //
3242e1e99SZequan Wu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4242e1e99SZequan Wu // See https://llvm.org/LICENSE.txt for license information.
5242e1e99SZequan Wu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6242e1e99SZequan Wu //
7242e1e99SZequan Wu //===----------------------------------------------------------------------===//
8242e1e99SZequan Wu 
9242e1e99SZequan Wu #include "ObjectFilePDB.h"
10242e1e99SZequan Wu #include "lldb/Core/Module.h"
11242e1e99SZequan Wu #include "lldb/Core/ModuleSpec.h"
12242e1e99SZequan Wu #include "lldb/Core/PluginManager.h"
13242e1e99SZequan Wu #include "lldb/Core/Section.h"
14242e1e99SZequan Wu #include "lldb/Utility/StreamString.h"
15242e1e99SZequan Wu #include "llvm/BinaryFormat/Magic.h"
16242e1e99SZequan Wu #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
17242e1e99SZequan Wu #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
18242e1e99SZequan Wu #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
19242e1e99SZequan Wu #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
20242e1e99SZequan Wu #include "llvm/DebugInfo/PDB/PDB.h"
21242e1e99SZequan Wu #include "llvm/Support/BinaryByteStream.h"
22242e1e99SZequan Wu 
23242e1e99SZequan Wu using namespace lldb;
24242e1e99SZequan Wu using namespace lldb_private;
25242e1e99SZequan Wu using namespace llvm::pdb;
26242e1e99SZequan Wu using namespace llvm::codeview;
27242e1e99SZequan Wu 
28242e1e99SZequan Wu LLDB_PLUGIN_DEFINE(ObjectFilePDB)
29242e1e99SZequan Wu 
30242e1e99SZequan Wu static UUID GetPDBUUID(InfoStream &IS) {
314348e0eeSZequan Wu   UUID::CvRecordPdb70 debug_info;
324348e0eeSZequan Wu   memcpy(&debug_info.Uuid, IS.getGuid().Guid, sizeof(debug_info.Uuid));
334348e0eeSZequan Wu   debug_info.Age = IS.getAge();
344348e0eeSZequan Wu   return UUID::fromCvRecord(debug_info);
35242e1e99SZequan Wu }
36242e1e99SZequan Wu 
37242e1e99SZequan Wu char ObjectFilePDB::ID;
38242e1e99SZequan Wu 
39242e1e99SZequan Wu void ObjectFilePDB::Initialize() {
40242e1e99SZequan Wu   PluginManager::RegisterPlugin(GetPluginNameStatic(),
41242e1e99SZequan Wu                                 GetPluginDescriptionStatic(), CreateInstance,
42242e1e99SZequan Wu                                 CreateMemoryInstance, GetModuleSpecifications);
43242e1e99SZequan Wu }
44242e1e99SZequan Wu 
45242e1e99SZequan Wu void ObjectFilePDB::Terminate() {
46242e1e99SZequan Wu   PluginManager::UnregisterPlugin(CreateInstance);
47242e1e99SZequan Wu }
48242e1e99SZequan Wu 
49242e1e99SZequan Wu ConstString ObjectFilePDB::GetPluginNameStatic() {
50242e1e99SZequan Wu   static ConstString g_name("pdb");
51242e1e99SZequan Wu   return g_name;
52242e1e99SZequan Wu }
53242e1e99SZequan Wu 
54242e1e99SZequan Wu ArchSpec ObjectFilePDB::GetArchitecture() {
55242e1e99SZequan Wu   auto dbi_stream = m_file_up->getPDBDbiStream();
56242e1e99SZequan Wu   if (!dbi_stream) {
57242e1e99SZequan Wu     llvm::consumeError(dbi_stream.takeError());
58242e1e99SZequan Wu     return ArchSpec();
59242e1e99SZequan Wu   }
60242e1e99SZequan Wu 
61242e1e99SZequan Wu   PDB_Machine machine = dbi_stream->getMachineType();
62242e1e99SZequan Wu   switch (machine) {
63242e1e99SZequan Wu   default:
64242e1e99SZequan Wu     break;
65242e1e99SZequan Wu   case PDB_Machine::Amd64:
66242e1e99SZequan Wu   case PDB_Machine::x86:
67242e1e99SZequan Wu   case PDB_Machine::PowerPC:
68242e1e99SZequan Wu   case PDB_Machine::PowerPCFP:
69242e1e99SZequan Wu   case PDB_Machine::Arm:
70242e1e99SZequan Wu   case PDB_Machine::ArmNT:
71242e1e99SZequan Wu   case PDB_Machine::Thumb:
72242e1e99SZequan Wu   case PDB_Machine::Arm64:
73242e1e99SZequan Wu     ArchSpec arch;
74242e1e99SZequan Wu     arch.SetArchitecture(eArchTypeCOFF, static_cast<int>(machine),
75242e1e99SZequan Wu                          LLDB_INVALID_CPUTYPE);
76242e1e99SZequan Wu     return arch;
77242e1e99SZequan Wu   }
78242e1e99SZequan Wu   return ArchSpec();
79242e1e99SZequan Wu }
80242e1e99SZequan Wu 
81242e1e99SZequan Wu bool ObjectFilePDB::initPDBFile() {
82242e1e99SZequan Wu   m_file_up = loadPDBFile(m_file.GetPath(), m_allocator);
83242e1e99SZequan Wu   if (!m_file_up)
84242e1e99SZequan Wu     return false;
85242e1e99SZequan Wu   auto info_stream = m_file_up->getPDBInfoStream();
86242e1e99SZequan Wu   if (!info_stream) {
87242e1e99SZequan Wu     llvm::consumeError(info_stream.takeError());
88242e1e99SZequan Wu     return false;
89242e1e99SZequan Wu   }
90242e1e99SZequan Wu   m_uuid = GetPDBUUID(*info_stream);
91242e1e99SZequan Wu   return true;
92242e1e99SZequan Wu }
93242e1e99SZequan Wu 
94242e1e99SZequan Wu ObjectFile *
95242e1e99SZequan Wu ObjectFilePDB::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp,
96242e1e99SZequan Wu                               offset_t data_offset, const FileSpec *file,
97242e1e99SZequan Wu                               offset_t file_offset, offset_t length) {
98242e1e99SZequan Wu   auto objfile_up = std::make_unique<ObjectFilePDB>(
99242e1e99SZequan Wu       module_sp, data_sp, data_offset, file, file_offset, length);
100242e1e99SZequan Wu   if (!objfile_up->initPDBFile())
101242e1e99SZequan Wu     return nullptr;
102242e1e99SZequan Wu   return objfile_up.release();
103242e1e99SZequan Wu }
104242e1e99SZequan Wu 
105242e1e99SZequan Wu ObjectFile *ObjectFilePDB::CreateMemoryInstance(const ModuleSP &module_sp,
106242e1e99SZequan Wu                                                 DataBufferSP &data_sp,
107242e1e99SZequan Wu                                                 const ProcessSP &process_sp,
108242e1e99SZequan Wu                                                 addr_t header_addr) {
109242e1e99SZequan Wu   return nullptr;
110242e1e99SZequan Wu }
111242e1e99SZequan Wu 
112242e1e99SZequan Wu size_t ObjectFilePDB::GetModuleSpecifications(
113242e1e99SZequan Wu     const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
114242e1e99SZequan Wu     offset_t file_offset, offset_t length, ModuleSpecList &specs) {
115242e1e99SZequan Wu   const size_t initial_count = specs.GetSize();
116242e1e99SZequan Wu   ModuleSpec module_spec(file);
117242e1e99SZequan Wu   llvm::BumpPtrAllocator allocator;
118242e1e99SZequan Wu   std::unique_ptr<PDBFile> pdb_file = loadPDBFile(file.GetPath(), allocator);
119242e1e99SZequan Wu   if (!pdb_file)
120242e1e99SZequan Wu     return initial_count;
121242e1e99SZequan Wu 
122242e1e99SZequan Wu   auto info_stream = pdb_file->getPDBInfoStream();
123242e1e99SZequan Wu   if (!info_stream) {
124242e1e99SZequan Wu     llvm::consumeError(info_stream.takeError());
125242e1e99SZequan Wu     return initial_count;
126242e1e99SZequan Wu   }
127242e1e99SZequan Wu   auto dbi_stream = pdb_file->getPDBDbiStream();
128242e1e99SZequan Wu   if (!dbi_stream) {
129242e1e99SZequan Wu     llvm::consumeError(dbi_stream.takeError());
130242e1e99SZequan Wu     return initial_count;
131242e1e99SZequan Wu   }
132242e1e99SZequan Wu 
133242e1e99SZequan Wu   lldb_private::UUID &uuid = module_spec.GetUUID();
134242e1e99SZequan Wu   uuid = GetPDBUUID(*info_stream);
135242e1e99SZequan Wu 
136242e1e99SZequan Wu   ArchSpec &module_arch = module_spec.GetArchitecture();
137242e1e99SZequan Wu   switch (dbi_stream->getMachineType()) {
138242e1e99SZequan Wu   case PDB_Machine::Amd64:
139242e1e99SZequan Wu     module_arch.SetTriple("x86_64-pc-windows");
140242e1e99SZequan Wu     specs.Append(module_spec);
141242e1e99SZequan Wu     break;
142242e1e99SZequan Wu   case PDB_Machine::x86:
143242e1e99SZequan Wu     module_arch.SetTriple("i386-pc-windows");
144242e1e99SZequan Wu     specs.Append(module_spec);
145242e1e99SZequan Wu     module_arch.SetTriple("i686-pc-windows");
146242e1e99SZequan Wu     specs.Append(module_spec);
147242e1e99SZequan Wu     break;
148242e1e99SZequan Wu   case PDB_Machine::ArmNT:
149242e1e99SZequan Wu     module_arch.SetTriple("armv7-pc-windows");
150242e1e99SZequan Wu     specs.Append(module_spec);
151242e1e99SZequan Wu     break;
152242e1e99SZequan Wu   case PDB_Machine::Arm64:
153242e1e99SZequan Wu     module_arch.SetTriple("aarch64-pc-windows");
154242e1e99SZequan Wu     specs.Append(module_spec);
155242e1e99SZequan Wu     break;
156242e1e99SZequan Wu   default:
157242e1e99SZequan Wu     break;
158242e1e99SZequan Wu   }
159242e1e99SZequan Wu 
160242e1e99SZequan Wu   return specs.GetSize() - initial_count;
161242e1e99SZequan Wu }
162242e1e99SZequan Wu 
163242e1e99SZequan Wu ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, DataBufferSP &data_sp,
164242e1e99SZequan Wu                              offset_t data_offset, const FileSpec *file,
165242e1e99SZequan Wu                              offset_t offset, offset_t length)
166242e1e99SZequan Wu     : ObjectFile(module_sp, file, offset, length, data_sp, data_offset) {}
167242e1e99SZequan Wu 
168242e1e99SZequan Wu std::unique_ptr<PDBFile>
169242e1e99SZequan Wu ObjectFilePDB::loadPDBFile(std::string PdbPath,
170242e1e99SZequan Wu                            llvm::BumpPtrAllocator &Allocator) {
171242e1e99SZequan Wu   llvm::file_magic magic;
172242e1e99SZequan Wu   auto ec = llvm::identify_magic(PdbPath, magic);
173242e1e99SZequan Wu   if (ec || magic != llvm::file_magic::pdb)
174242e1e99SZequan Wu     return nullptr;
175242e1e99SZequan Wu   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer =
176*c83cd8feSAbhina Sreeskantharajan       llvm::MemoryBuffer::getFile(PdbPath, /*IsText=*/false,
177242e1e99SZequan Wu                                   /*RequiresNullTerminator=*/false);
178242e1e99SZequan Wu   if (!ErrorOrBuffer)
179242e1e99SZequan Wu     return nullptr;
180242e1e99SZequan Wu   std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
181242e1e99SZequan Wu 
182242e1e99SZequan Wu   llvm::StringRef Path = Buffer->getBufferIdentifier();
183242e1e99SZequan Wu   auto Stream = std::make_unique<llvm::MemoryBufferByteStream>(
184242e1e99SZequan Wu       std::move(Buffer), llvm::support::little);
185242e1e99SZequan Wu 
186242e1e99SZequan Wu   auto File = std::make_unique<PDBFile>(Path, std::move(Stream), Allocator);
187242e1e99SZequan Wu   if (auto EC = File->parseFileHeaders()) {
188242e1e99SZequan Wu     llvm::consumeError(std::move(EC));
189242e1e99SZequan Wu     return nullptr;
190242e1e99SZequan Wu   }
191242e1e99SZequan Wu   if (auto EC = File->parseStreamData()) {
192242e1e99SZequan Wu     llvm::consumeError(std::move(EC));
193242e1e99SZequan Wu     return nullptr;
194242e1e99SZequan Wu   }
195242e1e99SZequan Wu 
196242e1e99SZequan Wu   return File;
197242e1e99SZequan Wu }
198