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
LLDB_PLUGIN_DEFINE(ObjectFilePDB)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
Initialize()39 void ObjectFilePDB::Initialize() {
40 PluginManager::RegisterPlugin(GetPluginNameStatic(),
41 GetPluginDescriptionStatic(), CreateInstance,
42 CreateMemoryInstance, GetModuleSpecifications);
43 }
44
Terminate()45 void ObjectFilePDB::Terminate() {
46 PluginManager::UnregisterPlugin(CreateInstance);
47 }
48
GetPluginNameStatic()49 ConstString ObjectFilePDB::GetPluginNameStatic() {
50 static ConstString g_name("pdb");
51 return g_name;
52 }
53
GetArchitecture()54 ArchSpec ObjectFilePDB::GetArchitecture() {
55 auto dbi_stream = m_file_up->getPDBDbiStream();
56 if (!dbi_stream) {
57 llvm::consumeError(dbi_stream.takeError());
58 return ArchSpec();
59 }
60
61 PDB_Machine machine = dbi_stream->getMachineType();
62 switch (machine) {
63 default:
64 break;
65 case PDB_Machine::Amd64:
66 case PDB_Machine::x86:
67 case PDB_Machine::PowerPC:
68 case PDB_Machine::PowerPCFP:
69 case PDB_Machine::Arm:
70 case PDB_Machine::ArmNT:
71 case PDB_Machine::Thumb:
72 case PDB_Machine::Arm64:
73 ArchSpec arch;
74 arch.SetArchitecture(eArchTypeCOFF, static_cast<int>(machine),
75 LLDB_INVALID_CPUTYPE);
76 return arch;
77 }
78 return ArchSpec();
79 }
80
initPDBFile()81 bool ObjectFilePDB::initPDBFile() {
82 m_file_up = loadPDBFile(m_file.GetPath(), m_allocator);
83 if (!m_file_up)
84 return false;
85 auto info_stream = m_file_up->getPDBInfoStream();
86 if (!info_stream) {
87 llvm::consumeError(info_stream.takeError());
88 return false;
89 }
90 m_uuid = GetPDBUUID(*info_stream);
91 return true;
92 }
93
94 ObjectFile *
CreateInstance(const ModuleSP & module_sp,DataBufferSP & data_sp,offset_t data_offset,const FileSpec * file,offset_t file_offset,offset_t length)95 ObjectFilePDB::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp,
96 offset_t data_offset, const FileSpec *file,
97 offset_t file_offset, offset_t length) {
98 auto objfile_up = std::make_unique<ObjectFilePDB>(
99 module_sp, data_sp, data_offset, file, file_offset, length);
100 if (!objfile_up->initPDBFile())
101 return nullptr;
102 return objfile_up.release();
103 }
104
CreateMemoryInstance(const ModuleSP & module_sp,DataBufferSP & data_sp,const ProcessSP & process_sp,addr_t header_addr)105 ObjectFile *ObjectFilePDB::CreateMemoryInstance(const ModuleSP &module_sp,
106 DataBufferSP &data_sp,
107 const ProcessSP &process_sp,
108 addr_t header_addr) {
109 return nullptr;
110 }
111
GetModuleSpecifications(const FileSpec & file,DataBufferSP & data_sp,offset_t data_offset,offset_t file_offset,offset_t length,ModuleSpecList & specs)112 size_t ObjectFilePDB::GetModuleSpecifications(
113 const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
114 offset_t file_offset, offset_t length, ModuleSpecList &specs) {
115 const size_t initial_count = specs.GetSize();
116 ModuleSpec module_spec(file);
117 llvm::BumpPtrAllocator allocator;
118 std::unique_ptr<PDBFile> pdb_file = loadPDBFile(file.GetPath(), allocator);
119 if (!pdb_file)
120 return initial_count;
121
122 auto info_stream = pdb_file->getPDBInfoStream();
123 if (!info_stream) {
124 llvm::consumeError(info_stream.takeError());
125 return initial_count;
126 }
127 auto dbi_stream = pdb_file->getPDBDbiStream();
128 if (!dbi_stream) {
129 llvm::consumeError(dbi_stream.takeError());
130 return initial_count;
131 }
132
133 lldb_private::UUID &uuid = module_spec.GetUUID();
134 uuid = GetPDBUUID(*info_stream);
135
136 ArchSpec &module_arch = module_spec.GetArchitecture();
137 switch (dbi_stream->getMachineType()) {
138 case PDB_Machine::Amd64:
139 module_arch.SetTriple("x86_64-pc-windows");
140 specs.Append(module_spec);
141 break;
142 case PDB_Machine::x86:
143 module_arch.SetTriple("i386-pc-windows");
144 specs.Append(module_spec);
145 module_arch.SetTriple("i686-pc-windows");
146 specs.Append(module_spec);
147 break;
148 case PDB_Machine::ArmNT:
149 module_arch.SetTriple("armv7-pc-windows");
150 specs.Append(module_spec);
151 break;
152 case PDB_Machine::Arm64:
153 module_arch.SetTriple("aarch64-pc-windows");
154 specs.Append(module_spec);
155 break;
156 default:
157 break;
158 }
159
160 return specs.GetSize() - initial_count;
161 }
162
ObjectFilePDB(const ModuleSP & module_sp,DataBufferSP & data_sp,offset_t data_offset,const FileSpec * file,offset_t offset,offset_t length)163 ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, DataBufferSP &data_sp,
164 offset_t data_offset, const FileSpec *file,
165 offset_t offset, offset_t length)
166 : ObjectFile(module_sp, file, offset, length, data_sp, data_offset) {}
167
168 std::unique_ptr<PDBFile>
loadPDBFile(std::string PdbPath,llvm::BumpPtrAllocator & Allocator)169 ObjectFilePDB::loadPDBFile(std::string PdbPath,
170 llvm::BumpPtrAllocator &Allocator) {
171 llvm::file_magic magic;
172 auto ec = llvm::identify_magic(PdbPath, magic);
173 if (ec || magic != llvm::file_magic::pdb)
174 return nullptr;
175 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer =
176 llvm::MemoryBuffer::getFile(PdbPath, /*IsText=*/false,
177 /*RequiresNullTerminator=*/false);
178 if (!ErrorOrBuffer)
179 return nullptr;
180 std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
181
182 llvm::StringRef Path = Buffer->getBufferIdentifier();
183 auto Stream = std::make_unique<llvm::MemoryBufferByteStream>(
184 std::move(Buffer), llvm::support::little);
185
186 auto File = std::make_unique<PDBFile>(Path, std::move(Stream), Allocator);
187 if (auto EC = File->parseFileHeaders()) {
188 llvm::consumeError(std::move(EC));
189 return nullptr;
190 }
191 if (auto EC = File->parseStreamData()) {
192 llvm::consumeError(std::move(EC));
193 return nullptr;
194 }
195
196 return File;
197 }
198