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