Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
35271 views
1
//===-- LVReaderHandler.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
// This class implements the Reader Handler.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/DebugInfo/LogicalView/LVReaderHandler.h"
14
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
15
#include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
16
#include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h"
17
#include "llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h"
18
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
19
#include "llvm/DebugInfo/PDB/PDB.h"
20
#include "llvm/Object/COFF.h"
21
22
using namespace llvm;
23
using namespace llvm::object;
24
using namespace llvm::pdb;
25
using namespace llvm::logicalview;
26
27
#define DEBUG_TYPE "ReaderHandler"
28
29
Error LVReaderHandler::process() {
30
if (Error Err = createReaders())
31
return Err;
32
if (Error Err = printReaders())
33
return Err;
34
if (Error Err = compareReaders())
35
return Err;
36
37
return Error::success();
38
}
39
40
Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,
41
PdbOrObj &Input, StringRef FileFormatName,
42
StringRef ExePath) {
43
auto CreateOneReader = [&]() -> std::unique_ptr<LVReader> {
44
if (isa<ObjectFile *>(Input)) {
45
ObjectFile &Obj = *cast<ObjectFile *>(Input);
46
if (Obj.isCOFF()) {
47
COFFObjectFile *COFF = cast<COFFObjectFile>(&Obj);
48
return std::make_unique<LVCodeViewReader>(Filename, FileFormatName,
49
*COFF, W, ExePath);
50
}
51
if (Obj.isELF() || Obj.isMachO() || Obj.isWasm())
52
return std::make_unique<LVDWARFReader>(Filename, FileFormatName, Obj,
53
W);
54
}
55
if (isa<PDBFile *>(Input)) {
56
PDBFile &Pdb = *cast<PDBFile *>(Input);
57
return std::make_unique<LVCodeViewReader>(Filename, FileFormatName, Pdb,
58
W, ExePath);
59
}
60
return nullptr;
61
};
62
63
std::unique_ptr<LVReader> ReaderObj = CreateOneReader();
64
if (!ReaderObj)
65
return createStringError(errc::invalid_argument,
66
"unable to create reader for: '%s'",
67
Filename.str().c_str());
68
69
LVReader *Reader = ReaderObj.get();
70
Readers.emplace_back(std::move(ReaderObj));
71
return Reader->doLoad();
72
}
73
74
Error LVReaderHandler::handleArchive(LVReaders &Readers, StringRef Filename,
75
Archive &Arch) {
76
Error Err = Error::success();
77
for (const Archive::Child &Child : Arch.children(Err)) {
78
Expected<MemoryBufferRef> BuffOrErr = Child.getMemoryBufferRef();
79
if (Error Err = BuffOrErr.takeError())
80
return createStringError(errorToErrorCode(std::move(Err)), "%s",
81
Filename.str().c_str());
82
Expected<StringRef> NameOrErr = Child.getName();
83
if (Error Err = NameOrErr.takeError())
84
return createStringError(errorToErrorCode(std::move(Err)), "%s",
85
Filename.str().c_str());
86
std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();
87
if (Error Err = handleBuffer(Readers, Name, BuffOrErr.get()))
88
return createStringError(errorToErrorCode(std::move(Err)), "%s",
89
Filename.str().c_str());
90
}
91
92
return Error::success();
93
}
94
95
// Search for a matching executable image for the given PDB path.
96
static std::string searchForExe(const StringRef Path,
97
const StringRef Extension) {
98
SmallString<128> ExePath(Path);
99
llvm::sys::path::replace_extension(ExePath, Extension);
100
101
std::unique_ptr<IPDBSession> Session;
102
if (Error Err = loadDataForEXE(PDB_ReaderType::Native, ExePath, Session)) {
103
consumeError(std::move(Err));
104
return {};
105
}
106
// We have a candidate for the executable image.
107
Expected<std::string> PdbPathOrErr = NativeSession::searchForPdb({ExePath});
108
if (!PdbPathOrErr) {
109
consumeError(PdbPathOrErr.takeError());
110
return {};
111
}
112
// Convert any Windows backslashes into forward slashes to get the path.
113
std::string ConvertedPath = sys::path::convert_to_slash(
114
PdbPathOrErr.get(), sys::path::Style::windows);
115
if (ConvertedPath == Path)
116
return std::string(ExePath);
117
118
return {};
119
}
120
121
// Search for a matching object image for the given PDB path.
122
static std::string searchForObj(const StringRef Path,
123
const StringRef Extension) {
124
SmallString<128> ObjPath(Path);
125
llvm::sys::path::replace_extension(ObjPath, Extension);
126
if (llvm::sys::fs::exists(ObjPath)) {
127
ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
128
MemoryBuffer::getFileOrSTDIN(ObjPath);
129
if (!BuffOrErr)
130
return {};
131
return std::string(ObjPath);
132
}
133
134
return {};
135
}
136
137
Error LVReaderHandler::handleBuffer(LVReaders &Readers, StringRef Filename,
138
MemoryBufferRef Buffer, StringRef ExePath) {
139
// As PDB does not support the Binary interface, at this point we can check
140
// if the buffer corresponds to a PDB or PE file.
141
file_magic FileMagic = identify_magic(Buffer.getBuffer());
142
if (FileMagic == file_magic::pdb) {
143
if (!ExePath.empty())
144
return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath);
145
146
// Search in the directory derived from the given 'Filename' for a
147
// matching object file (.o, .obj, .lib) or a matching executable file
148
// (.exe/.dll) and try to create the reader based on the matched file.
149
// If no matching file is found then we load the original PDB file.
150
std::vector<StringRef> ExecutableExtensions = {"exe", "dll"};
151
for (StringRef Extension : ExecutableExtensions) {
152
std::string ExecutableImage = searchForExe(Filename, Extension);
153
if (ExecutableImage.empty())
154
continue;
155
if (Error Err = handleObject(Readers, Filename, Buffer.getBuffer(),
156
ExecutableImage)) {
157
consumeError(std::move(Err));
158
continue;
159
}
160
return Error::success();
161
}
162
163
std::vector<StringRef> ObjectExtensions = {"o", "obj", "lib"};
164
for (StringRef Extension : ObjectExtensions) {
165
std::string ObjectImage = searchForObj(Filename, Extension);
166
if (ObjectImage.empty())
167
continue;
168
if (Error Err = handleFile(Readers, ObjectImage)) {
169
consumeError(std::move(Err));
170
continue;
171
}
172
return Error::success();
173
}
174
175
// No matching executable/object image was found. Load the given PDB.
176
return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath);
177
}
178
if (FileMagic == file_magic::pecoff_executable) {
179
// If we have a valid executable, try to find a matching PDB file.
180
Expected<std::string> PdbPath = NativeSession::searchForPdb({Filename});
181
if (errorToErrorCode(PdbPath.takeError())) {
182
return createStringError(
183
errc::not_supported,
184
"Binary object format in '%s' does not have debug info.",
185
Filename.str().c_str());
186
}
187
// Process the matching PDB file and pass the executable filename.
188
return handleFile(Readers, PdbPath.get(), Filename);
189
}
190
191
Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer);
192
if (errorToErrorCode(BinOrErr.takeError())) {
193
return createStringError(errc::not_supported,
194
"Binary object format in '%s' is not supported.",
195
Filename.str().c_str());
196
}
197
return handleObject(Readers, Filename, *BinOrErr.get());
198
}
199
200
Error LVReaderHandler::handleFile(LVReaders &Readers, StringRef Filename,
201
StringRef ExePath) {
202
// Convert any Windows backslashes into forward slashes to get the path.
203
std::string ConvertedPath =
204
sys::path::convert_to_slash(Filename, sys::path::Style::windows);
205
ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
206
MemoryBuffer::getFileOrSTDIN(ConvertedPath);
207
if (BuffOrErr.getError()) {
208
return createStringError(errc::bad_file_descriptor,
209
"File '%s' does not exist.",
210
ConvertedPath.c_str());
211
}
212
std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
213
return handleBuffer(Readers, ConvertedPath, *Buffer, ExePath);
214
}
215
216
Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename,
217
MachOUniversalBinary &Mach) {
218
for (const MachOUniversalBinary::ObjectForArch &ObjForArch : Mach.objects()) {
219
std::string ObjName = (Twine(Filename) + Twine("(") +
220
Twine(ObjForArch.getArchFlagName()) + Twine(")"))
221
.str();
222
if (Expected<std::unique_ptr<MachOObjectFile>> MachOOrErr =
223
ObjForArch.getAsObjectFile()) {
224
MachOObjectFile &Obj = **MachOOrErr;
225
PdbOrObj Input = &Obj;
226
if (Error Err =
227
createReader(Filename, Readers, Input, Obj.getFileFormatName()))
228
return Err;
229
continue;
230
} else
231
consumeError(MachOOrErr.takeError());
232
if (Expected<std::unique_ptr<Archive>> ArchiveOrErr =
233
ObjForArch.getAsArchive()) {
234
if (Error Err = handleArchive(Readers, ObjName, *ArchiveOrErr.get()))
235
return Err;
236
continue;
237
} else
238
consumeError(ArchiveOrErr.takeError());
239
}
240
return Error::success();
241
}
242
243
Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
244
Binary &Binary) {
245
if (PdbOrObj Input = dyn_cast<ObjectFile>(&Binary))
246
return createReader(Filename, Readers, Input,
247
cast<ObjectFile *>(Input)->getFileFormatName());
248
249
if (MachOUniversalBinary *Fat = dyn_cast<MachOUniversalBinary>(&Binary))
250
return handleMach(Readers, Filename, *Fat);
251
252
if (Archive *Arch = dyn_cast<Archive>(&Binary))
253
return handleArchive(Readers, Filename, *Arch);
254
255
return createStringError(errc::not_supported,
256
"Binary object format in '%s' is not supported.",
257
Filename.str().c_str());
258
}
259
260
Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
261
StringRef Buffer, StringRef ExePath) {
262
std::unique_ptr<IPDBSession> Session;
263
if (Error Err = loadDataForPDB(PDB_ReaderType::Native, Filename, Session))
264
return createStringError(errorToErrorCode(std::move(Err)), "%s",
265
Filename.str().c_str());
266
267
std::unique_ptr<NativeSession> PdbSession;
268
PdbSession.reset(static_cast<NativeSession *>(Session.release()));
269
PdbOrObj Input = &PdbSession->getPDBFile();
270
StringRef FileFormatName;
271
size_t Pos = Buffer.find_first_of("\r\n");
272
if (Pos)
273
FileFormatName = Buffer.substr(0, Pos - 1);
274
return createReader(Filename, Readers, Input, FileFormatName, ExePath);
275
}
276
277
Error LVReaderHandler::createReaders() {
278
LLVM_DEBUG(dbgs() << "createReaders\n");
279
for (std::string &Object : Objects) {
280
LVReaders Readers;
281
if (Error Err = createReader(Object, Readers))
282
return Err;
283
TheReaders.insert(TheReaders.end(),
284
std::make_move_iterator(Readers.begin()),
285
std::make_move_iterator(Readers.end()));
286
}
287
288
return Error::success();
289
}
290
291
Error LVReaderHandler::printReaders() {
292
LLVM_DEBUG(dbgs() << "printReaders\n");
293
if (options().getPrintExecute())
294
for (const std::unique_ptr<LVReader> &Reader : TheReaders)
295
if (Error Err = Reader->doPrint())
296
return Err;
297
298
return Error::success();
299
}
300
301
Error LVReaderHandler::compareReaders() {
302
LLVM_DEBUG(dbgs() << "compareReaders\n");
303
size_t ReadersCount = TheReaders.size();
304
if (options().getCompareExecute() && ReadersCount >= 2) {
305
// If we have more than 2 readers, compare them by pairs.
306
size_t ViewPairs = ReadersCount / 2;
307
LVCompare Compare(OS);
308
for (size_t Pair = 0, Index = 0; Pair < ViewPairs; ++Pair) {
309
if (Error Err = Compare.execute(TheReaders[Index].get(),
310
TheReaders[Index + 1].get()))
311
return Err;
312
Index += 2;
313
}
314
}
315
316
return Error::success();
317
}
318
319
void LVReaderHandler::print(raw_ostream &OS) const { OS << "ReaderHandler\n"; }
320
321