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