xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
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() || 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 
handleArchive(LVReaders & Readers,StringRef Filename,Archive & Arch)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.
searchForExe(const StringRef Path,const StringRef Extension)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.
searchForObj(const StringRef Path,const StringRef Extension)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 
handleBuffer(LVReaders & Readers,StringRef Filename,MemoryBufferRef Buffer,StringRef ExePath)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 
handleFile(LVReaders & Readers,StringRef Filename,StringRef ExePath)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 
handleMach(LVReaders & Readers,StringRef Filename,MachOUniversalBinary & Mach)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 
handleObject(LVReaders & Readers,StringRef Filename,Binary & Binary)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 
handleObject(LVReaders & Readers,StringRef Filename,StringRef Buffer,StringRef ExePath)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 
createReaders()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 
printReaders()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 
compareReaders()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 
print(raw_ostream & OS) const319 void LVReaderHandler::print(raw_ostream &OS) const { OS << "ReaderHandler\n"; }
320