LLVM 23.0.0git
LVReaderHandler.cpp
Go to the documentation of this file.
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
20#include "llvm/IR/LLVMContext.h"
21#include "llvm/Object/COFF.h"
22
23using namespace llvm;
24using namespace llvm::object;
25using namespace llvm::pdb;
26using namespace llvm::logicalview;
27
28#define DEBUG_TYPE "ReaderHandler"
29
30static constexpr StringRef IRFileFormatName = "LLVM IR";
31
33 if (Error Err = createReaders())
34 return Err;
35 if (Error Err = printReaders())
36 return Err;
37 if (Error Err = compareReaders())
38 return Err;
39
40 return Error::success();
41}
42
43Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,
45 StringRef FileFormatName,
46 StringRef ExePath) {
47 auto CreateOneReader = [&]() -> std::unique_ptr<LVReader> {
50 if (Obj.isCOFF()) {
52 return std::make_unique<LVCodeViewReader>(Filename, FileFormatName,
53 *COFF, W, ExePath);
54 }
55 if (Obj.isELF() || Obj.isMachO() || Obj.isWasm())
56 return std::make_unique<LVDWARFReader>(Filename, FileFormatName, Obj,
57 W);
58 }
59 if (isa<PDBFile *>(Input)) {
61 return std::make_unique<LVCodeViewReader>(Filename, FileFormatName, Pdb,
62 W, ExePath);
63 }
64 if (IRObjectFile *Ir = dyn_cast<IRObjectFile *>(Input)) {
65 return std::make_unique<LVIRReader>(Filename, FileFormatName, Ir, W);
66 }
67 if (MemoryBufferRef *MemBuf = dyn_cast<MemoryBufferRef *>(Input)) {
68 // If the filename extension is '.ll' create an IR reader.
69 const StringRef IRFileExt = ".ll";
70 if (llvm::sys::path::extension(Filename) == IRFileExt)
71 return std::make_unique<LVIRReader>(Filename, IRFileFormatName, MemBuf,
72 W);
73 }
74 return nullptr;
75 };
76
77 std::unique_ptr<LVReader> ReaderObj = CreateOneReader();
78 if (!ReaderObj)
80 "unable to create reader for: '%s'",
81 Filename.str().c_str());
82
83 LVReader *Reader = ReaderObj.get();
84 Readers.emplace_back(std::move(ReaderObj));
85 return Reader->doLoad();
86}
87
88Error LVReaderHandler::handleArchive(LVReaders &Readers, StringRef Filename,
89 Archive &Arch) {
90 Error Err = Error::success();
91 for (const Archive::Child &Child : Arch.children(Err)) {
92 Expected<MemoryBufferRef> BuffOrErr = Child.getMemoryBufferRef();
93 if (Error Err = BuffOrErr.takeError())
94 return createStringError(errorToErrorCode(std::move(Err)), "%s",
95 Filename.str().c_str());
96 Expected<StringRef> NameOrErr = Child.getName();
97 if (Error Err = NameOrErr.takeError())
98 return createStringError(errorToErrorCode(std::move(Err)), "%s",
99 Filename.str().c_str());
100 std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();
101 if (Error Err = handleBuffer(Readers, Name, BuffOrErr.get()))
102 return createStringError(errorToErrorCode(std::move(Err)), "%s",
103 Filename.str().c_str());
104 }
105
106 if (Err)
107 return createStringError(errorToErrorCode(std::move(Err)), "%s",
108 Filename.str().c_str());
109 return Error::success();
110}
111
112// Search for a matching executable image for the given PDB path.
113static std::string searchForExe(const StringRef Path,
114 const StringRef Extension) {
115 SmallString<128> ExePath(Path);
117
118 std::unique_ptr<IPDBSession> Session;
119 if (Error Err = loadDataForEXE(PDB_ReaderType::Native, ExePath, Session)) {
120 consumeError(std::move(Err));
121 return {};
122 }
123 // We have a candidate for the executable image.
124 Expected<std::string> PdbPathOrErr = NativeSession::searchForPdb({ExePath});
125 if (!PdbPathOrErr) {
126 consumeError(PdbPathOrErr.takeError());
127 return {};
128 }
129 // Convert any Windows backslashes into forward slashes to get the path.
130 std::string ConvertedPath = sys::path::convert_to_slash(
131 PdbPathOrErr.get(), sys::path::Style::windows);
132 if (ConvertedPath == Path)
133 return std::string(ExePath);
134
135 return {};
136}
137
138// Search for a matching object image for the given PDB path.
139static std::string searchForObj(const StringRef Path,
140 const StringRef Extension) {
141 SmallString<128> ObjPath(Path);
143 if (llvm::sys::fs::exists(ObjPath)) {
146 if (!BuffOrErr)
147 return {};
148 return std::string(ObjPath);
149 }
150
151 return {};
152}
153
154Error LVReaderHandler::handleBuffer(LVReaders &Readers, StringRef Filename,
155 MemoryBufferRef Buffer, StringRef ExePath) {
156 // As PDB does not support the Binary interface, at this point we can check
157 // if the buffer corresponds to a PDB or PE file.
158 file_magic FileMagic = identify_magic(Buffer.getBuffer());
159 if (FileMagic == file_magic::pdb) {
160 if (!ExePath.empty())
161 return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath);
162
163 // Search in the directory derived from the given 'Filename' for a
164 // matching object file (.o, .obj, .lib) or a matching executable file
165 // (.exe/.dll) and try to create the reader based on the matched file.
166 // If no matching file is found then we load the original PDB file.
167 std::vector<StringRef> ExecutableExtensions = {"exe", "dll"};
168 for (StringRef Extension : ExecutableExtensions) {
169 std::string ExecutableImage = searchForExe(Filename, Extension);
170 if (ExecutableImage.empty())
171 continue;
172 if (Error Err = handleObject(Readers, Filename, Buffer.getBuffer(),
173 ExecutableImage)) {
174 consumeError(std::move(Err));
175 continue;
176 }
177 return Error::success();
178 }
179
180 std::vector<StringRef> ObjectExtensions = {"o", "obj", "lib"};
181 for (StringRef Extension : ObjectExtensions) {
182 std::string ObjectImage = searchForObj(Filename, Extension);
183 if (ObjectImage.empty())
184 continue;
185 if (Error Err = handleFile(Readers, ObjectImage)) {
186 consumeError(std::move(Err));
187 continue;
188 }
189 return Error::success();
190 }
191
192 // No matching executable/object image was found. Load the given PDB.
193 return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath);
194 }
195 if (FileMagic == file_magic::pecoff_executable) {
196 // If we have a valid executable, try to find a matching PDB file.
197 Expected<std::string> PdbPath = NativeSession::searchForPdb({Filename});
198 if (errorToErrorCode(PdbPath.takeError())) {
199 return createStringError(
201 "Binary object format in '%s' does not have debug info.",
202 Filename.str().c_str());
203 }
204 // Process the matching PDB file and pass the executable filename.
205 return handleFile(Readers, PdbPath.get(), Filename);
206 }
207
208 LLVMContext Context;
209 Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer, &Context);
210 if (errorToErrorCode(BinOrErr.takeError())) {
211 // Assume it is LLVM IR.
212 return handleObject(Readers, Filename, Buffer);
213 }
214 return handleObject(Readers, Filename, *BinOrErr.get());
215}
216
217Error LVReaderHandler::handleFile(LVReaders &Readers, StringRef Filename,
218 StringRef ExePath) {
219 // Convert any Windows backslashes into forward slashes to get the path.
220 std::string ConvertedPath =
222 ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
223 MemoryBuffer::getFileOrSTDIN(ConvertedPath);
224 if (BuffOrErr.getError()) {
226 "File '%s' does not exist.",
227 ConvertedPath.c_str());
228 }
229 std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
230 return handleBuffer(Readers, ConvertedPath, *Buffer, ExePath);
231}
232
233Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename,
234 MachOUniversalBinary &Mach) {
235 for (const MachOUniversalBinary::ObjectForArch &ObjForArch : Mach.objects()) {
236 std::string ObjName = (Twine(Filename) + Twine("(") +
237 Twine(ObjForArch.getArchFlagName()) + Twine(")"))
238 .str();
239 if (Expected<std::unique_ptr<MachOObjectFile>> MachOOrErr =
240 ObjForArch.getAsObjectFile()) {
241 MachOObjectFile &Obj = **MachOOrErr;
242 InputHandle Input = &Obj;
243 if (Error Err =
244 createReader(Filename, Readers, Input, Obj.getFileFormatName()))
245 return Err;
246 continue;
247 } else
248 consumeError(MachOOrErr.takeError());
249 if (Expected<std::unique_ptr<Archive>> ArchiveOrErr =
250 ObjForArch.getAsArchive()) {
251 if (Error Err = handleArchive(Readers, ObjName, *ArchiveOrErr.get()))
252 return Err;
253 continue;
254 } else
255 consumeError(ArchiveOrErr.takeError());
256 }
257 return Error::success();
258}
259
260Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
261 Binary &Binary) {
262 if (InputHandle Input = dyn_cast<ObjectFile>(&Binary))
263 return createReader(Filename, Readers, Input,
264 cast<ObjectFile *>(Input)->getFileFormatName());
265
266 if (MachOUniversalBinary *Fat = dyn_cast<MachOUniversalBinary>(&Binary))
267 return handleMach(Readers, Filename, *Fat);
268
269 if (Archive *Arch = dyn_cast<Archive>(&Binary))
270 return handleArchive(Readers, Filename, *Arch);
271
272 if (InputHandle Input = dyn_cast<IRObjectFile>(&Binary))
273 return createReader(Filename, Readers, Input, "Bitcode IR");
274
276 "Binary object format in '%s' is not supported.",
277 Filename.str().c_str());
278}
279
280Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
281 StringRef Buffer, StringRef ExePath) {
282 std::unique_ptr<IPDBSession> Session;
283 if (Error Err = loadDataForPDB(PDB_ReaderType::Native, Filename, Session))
284 return createStringError(errorToErrorCode(std::move(Err)), "%s",
285 Filename.str().c_str());
286
287 std::unique_ptr<NativeSession> PdbSession;
288 PdbSession.reset(static_cast<NativeSession *>(Session.release()));
289 InputHandle Input = &PdbSession->getPDBFile();
290 StringRef FileFormatName;
291 size_t Pos = Buffer.find_first_of("\r\n");
292 if (Pos)
293 FileFormatName = Buffer.substr(0, Pos - 1);
294 return createReader(Filename, Readers, Input, FileFormatName, ExePath);
295}
296
297Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
298 MemoryBufferRef Buffer) {
299 InputHandle Input = cast<MemoryBufferRef>(&Buffer);
300 return createReader(Filename, Readers, Input, IRFileFormatName);
301}
302
303Error LVReaderHandler::createReaders() {
304 LLVM_DEBUG(dbgs() << "createReaders\n");
305 for (std::string &Object : Objects) {
306 LVReaders Readers;
307 if (Error Err = createReader(Object, Readers))
308 return Err;
309 TheReaders.insert(TheReaders.end(),
310 std::make_move_iterator(Readers.begin()),
311 std::make_move_iterator(Readers.end()));
312 }
313
314 return Error::success();
315}
316
317Error LVReaderHandler::printReaders() {
318 LLVM_DEBUG(dbgs() << "printReaders\n");
319 if (options().getPrintExecute())
320 for (const std::unique_ptr<LVReader> &Reader : TheReaders)
321 if (Error Err = Reader->doPrint())
322 return Err;
323
324 return Error::success();
325}
326
327Error LVReaderHandler::compareReaders() {
328 LLVM_DEBUG(dbgs() << "compareReaders\n");
329 size_t ReadersCount = TheReaders.size();
330 if (options().getCompareExecute() && ReadersCount >= 2) {
331 // If we have more than 2 readers, compare them by pairs.
332 size_t ViewPairs = ReadersCount / 2;
333 LVCompare Compare(OS);
334 for (size_t Pair = 0, Index = 0; Pair < ViewPairs; ++Pair) {
335 if (Error Err = Compare.execute(TheReaders[Index].get(),
336 TheReaders[Index + 1].get()))
337 return Err;
338 Index += 2;
339 }
340 }
341
342 return Error::success();
343}
344
345void LVReaderHandler::print(raw_ostream &OS) const { OS << "ReaderHandler\n"; }
static constexpr StringRef IRFileFormatName
static std::string searchForObj(const StringRef Path, const StringRef Extension)
static std::string searchForExe(const StringRef Path, const StringRef Extension)
static constexpr StringLiteral Filename
#define LLVM_DEBUG(...)
Definition Debug.h:119
The Input class is used to parse a yaml document into in-memory structs and vectors.
Represents either an error or a value T.
Definition ErrorOr.h:56
reference get()
Definition ErrorOr.h:149
std::error_code getError() const
Definition ErrorOr.h:152
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
reference get()
Returns a reference to the stored T value.
Definition Error.h:582
StringRef getBuffer() const
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition StringRef.h:591
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
size_t find_first_of(char C, size_t From=0) const
Find the first character in the string that is C, or npos if not found.
Definition StringRef.h:396
LLVM_ABI void print(raw_ostream &OS) const
iterator_range< child_iterator > children(Error &Err, bool SkipInternal=true) const
Definition Archive.h:404
iterator_range< object_iterator > objects() const
static Expected< std::string > searchForPdb(const PdbSearchOptions &Opts)
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
std::vector< std::unique_ptr< LVReader > > LVReaders
PointerUnion< object::ObjectFile *, pdb::PDBFile *, object::IRObjectFile *, MemoryBufferRef *, StringRef * > InputHandle
LVOptions & options()
Definition LVOptions.h:448
LLVM_ABI Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)
Create a Binary from Source, autodetecting the file type.
Definition Binary.cpp:45
LLVM_ABI Error loadDataForEXE(PDB_ReaderType Type, StringRef Path, std::unique_ptr< IPDBSession > &Session)
Definition PDB.cpp:35
LLVM_ABI Error loadDataForPDB(PDB_ReaderType Type, StringRef Path, std::unique_ptr< IPDBSession > &Session)
Definition PDB.cpp:22
LLVM_ABI bool exists(const basic_file_status &status)
Does file exist?
Definition Path.cpp:1107
LLVM_ABI void replace_extension(SmallVectorImpl< char > &path, const Twine &extension, Style style=Style::native)
Replace the file extension of path with extension.
Definition Path.cpp:491
LLVM_ABI std::string convert_to_slash(StringRef path, Style style=Style::native)
Replaces backslashes with slashes if Windows.
Definition Path.cpp:585
LLVM_ABI StringRef extension(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get extension.
Definition Path.cpp:607
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI file_magic identify_magic(StringRef magic)
Identify the type of a binary file based on how magical it is.
Definition Magic.cpp:33
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
@ bad_file_descriptor
Definition Errc.h:39
@ not_supported
Definition Errc.h:69
@ invalid_argument
Definition Errc.h:56
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI std::error_code errorToErrorCode(Error Err)
Helper for converting an ECError to a std::error_code.
Definition Error.cpp:113
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1106
@ pdb
Windows PDB debug info file.
Definition Magic.h:55
@ pecoff_executable
PECOFF executable file.
Definition Magic.h:50