1*242e1e99SZequan Wu //===-- ObjectFilePDB.cpp -------------------------------------------------===//
2*242e1e99SZequan Wu //
3*242e1e99SZequan Wu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*242e1e99SZequan Wu // See https://llvm.org/LICENSE.txt for license information.
5*242e1e99SZequan Wu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*242e1e99SZequan Wu //
7*242e1e99SZequan Wu //===----------------------------------------------------------------------===//
8*242e1e99SZequan Wu 
9*242e1e99SZequan Wu #include "ObjectFilePDB.h"
10*242e1e99SZequan Wu #include "lldb/Core/Module.h"
11*242e1e99SZequan Wu #include "lldb/Core/ModuleSpec.h"
12*242e1e99SZequan Wu #include "lldb/Core/PluginManager.h"
13*242e1e99SZequan Wu #include "lldb/Core/Section.h"
14*242e1e99SZequan Wu #include "lldb/Utility/StreamString.h"
15*242e1e99SZequan Wu #include "llvm/BinaryFormat/Magic.h"
16*242e1e99SZequan Wu #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
17*242e1e99SZequan Wu #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
18*242e1e99SZequan Wu #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
19*242e1e99SZequan Wu #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
20*242e1e99SZequan Wu #include "llvm/DebugInfo/PDB/PDB.h"
21*242e1e99SZequan Wu #include "llvm/Support/BinaryByteStream.h"
22*242e1e99SZequan Wu 
23*242e1e99SZequan Wu using namespace lldb;
24*242e1e99SZequan Wu using namespace lldb_private;
25*242e1e99SZequan Wu using namespace llvm::pdb;
26*242e1e99SZequan Wu using namespace llvm::codeview;
27*242e1e99SZequan Wu 
28*242e1e99SZequan Wu LLDB_PLUGIN_DEFINE(ObjectFilePDB)
29*242e1e99SZequan Wu 
30*242e1e99SZequan Wu struct CVInfoPdb70 {
31*242e1e99SZequan Wu   // 16-byte GUID
32*242e1e99SZequan Wu   struct _Guid {
33*242e1e99SZequan Wu     llvm::support::ulittle32_t Data1;
34*242e1e99SZequan Wu     llvm::support::ulittle16_t Data2;
35*242e1e99SZequan Wu     llvm::support::ulittle16_t Data3;
36*242e1e99SZequan Wu     uint8_t Data4[8];
37*242e1e99SZequan Wu   } Guid;
38*242e1e99SZequan Wu 
39*242e1e99SZequan Wu   llvm::support::ulittle32_t Age;
40*242e1e99SZequan Wu };
41*242e1e99SZequan Wu 
42*242e1e99SZequan Wu static UUID GetPDBUUID(InfoStream &IS) {
43*242e1e99SZequan Wu   // This part is similar with what has done in ObjectFilePECOFF.
44*242e1e99SZequan Wu   using llvm::support::endian::read16be;
45*242e1e99SZequan Wu   using llvm::support::endian::read32;
46*242e1e99SZequan Wu   using llvm::support::endian::read32be;
47*242e1e99SZequan Wu 
48*242e1e99SZequan Wu   GUID guid = IS.getGuid();
49*242e1e99SZequan Wu   const uint8_t *guid_p = guid.Guid;
50*242e1e99SZequan Wu   struct CVInfoPdb70 info;
51*242e1e99SZequan Wu   info.Guid.Data1 = read32be(guid_p);
52*242e1e99SZequan Wu   guid_p += 4;
53*242e1e99SZequan Wu   info.Guid.Data2 = read16be(guid_p);
54*242e1e99SZequan Wu   guid_p += 2;
55*242e1e99SZequan Wu   info.Guid.Data3 = read16be(guid_p);
56*242e1e99SZequan Wu   guid_p += 2;
57*242e1e99SZequan Wu   memcpy(info.Guid.Data4, guid_p, 8);
58*242e1e99SZequan Wu 
59*242e1e99SZequan Wu   // Return 20-byte UUID if the Age is not zero
60*242e1e99SZequan Wu   uint32_t age = IS.getAge();
61*242e1e99SZequan Wu   if (age) {
62*242e1e99SZequan Wu     info.Age = read32(&age, llvm::support::big);
63*242e1e99SZequan Wu     return UUID::fromOptionalData(&info, sizeof(info));
64*242e1e99SZequan Wu   }
65*242e1e99SZequan Wu   // Otherwise return 16-byte GUID
66*242e1e99SZequan Wu   return UUID::fromOptionalData(&info.Guid, sizeof(info.Guid));
67*242e1e99SZequan Wu }
68*242e1e99SZequan Wu 
69*242e1e99SZequan Wu char ObjectFilePDB::ID;
70*242e1e99SZequan Wu 
71*242e1e99SZequan Wu void ObjectFilePDB::Initialize() {
72*242e1e99SZequan Wu   PluginManager::RegisterPlugin(GetPluginNameStatic(),
73*242e1e99SZequan Wu                                 GetPluginDescriptionStatic(), CreateInstance,
74*242e1e99SZequan Wu                                 CreateMemoryInstance, GetModuleSpecifications);
75*242e1e99SZequan Wu }
76*242e1e99SZequan Wu 
77*242e1e99SZequan Wu void ObjectFilePDB::Terminate() {
78*242e1e99SZequan Wu   PluginManager::UnregisterPlugin(CreateInstance);
79*242e1e99SZequan Wu }
80*242e1e99SZequan Wu 
81*242e1e99SZequan Wu ConstString ObjectFilePDB::GetPluginNameStatic() {
82*242e1e99SZequan Wu   static ConstString g_name("pdb");
83*242e1e99SZequan Wu   return g_name;
84*242e1e99SZequan Wu }
85*242e1e99SZequan Wu 
86*242e1e99SZequan Wu ArchSpec ObjectFilePDB::GetArchitecture() {
87*242e1e99SZequan Wu   auto dbi_stream = m_file_up->getPDBDbiStream();
88*242e1e99SZequan Wu   if (!dbi_stream) {
89*242e1e99SZequan Wu     llvm::consumeError(dbi_stream.takeError());
90*242e1e99SZequan Wu     return ArchSpec();
91*242e1e99SZequan Wu   }
92*242e1e99SZequan Wu 
93*242e1e99SZequan Wu   PDB_Machine machine = dbi_stream->getMachineType();
94*242e1e99SZequan Wu   switch (machine) {
95*242e1e99SZequan Wu   default:
96*242e1e99SZequan Wu     break;
97*242e1e99SZequan Wu   case PDB_Machine::Amd64:
98*242e1e99SZequan Wu   case PDB_Machine::x86:
99*242e1e99SZequan Wu   case PDB_Machine::PowerPC:
100*242e1e99SZequan Wu   case PDB_Machine::PowerPCFP:
101*242e1e99SZequan Wu   case PDB_Machine::Arm:
102*242e1e99SZequan Wu   case PDB_Machine::ArmNT:
103*242e1e99SZequan Wu   case PDB_Machine::Thumb:
104*242e1e99SZequan Wu   case PDB_Machine::Arm64:
105*242e1e99SZequan Wu     ArchSpec arch;
106*242e1e99SZequan Wu     arch.SetArchitecture(eArchTypeCOFF, static_cast<int>(machine),
107*242e1e99SZequan Wu                          LLDB_INVALID_CPUTYPE);
108*242e1e99SZequan Wu     return arch;
109*242e1e99SZequan Wu   }
110*242e1e99SZequan Wu   return ArchSpec();
111*242e1e99SZequan Wu }
112*242e1e99SZequan Wu 
113*242e1e99SZequan Wu bool ObjectFilePDB::initPDBFile() {
114*242e1e99SZequan Wu   m_file_up = loadPDBFile(m_file.GetPath(), m_allocator);
115*242e1e99SZequan Wu   if (!m_file_up)
116*242e1e99SZequan Wu     return false;
117*242e1e99SZequan Wu   auto info_stream = m_file_up->getPDBInfoStream();
118*242e1e99SZequan Wu   if (!info_stream) {
119*242e1e99SZequan Wu     llvm::consumeError(info_stream.takeError());
120*242e1e99SZequan Wu     return false;
121*242e1e99SZequan Wu   }
122*242e1e99SZequan Wu   m_uuid = GetPDBUUID(*info_stream);
123*242e1e99SZequan Wu   return true;
124*242e1e99SZequan Wu }
125*242e1e99SZequan Wu 
126*242e1e99SZequan Wu ObjectFile *
127*242e1e99SZequan Wu ObjectFilePDB::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp,
128*242e1e99SZequan Wu                               offset_t data_offset, const FileSpec *file,
129*242e1e99SZequan Wu                               offset_t file_offset, offset_t length) {
130*242e1e99SZequan Wu   auto objfile_up = std::make_unique<ObjectFilePDB>(
131*242e1e99SZequan Wu       module_sp, data_sp, data_offset, file, file_offset, length);
132*242e1e99SZequan Wu   if (!objfile_up->initPDBFile())
133*242e1e99SZequan Wu     return nullptr;
134*242e1e99SZequan Wu   return objfile_up.release();
135*242e1e99SZequan Wu }
136*242e1e99SZequan Wu 
137*242e1e99SZequan Wu ObjectFile *ObjectFilePDB::CreateMemoryInstance(const ModuleSP &module_sp,
138*242e1e99SZequan Wu                                                 DataBufferSP &data_sp,
139*242e1e99SZequan Wu                                                 const ProcessSP &process_sp,
140*242e1e99SZequan Wu                                                 addr_t header_addr) {
141*242e1e99SZequan Wu   return nullptr;
142*242e1e99SZequan Wu }
143*242e1e99SZequan Wu 
144*242e1e99SZequan Wu size_t ObjectFilePDB::GetModuleSpecifications(
145*242e1e99SZequan Wu     const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
146*242e1e99SZequan Wu     offset_t file_offset, offset_t length, ModuleSpecList &specs) {
147*242e1e99SZequan Wu   const size_t initial_count = specs.GetSize();
148*242e1e99SZequan Wu   ModuleSpec module_spec(file);
149*242e1e99SZequan Wu   llvm::BumpPtrAllocator allocator;
150*242e1e99SZequan Wu   std::unique_ptr<PDBFile> pdb_file = loadPDBFile(file.GetPath(), allocator);
151*242e1e99SZequan Wu   if (!pdb_file)
152*242e1e99SZequan Wu     return initial_count;
153*242e1e99SZequan Wu 
154*242e1e99SZequan Wu   auto info_stream = pdb_file->getPDBInfoStream();
155*242e1e99SZequan Wu   if (!info_stream) {
156*242e1e99SZequan Wu     llvm::consumeError(info_stream.takeError());
157*242e1e99SZequan Wu     return initial_count;
158*242e1e99SZequan Wu   }
159*242e1e99SZequan Wu   auto dbi_stream = pdb_file->getPDBDbiStream();
160*242e1e99SZequan Wu   if (!dbi_stream) {
161*242e1e99SZequan Wu     llvm::consumeError(dbi_stream.takeError());
162*242e1e99SZequan Wu     return initial_count;
163*242e1e99SZequan Wu   }
164*242e1e99SZequan Wu 
165*242e1e99SZequan Wu   lldb_private::UUID &uuid = module_spec.GetUUID();
166*242e1e99SZequan Wu   uuid = GetPDBUUID(*info_stream);
167*242e1e99SZequan Wu 
168*242e1e99SZequan Wu   ArchSpec &module_arch = module_spec.GetArchitecture();
169*242e1e99SZequan Wu   switch (dbi_stream->getMachineType()) {
170*242e1e99SZequan Wu   case PDB_Machine::Amd64:
171*242e1e99SZequan Wu     module_arch.SetTriple("x86_64-pc-windows");
172*242e1e99SZequan Wu     specs.Append(module_spec);
173*242e1e99SZequan Wu     break;
174*242e1e99SZequan Wu   case PDB_Machine::x86:
175*242e1e99SZequan Wu     module_arch.SetTriple("i386-pc-windows");
176*242e1e99SZequan Wu     specs.Append(module_spec);
177*242e1e99SZequan Wu     module_arch.SetTriple("i686-pc-windows");
178*242e1e99SZequan Wu     specs.Append(module_spec);
179*242e1e99SZequan Wu     break;
180*242e1e99SZequan Wu   case PDB_Machine::ArmNT:
181*242e1e99SZequan Wu     module_arch.SetTriple("armv7-pc-windows");
182*242e1e99SZequan Wu     specs.Append(module_spec);
183*242e1e99SZequan Wu     break;
184*242e1e99SZequan Wu   case PDB_Machine::Arm64:
185*242e1e99SZequan Wu     module_arch.SetTriple("aarch64-pc-windows");
186*242e1e99SZequan Wu     specs.Append(module_spec);
187*242e1e99SZequan Wu     break;
188*242e1e99SZequan Wu   default:
189*242e1e99SZequan Wu     break;
190*242e1e99SZequan Wu   }
191*242e1e99SZequan Wu 
192*242e1e99SZequan Wu   return specs.GetSize() - initial_count;
193*242e1e99SZequan Wu }
194*242e1e99SZequan Wu 
195*242e1e99SZequan Wu ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, DataBufferSP &data_sp,
196*242e1e99SZequan Wu                              offset_t data_offset, const FileSpec *file,
197*242e1e99SZequan Wu                              offset_t offset, offset_t length)
198*242e1e99SZequan Wu     : ObjectFile(module_sp, file, offset, length, data_sp, data_offset) {}
199*242e1e99SZequan Wu 
200*242e1e99SZequan Wu std::unique_ptr<PDBFile>
201*242e1e99SZequan Wu ObjectFilePDB::loadPDBFile(std::string PdbPath,
202*242e1e99SZequan Wu                            llvm::BumpPtrAllocator &Allocator) {
203*242e1e99SZequan Wu   llvm::file_magic magic;
204*242e1e99SZequan Wu   auto ec = llvm::identify_magic(PdbPath, magic);
205*242e1e99SZequan Wu   if (ec || magic != llvm::file_magic::pdb)
206*242e1e99SZequan Wu     return nullptr;
207*242e1e99SZequan Wu   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer =
208*242e1e99SZequan Wu       llvm::MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1,
209*242e1e99SZequan Wu                                   /*RequiresNullTerminator=*/false);
210*242e1e99SZequan Wu   if (!ErrorOrBuffer)
211*242e1e99SZequan Wu     return nullptr;
212*242e1e99SZequan Wu   std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
213*242e1e99SZequan Wu 
214*242e1e99SZequan Wu   llvm::StringRef Path = Buffer->getBufferIdentifier();
215*242e1e99SZequan Wu   auto Stream = std::make_unique<llvm::MemoryBufferByteStream>(
216*242e1e99SZequan Wu       std::move(Buffer), llvm::support::little);
217*242e1e99SZequan Wu 
218*242e1e99SZequan Wu   auto File = std::make_unique<PDBFile>(Path, std::move(Stream), Allocator);
219*242e1e99SZequan Wu   if (auto EC = File->parseFileHeaders()) {
220*242e1e99SZequan Wu     llvm::consumeError(std::move(EC));
221*242e1e99SZequan Wu     return nullptr;
222*242e1e99SZequan Wu   }
223*242e1e99SZequan Wu   if (auto EC = File->parseStreamData()) {
224*242e1e99SZequan Wu     llvm::consumeError(std::move(EC));
225*242e1e99SZequan Wu     return nullptr;
226*242e1e99SZequan Wu   }
227*242e1e99SZequan Wu 
228*242e1e99SZequan Wu   return File;
229*242e1e99SZequan Wu }
230