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