xref: /llvm-project/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp (revision 37e48e4a7360a6faf1b157e843160d9e65223890)
14f06d46fSCarlos Alberto Enciso //===-- LVReaderHandler.cpp -----------------------------------------------===//
24f06d46fSCarlos Alberto Enciso //
34f06d46fSCarlos Alberto Enciso // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44f06d46fSCarlos Alberto Enciso // See https://llvm.org/LICENSE.txt for license information.
54f06d46fSCarlos Alberto Enciso // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64f06d46fSCarlos Alberto Enciso //
74f06d46fSCarlos Alberto Enciso //===----------------------------------------------------------------------===//
84f06d46fSCarlos Alberto Enciso //
94f06d46fSCarlos Alberto Enciso // This class implements the Reader Handler.
104f06d46fSCarlos Alberto Enciso //
114f06d46fSCarlos Alberto Enciso //===----------------------------------------------------------------------===//
124f06d46fSCarlos Alberto Enciso 
134f06d46fSCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/LVReaderHandler.h"
144f06d46fSCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
15e7950fceSCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h"
16c1ccf078SCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h"
17e7950fceSCarlos Alberto Enciso #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
18e7950fceSCarlos Alberto Enciso #include "llvm/DebugInfo/PDB/PDB.h"
19e7950fceSCarlos Alberto Enciso #include "llvm/Object/COFF.h"
204f06d46fSCarlos Alberto Enciso 
214f06d46fSCarlos Alberto Enciso using namespace llvm;
224f06d46fSCarlos Alberto Enciso using namespace llvm::object;
234f06d46fSCarlos Alberto Enciso using namespace llvm::pdb;
244f06d46fSCarlos Alberto Enciso using namespace llvm::logicalview;
254f06d46fSCarlos Alberto Enciso 
264f06d46fSCarlos Alberto Enciso #define DEBUG_TYPE "ReaderHandler"
274f06d46fSCarlos Alberto Enciso 
284f06d46fSCarlos Alberto Enciso Error LVReaderHandler::process() {
294f06d46fSCarlos Alberto Enciso   if (Error Err = createReaders())
304f06d46fSCarlos Alberto Enciso     return Err;
314f06d46fSCarlos Alberto Enciso   if (Error Err = printReaders())
324f06d46fSCarlos Alberto Enciso     return Err;
334f06d46fSCarlos Alberto Enciso   if (Error Err = compareReaders())
344f06d46fSCarlos Alberto Enciso     return Err;
354f06d46fSCarlos Alberto Enciso 
364f06d46fSCarlos Alberto Enciso   return Error::success();
374f06d46fSCarlos Alberto Enciso }
384f06d46fSCarlos Alberto Enciso 
394f06d46fSCarlos Alberto Enciso Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,
404f06d46fSCarlos Alberto Enciso                                     PdbOrObj &Input, StringRef FileFormatName,
414f06d46fSCarlos Alberto Enciso                                     StringRef ExePath) {
427fbcc244SCarlos Alberto Enciso   auto CreateOneReader = [&]() -> std::unique_ptr<LVReader> {
437021182dSShraiysh Vaishay     if (isa<ObjectFile *>(Input)) {
447021182dSShraiysh Vaishay       ObjectFile &Obj = *cast<ObjectFile *>(Input);
45e7950fceSCarlos Alberto Enciso       if (Obj.isCOFF()) {
46e7950fceSCarlos Alberto Enciso         COFFObjectFile *COFF = cast<COFFObjectFile>(&Obj);
47e7950fceSCarlos Alberto Enciso         return std::make_unique<LVCodeViewReader>(Filename, FileFormatName,
48e7950fceSCarlos Alberto Enciso                                                   *COFF, W, ExePath);
49e7950fceSCarlos Alberto Enciso       }
50b19cfb91SCarlos Alberto Enciso       if (Obj.isELF() || Obj.isMachO() || Obj.isWasm())
51c1ccf078SCarlos Alberto Enciso         return std::make_unique<LVDWARFReader>(Filename, FileFormatName, Obj,
52c1ccf078SCarlos Alberto Enciso                                                W);
534f06d46fSCarlos Alberto Enciso     }
547021182dSShraiysh Vaishay     if (isa<PDBFile *>(Input)) {
557021182dSShraiysh Vaishay       PDBFile &Pdb = *cast<PDBFile *>(Input);
56e7950fceSCarlos Alberto Enciso       return std::make_unique<LVCodeViewReader>(Filename, FileFormatName, Pdb,
57e7950fceSCarlos Alberto Enciso                                                 W, ExePath);
58e7950fceSCarlos Alberto Enciso     }
594f06d46fSCarlos Alberto Enciso     return nullptr;
604f06d46fSCarlos Alberto Enciso   };
614f06d46fSCarlos Alberto Enciso 
627fbcc244SCarlos Alberto Enciso   std::unique_ptr<LVReader> ReaderObj = CreateOneReader();
637fbcc244SCarlos Alberto Enciso   if (!ReaderObj)
644f06d46fSCarlos Alberto Enciso     return createStringError(errc::invalid_argument,
654f06d46fSCarlos Alberto Enciso                              "unable to create reader for: '%s'",
664f06d46fSCarlos Alberto Enciso                              Filename.str().c_str());
674f06d46fSCarlos Alberto Enciso 
687fbcc244SCarlos Alberto Enciso   LVReader *Reader = ReaderObj.get();
697fbcc244SCarlos Alberto Enciso   Readers.emplace_back(std::move(ReaderObj));
704f06d46fSCarlos Alberto Enciso   return Reader->doLoad();
714f06d46fSCarlos Alberto Enciso }
724f06d46fSCarlos Alberto Enciso 
734f06d46fSCarlos Alberto Enciso Error LVReaderHandler::handleArchive(LVReaders &Readers, StringRef Filename,
744f06d46fSCarlos Alberto Enciso                                      Archive &Arch) {
754f06d46fSCarlos Alberto Enciso   Error Err = Error::success();
764f06d46fSCarlos Alberto Enciso   for (const Archive::Child &Child : Arch.children(Err)) {
774f06d46fSCarlos Alberto Enciso     Expected<MemoryBufferRef> BuffOrErr = Child.getMemoryBufferRef();
784f06d46fSCarlos Alberto Enciso     if (Error Err = BuffOrErr.takeError())
794f06d46fSCarlos Alberto Enciso       return createStringError(errorToErrorCode(std::move(Err)), "%s",
804f06d46fSCarlos Alberto Enciso                                Filename.str().c_str());
814f06d46fSCarlos Alberto Enciso     Expected<StringRef> NameOrErr = Child.getName();
824f06d46fSCarlos Alberto Enciso     if (Error Err = NameOrErr.takeError())
834f06d46fSCarlos Alberto Enciso       return createStringError(errorToErrorCode(std::move(Err)), "%s",
844f06d46fSCarlos Alberto Enciso                                Filename.str().c_str());
854f06d46fSCarlos Alberto Enciso     std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();
864f06d46fSCarlos Alberto Enciso     if (Error Err = handleBuffer(Readers, Name, BuffOrErr.get()))
874f06d46fSCarlos Alberto Enciso       return createStringError(errorToErrorCode(std::move(Err)), "%s",
884f06d46fSCarlos Alberto Enciso                                Filename.str().c_str());
894f06d46fSCarlos Alberto Enciso   }
904f06d46fSCarlos Alberto Enciso 
91*37e48e4aSaurelien35   if (Err)
92*37e48e4aSaurelien35     return createStringError(errorToErrorCode(std::move(Err)), "%s",
93*37e48e4aSaurelien35                              Filename.str().c_str());
944f06d46fSCarlos Alberto Enciso   return Error::success();
954f06d46fSCarlos Alberto Enciso }
964f06d46fSCarlos Alberto Enciso 
97e7950fceSCarlos Alberto Enciso // Search for a matching executable image for the given PDB path.
98e7950fceSCarlos Alberto Enciso static std::string searchForExe(const StringRef Path,
99e7950fceSCarlos Alberto Enciso                                 const StringRef Extension) {
100e7950fceSCarlos Alberto Enciso   SmallString<128> ExePath(Path);
101e7950fceSCarlos Alberto Enciso   llvm::sys::path::replace_extension(ExePath, Extension);
102e7950fceSCarlos Alberto Enciso 
103e7950fceSCarlos Alberto Enciso   std::unique_ptr<IPDBSession> Session;
104e7950fceSCarlos Alberto Enciso   if (Error Err = loadDataForEXE(PDB_ReaderType::Native, ExePath, Session)) {
105e7950fceSCarlos Alberto Enciso     consumeError(std::move(Err));
106e7950fceSCarlos Alberto Enciso     return {};
107e7950fceSCarlos Alberto Enciso   }
108e7950fceSCarlos Alberto Enciso   // We have a candidate for the executable image.
109e7950fceSCarlos Alberto Enciso   Expected<std::string> PdbPathOrErr = NativeSession::searchForPdb({ExePath});
110e7950fceSCarlos Alberto Enciso   if (!PdbPathOrErr) {
111e7950fceSCarlos Alberto Enciso     consumeError(PdbPathOrErr.takeError());
112e7950fceSCarlos Alberto Enciso     return {};
113e7950fceSCarlos Alberto Enciso   }
114e7950fceSCarlos Alberto Enciso   // Convert any Windows backslashes into forward slashes to get the path.
115e7950fceSCarlos Alberto Enciso   std::string ConvertedPath = sys::path::convert_to_slash(
116e7950fceSCarlos Alberto Enciso       PdbPathOrErr.get(), sys::path::Style::windows);
117e7950fceSCarlos Alberto Enciso   if (ConvertedPath == Path)
118e7950fceSCarlos Alberto Enciso     return std::string(ExePath);
119e7950fceSCarlos Alberto Enciso 
120e7950fceSCarlos Alberto Enciso   return {};
121e7950fceSCarlos Alberto Enciso }
122e7950fceSCarlos Alberto Enciso 
123e7950fceSCarlos Alberto Enciso // Search for a matching object image for the given PDB path.
124e7950fceSCarlos Alberto Enciso static std::string searchForObj(const StringRef Path,
125e7950fceSCarlos Alberto Enciso                                 const StringRef Extension) {
126e7950fceSCarlos Alberto Enciso   SmallString<128> ObjPath(Path);
127e7950fceSCarlos Alberto Enciso   llvm::sys::path::replace_extension(ObjPath, Extension);
128e7950fceSCarlos Alberto Enciso   if (llvm::sys::fs::exists(ObjPath)) {
129e7950fceSCarlos Alberto Enciso     ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
130e7950fceSCarlos Alberto Enciso         MemoryBuffer::getFileOrSTDIN(ObjPath);
131e7950fceSCarlos Alberto Enciso     if (!BuffOrErr)
132e7950fceSCarlos Alberto Enciso       return {};
133e7950fceSCarlos Alberto Enciso     return std::string(ObjPath);
134e7950fceSCarlos Alberto Enciso   }
135e7950fceSCarlos Alberto Enciso 
136e7950fceSCarlos Alberto Enciso   return {};
137e7950fceSCarlos Alberto Enciso }
138e7950fceSCarlos Alberto Enciso 
1394f06d46fSCarlos Alberto Enciso Error LVReaderHandler::handleBuffer(LVReaders &Readers, StringRef Filename,
1404f06d46fSCarlos Alberto Enciso                                     MemoryBufferRef Buffer, StringRef ExePath) {
141e7950fceSCarlos Alberto Enciso   // As PDB does not support the Binary interface, at this point we can check
142e7950fceSCarlos Alberto Enciso   // if the buffer corresponds to a PDB or PE file.
143e7950fceSCarlos Alberto Enciso   file_magic FileMagic = identify_magic(Buffer.getBuffer());
144e7950fceSCarlos Alberto Enciso   if (FileMagic == file_magic::pdb) {
145e7950fceSCarlos Alberto Enciso     if (!ExePath.empty())
146e7950fceSCarlos Alberto Enciso       return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath);
147e7950fceSCarlos Alberto Enciso 
148e7950fceSCarlos Alberto Enciso     // Search in the directory derived from the given 'Filename' for a
149e7950fceSCarlos Alberto Enciso     // matching object file (.o, .obj, .lib) or a matching executable file
150e7950fceSCarlos Alberto Enciso     // (.exe/.dll) and try to create the reader based on the matched file.
151e7950fceSCarlos Alberto Enciso     // If no matching file is found then we load the original PDB file.
152e7950fceSCarlos Alberto Enciso     std::vector<StringRef> ExecutableExtensions = {"exe", "dll"};
153e7950fceSCarlos Alberto Enciso     for (StringRef Extension : ExecutableExtensions) {
154e7950fceSCarlos Alberto Enciso       std::string ExecutableImage = searchForExe(Filename, Extension);
155e7950fceSCarlos Alberto Enciso       if (ExecutableImage.empty())
156e7950fceSCarlos Alberto Enciso         continue;
157e7950fceSCarlos Alberto Enciso       if (Error Err = handleObject(Readers, Filename, Buffer.getBuffer(),
158e7950fceSCarlos Alberto Enciso                                    ExecutableImage)) {
159e7950fceSCarlos Alberto Enciso         consumeError(std::move(Err));
160e7950fceSCarlos Alberto Enciso         continue;
161e7950fceSCarlos Alberto Enciso       }
162e7950fceSCarlos Alberto Enciso       return Error::success();
163e7950fceSCarlos Alberto Enciso     }
164e7950fceSCarlos Alberto Enciso 
165e7950fceSCarlos Alberto Enciso     std::vector<StringRef> ObjectExtensions = {"o", "obj", "lib"};
166e7950fceSCarlos Alberto Enciso     for (StringRef Extension : ObjectExtensions) {
167e7950fceSCarlos Alberto Enciso       std::string ObjectImage = searchForObj(Filename, Extension);
168e7950fceSCarlos Alberto Enciso       if (ObjectImage.empty())
169e7950fceSCarlos Alberto Enciso         continue;
170e7950fceSCarlos Alberto Enciso       if (Error Err = handleFile(Readers, ObjectImage)) {
171e7950fceSCarlos Alberto Enciso         consumeError(std::move(Err));
172e7950fceSCarlos Alberto Enciso         continue;
173e7950fceSCarlos Alberto Enciso       }
174e7950fceSCarlos Alberto Enciso       return Error::success();
175e7950fceSCarlos Alberto Enciso     }
176e7950fceSCarlos Alberto Enciso 
177e7950fceSCarlos Alberto Enciso     // No matching executable/object image was found. Load the given PDB.
178e7950fceSCarlos Alberto Enciso     return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath);
179e7950fceSCarlos Alberto Enciso   }
180e7950fceSCarlos Alberto Enciso   if (FileMagic == file_magic::pecoff_executable) {
181e7950fceSCarlos Alberto Enciso     // If we have a valid executable, try to find a matching PDB file.
182e7950fceSCarlos Alberto Enciso     Expected<std::string> PdbPath = NativeSession::searchForPdb({Filename});
183e7950fceSCarlos Alberto Enciso     if (errorToErrorCode(PdbPath.takeError())) {
184e7950fceSCarlos Alberto Enciso       return createStringError(
185e7950fceSCarlos Alberto Enciso           errc::not_supported,
186e7950fceSCarlos Alberto Enciso           "Binary object format in '%s' does not have debug info.",
187e7950fceSCarlos Alberto Enciso           Filename.str().c_str());
188e7950fceSCarlos Alberto Enciso     }
189e7950fceSCarlos Alberto Enciso     // Process the matching PDB file and pass the executable filename.
190e7950fceSCarlos Alberto Enciso     return handleFile(Readers, PdbPath.get(), Filename);
191e7950fceSCarlos Alberto Enciso   }
192e7950fceSCarlos Alberto Enciso 
1934f06d46fSCarlos Alberto Enciso   Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer);
1944f06d46fSCarlos Alberto Enciso   if (errorToErrorCode(BinOrErr.takeError())) {
1954f06d46fSCarlos Alberto Enciso     return createStringError(errc::not_supported,
1964f06d46fSCarlos Alberto Enciso                              "Binary object format in '%s' is not supported.",
1974f06d46fSCarlos Alberto Enciso                              Filename.str().c_str());
1984f06d46fSCarlos Alberto Enciso   }
1994f06d46fSCarlos Alberto Enciso   return handleObject(Readers, Filename, *BinOrErr.get());
2004f06d46fSCarlos Alberto Enciso }
2014f06d46fSCarlos Alberto Enciso 
2024f06d46fSCarlos Alberto Enciso Error LVReaderHandler::handleFile(LVReaders &Readers, StringRef Filename,
2034f06d46fSCarlos Alberto Enciso                                   StringRef ExePath) {
2044f06d46fSCarlos Alberto Enciso   // Convert any Windows backslashes into forward slashes to get the path.
2054f06d46fSCarlos Alberto Enciso   std::string ConvertedPath =
2064f06d46fSCarlos Alberto Enciso       sys::path::convert_to_slash(Filename, sys::path::Style::windows);
2074f06d46fSCarlos Alberto Enciso   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
2084f06d46fSCarlos Alberto Enciso       MemoryBuffer::getFileOrSTDIN(ConvertedPath);
2094f06d46fSCarlos Alberto Enciso   if (BuffOrErr.getError()) {
2104f06d46fSCarlos Alberto Enciso     return createStringError(errc::bad_file_descriptor,
2114f06d46fSCarlos Alberto Enciso                              "File '%s' does not exist.",
2124f06d46fSCarlos Alberto Enciso                              ConvertedPath.c_str());
2134f06d46fSCarlos Alberto Enciso   }
2144f06d46fSCarlos Alberto Enciso   std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
2154f06d46fSCarlos Alberto Enciso   return handleBuffer(Readers, ConvertedPath, *Buffer, ExePath);
2164f06d46fSCarlos Alberto Enciso }
2174f06d46fSCarlos Alberto Enciso 
2184f06d46fSCarlos Alberto Enciso Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename,
2194f06d46fSCarlos Alberto Enciso                                   MachOUniversalBinary &Mach) {
2204f06d46fSCarlos Alberto Enciso   for (const MachOUniversalBinary::ObjectForArch &ObjForArch : Mach.objects()) {
2214f06d46fSCarlos Alberto Enciso     std::string ObjName = (Twine(Filename) + Twine("(") +
2224f06d46fSCarlos Alberto Enciso                            Twine(ObjForArch.getArchFlagName()) + Twine(")"))
2234f06d46fSCarlos Alberto Enciso                               .str();
2244f06d46fSCarlos Alberto Enciso     if (Expected<std::unique_ptr<MachOObjectFile>> MachOOrErr =
2254f06d46fSCarlos Alberto Enciso             ObjForArch.getAsObjectFile()) {
2264f06d46fSCarlos Alberto Enciso       MachOObjectFile &Obj = **MachOOrErr;
2274f06d46fSCarlos Alberto Enciso       PdbOrObj Input = &Obj;
2284f06d46fSCarlos Alberto Enciso       if (Error Err =
2294f06d46fSCarlos Alberto Enciso               createReader(Filename, Readers, Input, Obj.getFileFormatName()))
2304f06d46fSCarlos Alberto Enciso         return Err;
2314f06d46fSCarlos Alberto Enciso       continue;
2324f06d46fSCarlos Alberto Enciso     } else
2334f06d46fSCarlos Alberto Enciso       consumeError(MachOOrErr.takeError());
2344f06d46fSCarlos Alberto Enciso     if (Expected<std::unique_ptr<Archive>> ArchiveOrErr =
2354f06d46fSCarlos Alberto Enciso             ObjForArch.getAsArchive()) {
2364f06d46fSCarlos Alberto Enciso       if (Error Err = handleArchive(Readers, ObjName, *ArchiveOrErr.get()))
2374f06d46fSCarlos Alberto Enciso         return Err;
2384f06d46fSCarlos Alberto Enciso       continue;
2394f06d46fSCarlos Alberto Enciso     } else
2404f06d46fSCarlos Alberto Enciso       consumeError(ArchiveOrErr.takeError());
2414f06d46fSCarlos Alberto Enciso   }
2424f06d46fSCarlos Alberto Enciso   return Error::success();
2434f06d46fSCarlos Alberto Enciso }
2444f06d46fSCarlos Alberto Enciso 
2454f06d46fSCarlos Alberto Enciso Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
2464f06d46fSCarlos Alberto Enciso                                     Binary &Binary) {
2474f06d46fSCarlos Alberto Enciso   if (PdbOrObj Input = dyn_cast<ObjectFile>(&Binary))
2484f06d46fSCarlos Alberto Enciso     return createReader(Filename, Readers, Input,
2497021182dSShraiysh Vaishay                         cast<ObjectFile *>(Input)->getFileFormatName());
2504f06d46fSCarlos Alberto Enciso 
2514f06d46fSCarlos Alberto Enciso   if (MachOUniversalBinary *Fat = dyn_cast<MachOUniversalBinary>(&Binary))
2524f06d46fSCarlos Alberto Enciso     return handleMach(Readers, Filename, *Fat);
2534f06d46fSCarlos Alberto Enciso 
2544f06d46fSCarlos Alberto Enciso   if (Archive *Arch = dyn_cast<Archive>(&Binary))
2554f06d46fSCarlos Alberto Enciso     return handleArchive(Readers, Filename, *Arch);
2564f06d46fSCarlos Alberto Enciso 
2574f06d46fSCarlos Alberto Enciso   return createStringError(errc::not_supported,
2584f06d46fSCarlos Alberto Enciso                            "Binary object format in '%s' is not supported.",
2594f06d46fSCarlos Alberto Enciso                            Filename.str().c_str());
2604f06d46fSCarlos Alberto Enciso }
2614f06d46fSCarlos Alberto Enciso 
262e7950fceSCarlos Alberto Enciso Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
263e7950fceSCarlos Alberto Enciso                                     StringRef Buffer, StringRef ExePath) {
264e7950fceSCarlos Alberto Enciso   std::unique_ptr<IPDBSession> Session;
265e7950fceSCarlos Alberto Enciso   if (Error Err = loadDataForPDB(PDB_ReaderType::Native, Filename, Session))
266e7950fceSCarlos Alberto Enciso     return createStringError(errorToErrorCode(std::move(Err)), "%s",
267e7950fceSCarlos Alberto Enciso                              Filename.str().c_str());
268e7950fceSCarlos Alberto Enciso 
269e7950fceSCarlos Alberto Enciso   std::unique_ptr<NativeSession> PdbSession;
270e7950fceSCarlos Alberto Enciso   PdbSession.reset(static_cast<NativeSession *>(Session.release()));
271e7950fceSCarlos Alberto Enciso   PdbOrObj Input = &PdbSession->getPDBFile();
272e7950fceSCarlos Alberto Enciso   StringRef FileFormatName;
273e7950fceSCarlos Alberto Enciso   size_t Pos = Buffer.find_first_of("\r\n");
274e7950fceSCarlos Alberto Enciso   if (Pos)
275e7950fceSCarlos Alberto Enciso     FileFormatName = Buffer.substr(0, Pos - 1);
276e7950fceSCarlos Alberto Enciso   return createReader(Filename, Readers, Input, FileFormatName, ExePath);
277e7950fceSCarlos Alberto Enciso }
278e7950fceSCarlos Alberto Enciso 
2794f06d46fSCarlos Alberto Enciso Error LVReaderHandler::createReaders() {
2804f06d46fSCarlos Alberto Enciso   LLVM_DEBUG(dbgs() << "createReaders\n");
2814f06d46fSCarlos Alberto Enciso   for (std::string &Object : Objects) {
2824f06d46fSCarlos Alberto Enciso     LVReaders Readers;
2834f06d46fSCarlos Alberto Enciso     if (Error Err = createReader(Object, Readers))
2844f06d46fSCarlos Alberto Enciso       return Err;
2857fbcc244SCarlos Alberto Enciso     TheReaders.insert(TheReaders.end(),
2867fbcc244SCarlos Alberto Enciso                       std::make_move_iterator(Readers.begin()),
2877fbcc244SCarlos Alberto Enciso                       std::make_move_iterator(Readers.end()));
2884f06d46fSCarlos Alberto Enciso   }
2894f06d46fSCarlos Alberto Enciso 
2904f06d46fSCarlos Alberto Enciso   return Error::success();
2914f06d46fSCarlos Alberto Enciso }
2924f06d46fSCarlos Alberto Enciso 
2934f06d46fSCarlos Alberto Enciso Error LVReaderHandler::printReaders() {
2944f06d46fSCarlos Alberto Enciso   LLVM_DEBUG(dbgs() << "printReaders\n");
2954f06d46fSCarlos Alberto Enciso   if (options().getPrintExecute())
2967fbcc244SCarlos Alberto Enciso     for (const std::unique_ptr<LVReader> &Reader : TheReaders)
2974f06d46fSCarlos Alberto Enciso       if (Error Err = Reader->doPrint())
2984f06d46fSCarlos Alberto Enciso         return Err;
2994f06d46fSCarlos Alberto Enciso 
3004f06d46fSCarlos Alberto Enciso   return Error::success();
3014f06d46fSCarlos Alberto Enciso }
3024f06d46fSCarlos Alberto Enciso 
3034f06d46fSCarlos Alberto Enciso Error LVReaderHandler::compareReaders() {
3044f06d46fSCarlos Alberto Enciso   LLVM_DEBUG(dbgs() << "compareReaders\n");
3054f06d46fSCarlos Alberto Enciso   size_t ReadersCount = TheReaders.size();
3064f06d46fSCarlos Alberto Enciso   if (options().getCompareExecute() && ReadersCount >= 2) {
3074f06d46fSCarlos Alberto Enciso     // If we have more than 2 readers, compare them by pairs.
3084f06d46fSCarlos Alberto Enciso     size_t ViewPairs = ReadersCount / 2;
3094f06d46fSCarlos Alberto Enciso     LVCompare Compare(OS);
3104f06d46fSCarlos Alberto Enciso     for (size_t Pair = 0, Index = 0; Pair < ViewPairs; ++Pair) {
3117fbcc244SCarlos Alberto Enciso       if (Error Err = Compare.execute(TheReaders[Index].get(),
3127fbcc244SCarlos Alberto Enciso                                       TheReaders[Index + 1].get()))
3134f06d46fSCarlos Alberto Enciso         return Err;
3144f06d46fSCarlos Alberto Enciso       Index += 2;
3154f06d46fSCarlos Alberto Enciso     }
3164f06d46fSCarlos Alberto Enciso   }
3174f06d46fSCarlos Alberto Enciso 
3184f06d46fSCarlos Alberto Enciso   return Error::success();
3194f06d46fSCarlos Alberto Enciso }
3204f06d46fSCarlos Alberto Enciso 
3214f06d46fSCarlos Alberto Enciso void LVReaderHandler::print(raw_ostream &OS) const { OS << "ReaderHandler\n"; }
322