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
23using namespace lldb;
24using namespace lldb_private;
25using namespace llvm::pdb;
26using namespace llvm::codeview;
27
28LLDB_PLUGIN_DEFINE(ObjectFilePDB)
29
30static UUID GetPDBUUID(InfoStream &IS, DbiStream &DS) {
31 UUID::CvRecordPdb70 debug_info;
32 memcpy(dest: &debug_info.Uuid, src: IS.getGuid().Guid, n: sizeof(debug_info.Uuid));
33 debug_info.Age = DS.getAge();
34 return UUID(debug_info);
35}
36
37char ObjectFilePDB::ID;
38
39void ObjectFilePDB::Initialize() {
40 PluginManager::RegisterPlugin(name: GetPluginNameStatic(),
41 description: GetPluginDescriptionStatic(), create_callback: CreateInstance,
42 create_memory_callback: CreateMemoryInstance, get_module_specifications: GetModuleSpecifications);
43}
44
45void ObjectFilePDB::Terminate() {
46 PluginManager::UnregisterPlugin(create_callback: CreateInstance);
47}
48
49ArchSpec ObjectFilePDB::GetArchitecture() {
50 auto dbi_stream = m_file_up->getPDBDbiStream();
51 if (!dbi_stream) {
52 llvm::consumeError(Err: 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(arch_type: eArchTypeCOFF, cpu: static_cast<int>(machine),
70 LLDB_INVALID_CPUTYPE);
71 return arch;
72 }
73 return ArchSpec();
74}
75
76bool ObjectFilePDB::initPDBFile() {
77 m_file_up = loadPDBFile(PdbPath: m_file.GetPath(), Allocator&: 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(Err: info_stream.takeError());
83 return false;
84 }
85 auto dbi_stream = m_file_up->getPDBDbiStream();
86 if (!dbi_stream) {
87 llvm::consumeError(Err: dbi_stream.takeError());
88 return false;
89 }
90 m_uuid = GetPDBUUID(IS&: *info_stream, DS&: *dbi_stream);
91 return true;
92}
93
94ObjectFile *
95ObjectFilePDB::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 args: module_sp, args&: data_sp, args&: data_offset, args&: file, args&: file_offset, args&: length);
100 if (!objfile_up->initPDBFile())
101 return nullptr;
102 return objfile_up.release();
103}
104
105ObjectFile *ObjectFilePDB::CreateMemoryInstance(const ModuleSP &module_sp,
106 WritableDataBufferSP data_sp,
107 const ProcessSP &process_sp,
108 addr_t header_addr) {
109 return nullptr;
110}
111
112size_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(PdbPath: file.GetPath(), Allocator&: allocator);
119 if (!pdb_file)
120 return initial_count;
121
122 auto info_stream = pdb_file->getPDBInfoStream();
123 if (!info_stream) {
124 llvm::consumeError(Err: info_stream.takeError());
125 return initial_count;
126 }
127 auto dbi_stream = pdb_file->getPDBDbiStream();
128 if (!dbi_stream) {
129 llvm::consumeError(Err: dbi_stream.takeError());
130 return initial_count;
131 }
132
133 lldb_private::UUID &uuid = module_spec.GetUUID();
134 uuid = GetPDBUUID(IS&: *info_stream, DS&: *dbi_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(spec: module_spec);
141 break;
142 case PDB_Machine::x86:
143 module_arch.SetTriple("i386-pc-windows");
144 specs.Append(spec: module_spec);
145 break;
146 case PDB_Machine::ArmNT:
147 module_arch.SetTriple("armv7-pc-windows");
148 specs.Append(spec: module_spec);
149 break;
150 case PDB_Machine::Arm64:
151 module_arch.SetTriple("aarch64-pc-windows");
152 specs.Append(spec: module_spec);
153 break;
154 default:
155 break;
156 }
157
158 return specs.GetSize() - initial_count;
159}
160
161ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, DataBufferSP &data_sp,
162 offset_t data_offset, const FileSpec *file,
163 offset_t offset, offset_t length)
164 : ObjectFile(module_sp, file, offset, length, data_sp, data_offset) {}
165
166std::unique_ptr<PDBFile>
167ObjectFilePDB::loadPDBFile(std::string PdbPath,
168 llvm::BumpPtrAllocator &Allocator) {
169 llvm::file_magic magic;
170 auto ec = llvm::identify_magic(path: PdbPath, result&: magic);
171 if (ec || magic != llvm::file_magic::pdb)
172 return nullptr;
173 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ErrorOrBuffer =
174 llvm::MemoryBuffer::getFile(Filename: PdbPath, /*IsText=*/false,
175 /*RequiresNullTerminator=*/false);
176 if (!ErrorOrBuffer)
177 return nullptr;
178 std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
179
180 llvm::StringRef Path = Buffer->getBufferIdentifier();
181 auto Stream = std::make_unique<llvm::MemoryBufferByteStream>(
182 args: std::move(Buffer), args: llvm::endianness::little);
183
184 auto File = std::make_unique<PDBFile>(args&: Path, args: std::move(Stream), args&: Allocator);
185 if (auto EC = File->parseFileHeaders()) {
186 llvm::consumeError(Err: std::move(EC));
187 return nullptr;
188 }
189 if (auto EC = File->parseStreamData()) {
190 llvm::consumeError(Err: std::move(EC));
191 return nullptr;
192 }
193
194 return File;
195}
196

source code of lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp