Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
35271 views
//===-- LVReaderHandler.cpp -----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This class implements the Reader Handler.9//10//===----------------------------------------------------------------------===//1112#include "llvm/DebugInfo/LogicalView/LVReaderHandler.h"13#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"14#include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"15#include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h"16#include "llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h"17#include "llvm/DebugInfo/PDB/Native/NativeSession.h"18#include "llvm/DebugInfo/PDB/PDB.h"19#include "llvm/Object/COFF.h"2021using namespace llvm;22using namespace llvm::object;23using namespace llvm::pdb;24using namespace llvm::logicalview;2526#define DEBUG_TYPE "ReaderHandler"2728Error LVReaderHandler::process() {29if (Error Err = createReaders())30return Err;31if (Error Err = printReaders())32return Err;33if (Error Err = compareReaders())34return Err;3536return Error::success();37}3839Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,40PdbOrObj &Input, StringRef FileFormatName,41StringRef ExePath) {42auto CreateOneReader = [&]() -> std::unique_ptr<LVReader> {43if (isa<ObjectFile *>(Input)) {44ObjectFile &Obj = *cast<ObjectFile *>(Input);45if (Obj.isCOFF()) {46COFFObjectFile *COFF = cast<COFFObjectFile>(&Obj);47return std::make_unique<LVCodeViewReader>(Filename, FileFormatName,48*COFF, W, ExePath);49}50if (Obj.isELF() || Obj.isMachO() || Obj.isWasm())51return std::make_unique<LVDWARFReader>(Filename, FileFormatName, Obj,52W);53}54if (isa<PDBFile *>(Input)) {55PDBFile &Pdb = *cast<PDBFile *>(Input);56return std::make_unique<LVCodeViewReader>(Filename, FileFormatName, Pdb,57W, ExePath);58}59return nullptr;60};6162std::unique_ptr<LVReader> ReaderObj = CreateOneReader();63if (!ReaderObj)64return createStringError(errc::invalid_argument,65"unable to create reader for: '%s'",66Filename.str().c_str());6768LVReader *Reader = ReaderObj.get();69Readers.emplace_back(std::move(ReaderObj));70return Reader->doLoad();71}7273Error LVReaderHandler::handleArchive(LVReaders &Readers, StringRef Filename,74Archive &Arch) {75Error Err = Error::success();76for (const Archive::Child &Child : Arch.children(Err)) {77Expected<MemoryBufferRef> BuffOrErr = Child.getMemoryBufferRef();78if (Error Err = BuffOrErr.takeError())79return createStringError(errorToErrorCode(std::move(Err)), "%s",80Filename.str().c_str());81Expected<StringRef> NameOrErr = Child.getName();82if (Error Err = NameOrErr.takeError())83return createStringError(errorToErrorCode(std::move(Err)), "%s",84Filename.str().c_str());85std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();86if (Error Err = handleBuffer(Readers, Name, BuffOrErr.get()))87return createStringError(errorToErrorCode(std::move(Err)), "%s",88Filename.str().c_str());89}9091return Error::success();92}9394// Search for a matching executable image for the given PDB path.95static std::string searchForExe(const StringRef Path,96const StringRef Extension) {97SmallString<128> ExePath(Path);98llvm::sys::path::replace_extension(ExePath, Extension);99100std::unique_ptr<IPDBSession> Session;101if (Error Err = loadDataForEXE(PDB_ReaderType::Native, ExePath, Session)) {102consumeError(std::move(Err));103return {};104}105// We have a candidate for the executable image.106Expected<std::string> PdbPathOrErr = NativeSession::searchForPdb({ExePath});107if (!PdbPathOrErr) {108consumeError(PdbPathOrErr.takeError());109return {};110}111// Convert any Windows backslashes into forward slashes to get the path.112std::string ConvertedPath = sys::path::convert_to_slash(113PdbPathOrErr.get(), sys::path::Style::windows);114if (ConvertedPath == Path)115return std::string(ExePath);116117return {};118}119120// Search for a matching object image for the given PDB path.121static std::string searchForObj(const StringRef Path,122const StringRef Extension) {123SmallString<128> ObjPath(Path);124llvm::sys::path::replace_extension(ObjPath, Extension);125if (llvm::sys::fs::exists(ObjPath)) {126ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =127MemoryBuffer::getFileOrSTDIN(ObjPath);128if (!BuffOrErr)129return {};130return std::string(ObjPath);131}132133return {};134}135136Error LVReaderHandler::handleBuffer(LVReaders &Readers, StringRef Filename,137MemoryBufferRef Buffer, StringRef ExePath) {138// As PDB does not support the Binary interface, at this point we can check139// if the buffer corresponds to a PDB or PE file.140file_magic FileMagic = identify_magic(Buffer.getBuffer());141if (FileMagic == file_magic::pdb) {142if (!ExePath.empty())143return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath);144145// Search in the directory derived from the given 'Filename' for a146// matching object file (.o, .obj, .lib) or a matching executable file147// (.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.149std::vector<StringRef> ExecutableExtensions = {"exe", "dll"};150for (StringRef Extension : ExecutableExtensions) {151std::string ExecutableImage = searchForExe(Filename, Extension);152if (ExecutableImage.empty())153continue;154if (Error Err = handleObject(Readers, Filename, Buffer.getBuffer(),155ExecutableImage)) {156consumeError(std::move(Err));157continue;158}159return Error::success();160}161162std::vector<StringRef> ObjectExtensions = {"o", "obj", "lib"};163for (StringRef Extension : ObjectExtensions) {164std::string ObjectImage = searchForObj(Filename, Extension);165if (ObjectImage.empty())166continue;167if (Error Err = handleFile(Readers, ObjectImage)) {168consumeError(std::move(Err));169continue;170}171return Error::success();172}173174// No matching executable/object image was found. Load the given PDB.175return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath);176}177if (FileMagic == file_magic::pecoff_executable) {178// If we have a valid executable, try to find a matching PDB file.179Expected<std::string> PdbPath = NativeSession::searchForPdb({Filename});180if (errorToErrorCode(PdbPath.takeError())) {181return createStringError(182errc::not_supported,183"Binary object format in '%s' does not have debug info.",184Filename.str().c_str());185}186// Process the matching PDB file and pass the executable filename.187return handleFile(Readers, PdbPath.get(), Filename);188}189190Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer);191if (errorToErrorCode(BinOrErr.takeError())) {192return createStringError(errc::not_supported,193"Binary object format in '%s' is not supported.",194Filename.str().c_str());195}196return handleObject(Readers, Filename, *BinOrErr.get());197}198199Error LVReaderHandler::handleFile(LVReaders &Readers, StringRef Filename,200StringRef ExePath) {201// Convert any Windows backslashes into forward slashes to get the path.202std::string ConvertedPath =203sys::path::convert_to_slash(Filename, sys::path::Style::windows);204ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =205MemoryBuffer::getFileOrSTDIN(ConvertedPath);206if (BuffOrErr.getError()) {207return createStringError(errc::bad_file_descriptor,208"File '%s' does not exist.",209ConvertedPath.c_str());210}211std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());212return handleBuffer(Readers, ConvertedPath, *Buffer, ExePath);213}214215Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename,216MachOUniversalBinary &Mach) {217for (const MachOUniversalBinary::ObjectForArch &ObjForArch : Mach.objects()) {218std::string ObjName = (Twine(Filename) + Twine("(") +219Twine(ObjForArch.getArchFlagName()) + Twine(")"))220.str();221if (Expected<std::unique_ptr<MachOObjectFile>> MachOOrErr =222ObjForArch.getAsObjectFile()) {223MachOObjectFile &Obj = **MachOOrErr;224PdbOrObj Input = &Obj;225if (Error Err =226createReader(Filename, Readers, Input, Obj.getFileFormatName()))227return Err;228continue;229} else230consumeError(MachOOrErr.takeError());231if (Expected<std::unique_ptr<Archive>> ArchiveOrErr =232ObjForArch.getAsArchive()) {233if (Error Err = handleArchive(Readers, ObjName, *ArchiveOrErr.get()))234return Err;235continue;236} else237consumeError(ArchiveOrErr.takeError());238}239return Error::success();240}241242Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,243Binary &Binary) {244if (PdbOrObj Input = dyn_cast<ObjectFile>(&Binary))245return createReader(Filename, Readers, Input,246cast<ObjectFile *>(Input)->getFileFormatName());247248if (MachOUniversalBinary *Fat = dyn_cast<MachOUniversalBinary>(&Binary))249return handleMach(Readers, Filename, *Fat);250251if (Archive *Arch = dyn_cast<Archive>(&Binary))252return handleArchive(Readers, Filename, *Arch);253254return createStringError(errc::not_supported,255"Binary object format in '%s' is not supported.",256Filename.str().c_str());257}258259Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,260StringRef Buffer, StringRef ExePath) {261std::unique_ptr<IPDBSession> Session;262if (Error Err = loadDataForPDB(PDB_ReaderType::Native, Filename, Session))263return createStringError(errorToErrorCode(std::move(Err)), "%s",264Filename.str().c_str());265266std::unique_ptr<NativeSession> PdbSession;267PdbSession.reset(static_cast<NativeSession *>(Session.release()));268PdbOrObj Input = &PdbSession->getPDBFile();269StringRef FileFormatName;270size_t Pos = Buffer.find_first_of("\r\n");271if (Pos)272FileFormatName = Buffer.substr(0, Pos - 1);273return createReader(Filename, Readers, Input, FileFormatName, ExePath);274}275276Error LVReaderHandler::createReaders() {277LLVM_DEBUG(dbgs() << "createReaders\n");278for (std::string &Object : Objects) {279LVReaders Readers;280if (Error Err = createReader(Object, Readers))281return Err;282TheReaders.insert(TheReaders.end(),283std::make_move_iterator(Readers.begin()),284std::make_move_iterator(Readers.end()));285}286287return Error::success();288}289290Error LVReaderHandler::printReaders() {291LLVM_DEBUG(dbgs() << "printReaders\n");292if (options().getPrintExecute())293for (const std::unique_ptr<LVReader> &Reader : TheReaders)294if (Error Err = Reader->doPrint())295return Err;296297return Error::success();298}299300Error LVReaderHandler::compareReaders() {301LLVM_DEBUG(dbgs() << "compareReaders\n");302size_t ReadersCount = TheReaders.size();303if (options().getCompareExecute() && ReadersCount >= 2) {304// If we have more than 2 readers, compare them by pairs.305size_t ViewPairs = ReadersCount / 2;306LVCompare Compare(OS);307for (size_t Pair = 0, Index = 0; Pair < ViewPairs; ++Pair) {308if (Error Err = Compare.execute(TheReaders[Index].get(),309TheReaders[Index + 1].get()))310return Err;311Index += 2;312}313}314315return Error::success();316}317318void LVReaderHandler::print(raw_ostream &OS) const { OS << "ReaderHandler\n"; }319320321