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/LogicalView/Core/LVCompare.h"
15 #include "llvm/DebugInfo/LogicalView/Readers/LVELFReader.h"
16 
17 using namespace llvm;
18 using namespace llvm::object;
19 using namespace llvm::pdb;
20 using namespace llvm::logicalview;
21 
22 #define DEBUG_TYPE "ReaderHandler"
23 
24 Error LVReaderHandler::process() {
25   if (Error Err = createReaders())
26     return Err;
27   if (Error Err = printReaders())
28     return Err;
29   if (Error Err = compareReaders())
30     return Err;
31 
32   return Error::success();
33 }
34 
35 void LVReaderHandler::destroyReaders() {
36   LLVM_DEBUG(dbgs() << "destroyReaders\n");
37   for (const LVReader *Reader : TheReaders)
38     delete Reader;
39 }
40 
41 Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,
42                                     PdbOrObj &Input, StringRef FileFormatName,
43                                     StringRef ExePath) {
44   auto CreateOneReader = [&]() -> LVReader * {
45     if (Input.is<ObjectFile *>()) {
46       ObjectFile &Obj = *Input.get<ObjectFile *>();
47       if (Obj.isELF() || Obj.isMachO())
48         return new LVELFReader(Filename, FileFormatName, Obj, W);
49     }
50     return nullptr;
51   };
52 
53   LVReader *Reader = CreateOneReader();
54   if (!Reader)
55     return createStringError(errc::invalid_argument,
56                              "unable to create reader for: '%s'",
57                              Filename.str().c_str());
58 
59   Readers.push_back(Reader);
60   return Reader->doLoad();
61 }
62 
63 Error LVReaderHandler::handleArchive(LVReaders &Readers, StringRef Filename,
64                                      Archive &Arch) {
65   Error Err = Error::success();
66   for (const Archive::Child &Child : Arch.children(Err)) {
67     Expected<MemoryBufferRef> BuffOrErr = Child.getMemoryBufferRef();
68     if (Error Err = BuffOrErr.takeError())
69       return createStringError(errorToErrorCode(std::move(Err)), "%s",
70                                Filename.str().c_str());
71     Expected<StringRef> NameOrErr = Child.getName();
72     if (Error Err = NameOrErr.takeError())
73       return createStringError(errorToErrorCode(std::move(Err)), "%s",
74                                Filename.str().c_str());
75     std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();
76     if (Error Err = handleBuffer(Readers, Name, BuffOrErr.get()))
77       return createStringError(errorToErrorCode(std::move(Err)), "%s",
78                                Filename.str().c_str());
79   }
80 
81   return Error::success();
82 }
83 
84 Error LVReaderHandler::handleBuffer(LVReaders &Readers, StringRef Filename,
85                                     MemoryBufferRef Buffer, StringRef ExePath) {
86   Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer);
87   if (errorToErrorCode(BinOrErr.takeError())) {
88     return createStringError(errc::not_supported,
89                              "Binary object format in '%s' is not supported.",
90                              Filename.str().c_str());
91   }
92   return handleObject(Readers, Filename, *BinOrErr.get());
93 }
94 
95 Error LVReaderHandler::handleFile(LVReaders &Readers, StringRef Filename,
96                                   StringRef ExePath) {
97   // Convert any Windows backslashes into forward slashes to get the path.
98   std::string ConvertedPath =
99       sys::path::convert_to_slash(Filename, sys::path::Style::windows);
100   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
101       MemoryBuffer::getFileOrSTDIN(ConvertedPath);
102   if (BuffOrErr.getError()) {
103     return createStringError(errc::bad_file_descriptor,
104                              "File '%s' does not exist.",
105                              ConvertedPath.c_str());
106   }
107   std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
108   return handleBuffer(Readers, ConvertedPath, *Buffer, ExePath);
109 }
110 
111 Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename,
112                                   MachOUniversalBinary &Mach) {
113   for (const MachOUniversalBinary::ObjectForArch &ObjForArch : Mach.objects()) {
114     std::string ObjName = (Twine(Filename) + Twine("(") +
115                            Twine(ObjForArch.getArchFlagName()) + Twine(")"))
116                               .str();
117     if (Expected<std::unique_ptr<MachOObjectFile>> MachOOrErr =
118             ObjForArch.getAsObjectFile()) {
119       MachOObjectFile &Obj = **MachOOrErr;
120       PdbOrObj Input = &Obj;
121       if (Error Err =
122               createReader(Filename, Readers, Input, Obj.getFileFormatName()))
123         return Err;
124       continue;
125     } else
126       consumeError(MachOOrErr.takeError());
127     if (Expected<std::unique_ptr<Archive>> ArchiveOrErr =
128             ObjForArch.getAsArchive()) {
129       if (Error Err = handleArchive(Readers, ObjName, *ArchiveOrErr.get()))
130         return Err;
131       continue;
132     } else
133       consumeError(ArchiveOrErr.takeError());
134   }
135   return Error::success();
136 }
137 
138 Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
139                                     Binary &Binary) {
140   if (PdbOrObj Input = dyn_cast<ObjectFile>(&Binary))
141     return createReader(Filename, Readers, Input,
142                         Input.get<ObjectFile *>()->getFileFormatName());
143 
144   if (MachOUniversalBinary *Fat = dyn_cast<MachOUniversalBinary>(&Binary))
145     return handleMach(Readers, Filename, *Fat);
146 
147   if (Archive *Arch = dyn_cast<Archive>(&Binary))
148     return handleArchive(Readers, Filename, *Arch);
149 
150   return createStringError(errc::not_supported,
151                            "Binary object format in '%s' is not supported.",
152                            Filename.str().c_str());
153 }
154 
155 Error LVReaderHandler::createReaders() {
156   LLVM_DEBUG(dbgs() << "createReaders\n");
157   for (std::string &Object : Objects) {
158     LVReaders Readers;
159     if (Error Err = createReader(Object, Readers))
160       return Err;
161     TheReaders.insert(TheReaders.end(), Readers.begin(), Readers.end());
162   }
163 
164   return Error::success();
165 }
166 
167 Error LVReaderHandler::printReaders() {
168   LLVM_DEBUG(dbgs() << "printReaders\n");
169   if (options().getPrintExecute())
170     for (LVReader *Reader : TheReaders)
171       if (Error Err = Reader->doPrint())
172         return Err;
173 
174   return Error::success();
175 }
176 
177 Error LVReaderHandler::compareReaders() {
178   LLVM_DEBUG(dbgs() << "compareReaders\n");
179   size_t ReadersCount = TheReaders.size();
180   if (options().getCompareExecute() && ReadersCount >= 2) {
181     // If we have more than 2 readers, compare them by pairs.
182     size_t ViewPairs = ReadersCount / 2;
183     LVCompare Compare(OS);
184     for (size_t Pair = 0, Index = 0; Pair < ViewPairs; ++Pair) {
185       if (Error Err = Compare.execute(TheReaders[Index], TheReaders[Index + 1]))
186         return Err;
187       Index += 2;
188     }
189   }
190 
191   return Error::success();
192 }
193 
194 void LVReaderHandler::print(raw_ostream &OS) const { OS << "ReaderHandler\n"; }
195