brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.3 KiB · 69513f2 Raw
322 lines · cpp
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-exception6//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/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"20 21using namespace llvm;22using namespace llvm::object;23using namespace llvm::pdb;24using namespace llvm::logicalview;25 26#define DEBUG_TYPE "ReaderHandler"27 28Error LVReaderHandler::process() {29  if (Error Err = createReaders())30    return Err;31  if (Error Err = printReaders())32    return Err;33  if (Error Err = compareReaders())34    return Err;35 36  return Error::success();37}38 39Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,40                                    PdbOrObj &Input, StringRef FileFormatName,41                                    StringRef ExePath) {42  auto CreateOneReader = [&]() -> std::unique_ptr<LVReader> {43    if (isa<ObjectFile *>(Input)) {44      ObjectFile &Obj = *cast<ObjectFile *>(Input);45      if (Obj.isCOFF()) {46        COFFObjectFile *COFF = cast<COFFObjectFile>(&Obj);47        return std::make_unique<LVCodeViewReader>(Filename, FileFormatName,48                                                  *COFF, W, ExePath);49      }50      if (Obj.isELF() || Obj.isMachO() || Obj.isWasm())51        return std::make_unique<LVDWARFReader>(Filename, FileFormatName, Obj,52                                               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  if (Err)92    return createStringError(errorToErrorCode(std::move(Err)), "%s",93                             Filename.str().c_str());94  return Error::success();95}96 97// Search for a matching executable image for the given PDB path.98static std::string searchForExe(const StringRef Path,99                                const StringRef Extension) {100  SmallString<128> ExePath(Path);101  llvm::sys::path::replace_extension(ExePath, Extension);102 103  std::unique_ptr<IPDBSession> Session;104  if (Error Err = loadDataForEXE(PDB_ReaderType::Native, ExePath, Session)) {105    consumeError(std::move(Err));106    return {};107  }108  // We have a candidate for the executable image.109  Expected<std::string> PdbPathOrErr = NativeSession::searchForPdb({ExePath});110  if (!PdbPathOrErr) {111    consumeError(PdbPathOrErr.takeError());112    return {};113  }114  // Convert any Windows backslashes into forward slashes to get the path.115  std::string ConvertedPath = sys::path::convert_to_slash(116      PdbPathOrErr.get(), sys::path::Style::windows);117  if (ConvertedPath == Path)118    return std::string(ExePath);119 120  return {};121}122 123// Search for a matching object image for the given PDB path.124static std::string searchForObj(const StringRef Path,125                                const StringRef Extension) {126  SmallString<128> ObjPath(Path);127  llvm::sys::path::replace_extension(ObjPath, Extension);128  if (llvm::sys::fs::exists(ObjPath)) {129    ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =130        MemoryBuffer::getFileOrSTDIN(ObjPath);131    if (!BuffOrErr)132      return {};133    return std::string(ObjPath);134  }135 136  return {};137}138 139Error LVReaderHandler::handleBuffer(LVReaders &Readers, StringRef Filename,140                                    MemoryBufferRef Buffer, StringRef ExePath) {141  // As PDB does not support the Binary interface, at this point we can check142  // if the buffer corresponds to a PDB or PE file.143  file_magic FileMagic = identify_magic(Buffer.getBuffer());144  if (FileMagic == file_magic::pdb) {145    if (!ExePath.empty())146      return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath);147 148    // Search in the directory derived from the given 'Filename' for a149    // matching object file (.o, .obj, .lib) or a matching executable file150    // (.exe/.dll) and try to create the reader based on the matched file.151    // If no matching file is found then we load the original PDB file.152    std::vector<StringRef> ExecutableExtensions = {"exe", "dll"};153    for (StringRef Extension : ExecutableExtensions) {154      std::string ExecutableImage = searchForExe(Filename, Extension);155      if (ExecutableImage.empty())156        continue;157      if (Error Err = handleObject(Readers, Filename, Buffer.getBuffer(),158                                   ExecutableImage)) {159        consumeError(std::move(Err));160        continue;161      }162      return Error::success();163    }164 165    std::vector<StringRef> ObjectExtensions = {"o", "obj", "lib"};166    for (StringRef Extension : ObjectExtensions) {167      std::string ObjectImage = searchForObj(Filename, Extension);168      if (ObjectImage.empty())169        continue;170      if (Error Err = handleFile(Readers, ObjectImage)) {171        consumeError(std::move(Err));172        continue;173      }174      return Error::success();175    }176 177    // No matching executable/object image was found. Load the given PDB.178    return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath);179  }180  if (FileMagic == file_magic::pecoff_executable) {181    // If we have a valid executable, try to find a matching PDB file.182    Expected<std::string> PdbPath = NativeSession::searchForPdb({Filename});183    if (errorToErrorCode(PdbPath.takeError())) {184      return createStringError(185          errc::not_supported,186          "Binary object format in '%s' does not have debug info.",187          Filename.str().c_str());188    }189    // Process the matching PDB file and pass the executable filename.190    return handleFile(Readers, PdbPath.get(), Filename);191  }192 193  Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer);194  if (errorToErrorCode(BinOrErr.takeError())) {195    return createStringError(errc::not_supported,196                             "Binary object format in '%s' is not supported.",197                             Filename.str().c_str());198  }199  return handleObject(Readers, Filename, *BinOrErr.get());200}201 202Error LVReaderHandler::handleFile(LVReaders &Readers, StringRef Filename,203                                  StringRef ExePath) {204  // Convert any Windows backslashes into forward slashes to get the path.205  std::string ConvertedPath =206      sys::path::convert_to_slash(Filename, sys::path::Style::windows);207  ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =208      MemoryBuffer::getFileOrSTDIN(ConvertedPath);209  if (BuffOrErr.getError()) {210    return createStringError(errc::bad_file_descriptor,211                             "File '%s' does not exist.",212                             ConvertedPath.c_str());213  }214  std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());215  return handleBuffer(Readers, ConvertedPath, *Buffer, ExePath);216}217 218Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename,219                                  MachOUniversalBinary &Mach) {220  for (const MachOUniversalBinary::ObjectForArch &ObjForArch : Mach.objects()) {221    std::string ObjName = (Twine(Filename) + Twine("(") +222                           Twine(ObjForArch.getArchFlagName()) + Twine(")"))223                              .str();224    if (Expected<std::unique_ptr<MachOObjectFile>> MachOOrErr =225            ObjForArch.getAsObjectFile()) {226      MachOObjectFile &Obj = **MachOOrErr;227      PdbOrObj Input = &Obj;228      if (Error Err =229              createReader(Filename, Readers, Input, Obj.getFileFormatName()))230        return Err;231      continue;232    } else233      consumeError(MachOOrErr.takeError());234    if (Expected<std::unique_ptr<Archive>> ArchiveOrErr =235            ObjForArch.getAsArchive()) {236      if (Error Err = handleArchive(Readers, ObjName, *ArchiveOrErr.get()))237        return Err;238      continue;239    } else240      consumeError(ArchiveOrErr.takeError());241  }242  return Error::success();243}244 245Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,246                                    Binary &Binary) {247  if (PdbOrObj Input = dyn_cast<ObjectFile>(&Binary))248    return createReader(Filename, Readers, Input,249                        cast<ObjectFile *>(Input)->getFileFormatName());250 251  if (MachOUniversalBinary *Fat = dyn_cast<MachOUniversalBinary>(&Binary))252    return handleMach(Readers, Filename, *Fat);253 254  if (Archive *Arch = dyn_cast<Archive>(&Binary))255    return handleArchive(Readers, Filename, *Arch);256 257  return createStringError(errc::not_supported,258                           "Binary object format in '%s' is not supported.",259                           Filename.str().c_str());260}261 262Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,263                                    StringRef Buffer, StringRef ExePath) {264  std::unique_ptr<IPDBSession> Session;265  if (Error Err = loadDataForPDB(PDB_ReaderType::Native, Filename, Session))266    return createStringError(errorToErrorCode(std::move(Err)), "%s",267                             Filename.str().c_str());268 269  std::unique_ptr<NativeSession> PdbSession;270  PdbSession.reset(static_cast<NativeSession *>(Session.release()));271  PdbOrObj Input = &PdbSession->getPDBFile();272  StringRef FileFormatName;273  size_t Pos = Buffer.find_first_of("\r\n");274  if (Pos)275    FileFormatName = Buffer.substr(0, Pos - 1);276  return createReader(Filename, Readers, Input, FileFormatName, ExePath);277}278 279Error LVReaderHandler::createReaders() {280  LLVM_DEBUG(dbgs() << "createReaders\n");281  for (std::string &Object : Objects) {282    LVReaders Readers;283    if (Error Err = createReader(Object, Readers))284      return Err;285    TheReaders.insert(TheReaders.end(),286                      std::make_move_iterator(Readers.begin()),287                      std::make_move_iterator(Readers.end()));288  }289 290  return Error::success();291}292 293Error LVReaderHandler::printReaders() {294  LLVM_DEBUG(dbgs() << "printReaders\n");295  if (options().getPrintExecute())296    for (const std::unique_ptr<LVReader> &Reader : TheReaders)297      if (Error Err = Reader->doPrint())298        return Err;299 300  return Error::success();301}302 303Error LVReaderHandler::compareReaders() {304  LLVM_DEBUG(dbgs() << "compareReaders\n");305  size_t ReadersCount = TheReaders.size();306  if (options().getCompareExecute() && ReadersCount >= 2) {307    // If we have more than 2 readers, compare them by pairs.308    size_t ViewPairs = ReadersCount / 2;309    LVCompare Compare(OS);310    for (size_t Pair = 0, Index = 0; Pair < ViewPairs; ++Pair) {311      if (Error Err = Compare.execute(TheReaders[Index].get(),312                                      TheReaders[Index + 1].get()))313        return Err;314      Index += 2;315    }316  }317 318  return Error::success();319}320 321void LVReaderHandler::print(raw_ostream &OS) const { OS << "ReaderHandler\n"; }322