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
22using namespace llvm;
23using namespace llvm::object;
24using namespace llvm::pdb;
25using namespace llvm::logicalview;
26
27#define DEBUG_TYPE "ReaderHandler"
28
29Error 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
40Error 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
73Error 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.
95static 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.
121static 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
136Error 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
199Error 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
215Error 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
242Error 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
259Error 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
276Error 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
290Error 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
300Error 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
318void LVReaderHandler::print(raw_ostream &OS) const { OS << "ReaderHandler\n"; }
319