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"
1406c3fb27SDimitry Andric #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
15bdd1243dSDimitry Andric #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
1606c3fb27SDimitry Andric #include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h"
17*0fca6ea1SDimitry Andric #include "llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h"
1806c3fb27SDimitry Andric #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
1906c3fb27SDimitry Andric #include "llvm/DebugInfo/PDB/PDB.h"
2006c3fb27SDimitry 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
process()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
createReader(StringRef Filename,LVReaders & Readers,PdbOrObj & Input,StringRef FileFormatName,StringRef ExePath)40bdd1243dSDimitry Andric Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,
41bdd1243dSDimitry Andric PdbOrObj &Input, StringRef FileFormatName,
42bdd1243dSDimitry Andric StringRef ExePath) {
4306c3fb27SDimitry Andric auto CreateOneReader = [&]() -> std::unique_ptr<LVReader> {
4406c3fb27SDimitry Andric if (isa<ObjectFile *>(Input)) {
4506c3fb27SDimitry Andric ObjectFile &Obj = *cast<ObjectFile *>(Input);
4606c3fb27SDimitry Andric if (Obj.isCOFF()) {
4706c3fb27SDimitry Andric COFFObjectFile *COFF = cast<COFFObjectFile>(&Obj);
4806c3fb27SDimitry Andric return std::make_unique<LVCodeViewReader>(Filename, FileFormatName,
4906c3fb27SDimitry Andric *COFF, W, ExePath);
5006c3fb27SDimitry Andric }
51*0fca6ea1SDimitry Andric if (Obj.isELF() || Obj.isMachO() || Obj.isWasm())
52*0fca6ea1SDimitry Andric return std::make_unique<LVDWARFReader>(Filename, FileFormatName, Obj,
53*0fca6ea1SDimitry Andric W);
5406c3fb27SDimitry Andric }
5506c3fb27SDimitry Andric if (isa<PDBFile *>(Input)) {
5606c3fb27SDimitry Andric PDBFile &Pdb = *cast<PDBFile *>(Input);
5706c3fb27SDimitry Andric return std::make_unique<LVCodeViewReader>(Filename, FileFormatName, Pdb,
5806c3fb27SDimitry Andric W, ExePath);
59bdd1243dSDimitry Andric }
60bdd1243dSDimitry Andric return nullptr;
61bdd1243dSDimitry Andric };
62bdd1243dSDimitry Andric
6306c3fb27SDimitry Andric std::unique_ptr<LVReader> ReaderObj = CreateOneReader();
6406c3fb27SDimitry Andric if (!ReaderObj)
65bdd1243dSDimitry Andric return createStringError(errc::invalid_argument,
66bdd1243dSDimitry Andric "unable to create reader for: '%s'",
67bdd1243dSDimitry Andric Filename.str().c_str());
68bdd1243dSDimitry Andric
6906c3fb27SDimitry Andric LVReader *Reader = ReaderObj.get();
7006c3fb27SDimitry Andric Readers.emplace_back(std::move(ReaderObj));
71bdd1243dSDimitry Andric return Reader->doLoad();
72bdd1243dSDimitry Andric }
73bdd1243dSDimitry Andric
handleArchive(LVReaders & Readers,StringRef Filename,Archive & Arch)74bdd1243dSDimitry Andric Error LVReaderHandler::handleArchive(LVReaders &Readers, StringRef Filename,
75bdd1243dSDimitry Andric Archive &Arch) {
76bdd1243dSDimitry Andric Error Err = Error::success();
77bdd1243dSDimitry Andric for (const Archive::Child &Child : Arch.children(Err)) {
78bdd1243dSDimitry Andric Expected<MemoryBufferRef> BuffOrErr = Child.getMemoryBufferRef();
79bdd1243dSDimitry Andric if (Error Err = BuffOrErr.takeError())
80bdd1243dSDimitry Andric return createStringError(errorToErrorCode(std::move(Err)), "%s",
81bdd1243dSDimitry Andric Filename.str().c_str());
82bdd1243dSDimitry Andric Expected<StringRef> NameOrErr = Child.getName();
83bdd1243dSDimitry Andric if (Error Err = NameOrErr.takeError())
84bdd1243dSDimitry Andric return createStringError(errorToErrorCode(std::move(Err)), "%s",
85bdd1243dSDimitry Andric Filename.str().c_str());
86bdd1243dSDimitry Andric std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();
87bdd1243dSDimitry Andric if (Error Err = handleBuffer(Readers, Name, BuffOrErr.get()))
88bdd1243dSDimitry Andric return createStringError(errorToErrorCode(std::move(Err)), "%s",
89bdd1243dSDimitry Andric Filename.str().c_str());
90bdd1243dSDimitry Andric }
91bdd1243dSDimitry Andric
92bdd1243dSDimitry Andric return Error::success();
93bdd1243dSDimitry Andric }
94bdd1243dSDimitry Andric
9506c3fb27SDimitry Andric // Search for a matching executable image for the given PDB path.
searchForExe(const StringRef Path,const StringRef Extension)9606c3fb27SDimitry Andric static std::string searchForExe(const StringRef Path,
9706c3fb27SDimitry Andric const StringRef Extension) {
9806c3fb27SDimitry Andric SmallString<128> ExePath(Path);
9906c3fb27SDimitry Andric llvm::sys::path::replace_extension(ExePath, Extension);
10006c3fb27SDimitry Andric
10106c3fb27SDimitry Andric std::unique_ptr<IPDBSession> Session;
10206c3fb27SDimitry Andric if (Error Err = loadDataForEXE(PDB_ReaderType::Native, ExePath, Session)) {
10306c3fb27SDimitry Andric consumeError(std::move(Err));
10406c3fb27SDimitry Andric return {};
10506c3fb27SDimitry Andric }
10606c3fb27SDimitry Andric // We have a candidate for the executable image.
10706c3fb27SDimitry Andric Expected<std::string> PdbPathOrErr = NativeSession::searchForPdb({ExePath});
10806c3fb27SDimitry Andric if (!PdbPathOrErr) {
10906c3fb27SDimitry Andric consumeError(PdbPathOrErr.takeError());
11006c3fb27SDimitry Andric return {};
11106c3fb27SDimitry Andric }
11206c3fb27SDimitry Andric // Convert any Windows backslashes into forward slashes to get the path.
11306c3fb27SDimitry Andric std::string ConvertedPath = sys::path::convert_to_slash(
11406c3fb27SDimitry Andric PdbPathOrErr.get(), sys::path::Style::windows);
11506c3fb27SDimitry Andric if (ConvertedPath == Path)
11606c3fb27SDimitry Andric return std::string(ExePath);
11706c3fb27SDimitry Andric
11806c3fb27SDimitry Andric return {};
11906c3fb27SDimitry Andric }
12006c3fb27SDimitry Andric
12106c3fb27SDimitry Andric // Search for a matching object image for the given PDB path.
searchForObj(const StringRef Path,const StringRef Extension)12206c3fb27SDimitry Andric static std::string searchForObj(const StringRef Path,
12306c3fb27SDimitry Andric const StringRef Extension) {
12406c3fb27SDimitry Andric SmallString<128> ObjPath(Path);
12506c3fb27SDimitry Andric llvm::sys::path::replace_extension(ObjPath, Extension);
12606c3fb27SDimitry Andric if (llvm::sys::fs::exists(ObjPath)) {
12706c3fb27SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
12806c3fb27SDimitry Andric MemoryBuffer::getFileOrSTDIN(ObjPath);
12906c3fb27SDimitry Andric if (!BuffOrErr)
13006c3fb27SDimitry Andric return {};
13106c3fb27SDimitry Andric return std::string(ObjPath);
13206c3fb27SDimitry Andric }
13306c3fb27SDimitry Andric
13406c3fb27SDimitry Andric return {};
13506c3fb27SDimitry Andric }
13606c3fb27SDimitry Andric
handleBuffer(LVReaders & Readers,StringRef Filename,MemoryBufferRef Buffer,StringRef ExePath)137bdd1243dSDimitry Andric Error LVReaderHandler::handleBuffer(LVReaders &Readers, StringRef Filename,
138bdd1243dSDimitry Andric MemoryBufferRef Buffer, StringRef ExePath) {
13906c3fb27SDimitry Andric // As PDB does not support the Binary interface, at this point we can check
14006c3fb27SDimitry Andric // if the buffer corresponds to a PDB or PE file.
14106c3fb27SDimitry Andric file_magic FileMagic = identify_magic(Buffer.getBuffer());
14206c3fb27SDimitry Andric if (FileMagic == file_magic::pdb) {
14306c3fb27SDimitry Andric if (!ExePath.empty())
14406c3fb27SDimitry Andric return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath);
14506c3fb27SDimitry Andric
14606c3fb27SDimitry Andric // Search in the directory derived from the given 'Filename' for a
14706c3fb27SDimitry Andric // matching object file (.o, .obj, .lib) or a matching executable file
14806c3fb27SDimitry Andric // (.exe/.dll) and try to create the reader based on the matched file.
14906c3fb27SDimitry Andric // If no matching file is found then we load the original PDB file.
15006c3fb27SDimitry Andric std::vector<StringRef> ExecutableExtensions = {"exe", "dll"};
15106c3fb27SDimitry Andric for (StringRef Extension : ExecutableExtensions) {
15206c3fb27SDimitry Andric std::string ExecutableImage = searchForExe(Filename, Extension);
15306c3fb27SDimitry Andric if (ExecutableImage.empty())
15406c3fb27SDimitry Andric continue;
15506c3fb27SDimitry Andric if (Error Err = handleObject(Readers, Filename, Buffer.getBuffer(),
15606c3fb27SDimitry Andric ExecutableImage)) {
15706c3fb27SDimitry Andric consumeError(std::move(Err));
15806c3fb27SDimitry Andric continue;
15906c3fb27SDimitry Andric }
16006c3fb27SDimitry Andric return Error::success();
16106c3fb27SDimitry Andric }
16206c3fb27SDimitry Andric
16306c3fb27SDimitry Andric std::vector<StringRef> ObjectExtensions = {"o", "obj", "lib"};
16406c3fb27SDimitry Andric for (StringRef Extension : ObjectExtensions) {
16506c3fb27SDimitry Andric std::string ObjectImage = searchForObj(Filename, Extension);
16606c3fb27SDimitry Andric if (ObjectImage.empty())
16706c3fb27SDimitry Andric continue;
16806c3fb27SDimitry Andric if (Error Err = handleFile(Readers, ObjectImage)) {
16906c3fb27SDimitry Andric consumeError(std::move(Err));
17006c3fb27SDimitry Andric continue;
17106c3fb27SDimitry Andric }
17206c3fb27SDimitry Andric return Error::success();
17306c3fb27SDimitry Andric }
17406c3fb27SDimitry Andric
17506c3fb27SDimitry Andric // No matching executable/object image was found. Load the given PDB.
17606c3fb27SDimitry Andric return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath);
17706c3fb27SDimitry Andric }
17806c3fb27SDimitry Andric if (FileMagic == file_magic::pecoff_executable) {
17906c3fb27SDimitry Andric // If we have a valid executable, try to find a matching PDB file.
18006c3fb27SDimitry Andric Expected<std::string> PdbPath = NativeSession::searchForPdb({Filename});
18106c3fb27SDimitry Andric if (errorToErrorCode(PdbPath.takeError())) {
18206c3fb27SDimitry Andric return createStringError(
18306c3fb27SDimitry Andric errc::not_supported,
18406c3fb27SDimitry Andric "Binary object format in '%s' does not have debug info.",
18506c3fb27SDimitry Andric Filename.str().c_str());
18606c3fb27SDimitry Andric }
18706c3fb27SDimitry Andric // Process the matching PDB file and pass the executable filename.
18806c3fb27SDimitry Andric return handleFile(Readers, PdbPath.get(), Filename);
18906c3fb27SDimitry Andric }
19006c3fb27SDimitry Andric
191bdd1243dSDimitry Andric Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer);
192bdd1243dSDimitry Andric if (errorToErrorCode(BinOrErr.takeError())) {
193bdd1243dSDimitry Andric return createStringError(errc::not_supported,
194bdd1243dSDimitry Andric "Binary object format in '%s' is not supported.",
195bdd1243dSDimitry Andric Filename.str().c_str());
196bdd1243dSDimitry Andric }
197bdd1243dSDimitry Andric return handleObject(Readers, Filename, *BinOrErr.get());
198bdd1243dSDimitry Andric }
199bdd1243dSDimitry Andric
handleFile(LVReaders & Readers,StringRef Filename,StringRef ExePath)200bdd1243dSDimitry Andric Error LVReaderHandler::handleFile(LVReaders &Readers, StringRef Filename,
201bdd1243dSDimitry Andric StringRef ExePath) {
202bdd1243dSDimitry Andric // Convert any Windows backslashes into forward slashes to get the path.
203bdd1243dSDimitry Andric std::string ConvertedPath =
204bdd1243dSDimitry Andric sys::path::convert_to_slash(Filename, sys::path::Style::windows);
205bdd1243dSDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
206bdd1243dSDimitry Andric MemoryBuffer::getFileOrSTDIN(ConvertedPath);
207bdd1243dSDimitry Andric if (BuffOrErr.getError()) {
208bdd1243dSDimitry Andric return createStringError(errc::bad_file_descriptor,
209bdd1243dSDimitry Andric "File '%s' does not exist.",
210bdd1243dSDimitry Andric ConvertedPath.c_str());
211bdd1243dSDimitry Andric }
212bdd1243dSDimitry Andric std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
213bdd1243dSDimitry Andric return handleBuffer(Readers, ConvertedPath, *Buffer, ExePath);
214bdd1243dSDimitry Andric }
215bdd1243dSDimitry Andric
handleMach(LVReaders & Readers,StringRef Filename,MachOUniversalBinary & Mach)216bdd1243dSDimitry Andric Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename,
217bdd1243dSDimitry Andric MachOUniversalBinary &Mach) {
218bdd1243dSDimitry Andric for (const MachOUniversalBinary::ObjectForArch &ObjForArch : Mach.objects()) {
219bdd1243dSDimitry Andric std::string ObjName = (Twine(Filename) + Twine("(") +
220bdd1243dSDimitry Andric Twine(ObjForArch.getArchFlagName()) + Twine(")"))
221bdd1243dSDimitry Andric .str();
222bdd1243dSDimitry Andric if (Expected<std::unique_ptr<MachOObjectFile>> MachOOrErr =
223bdd1243dSDimitry Andric ObjForArch.getAsObjectFile()) {
224bdd1243dSDimitry Andric MachOObjectFile &Obj = **MachOOrErr;
225bdd1243dSDimitry Andric PdbOrObj Input = &Obj;
226bdd1243dSDimitry Andric if (Error Err =
227bdd1243dSDimitry Andric createReader(Filename, Readers, Input, Obj.getFileFormatName()))
228bdd1243dSDimitry Andric return Err;
229bdd1243dSDimitry Andric continue;
230bdd1243dSDimitry Andric } else
231bdd1243dSDimitry Andric consumeError(MachOOrErr.takeError());
232bdd1243dSDimitry Andric if (Expected<std::unique_ptr<Archive>> ArchiveOrErr =
233bdd1243dSDimitry Andric ObjForArch.getAsArchive()) {
234bdd1243dSDimitry Andric if (Error Err = handleArchive(Readers, ObjName, *ArchiveOrErr.get()))
235bdd1243dSDimitry Andric return Err;
236bdd1243dSDimitry Andric continue;
237bdd1243dSDimitry Andric } else
238bdd1243dSDimitry Andric consumeError(ArchiveOrErr.takeError());
239bdd1243dSDimitry Andric }
240bdd1243dSDimitry Andric return Error::success();
241bdd1243dSDimitry Andric }
242bdd1243dSDimitry Andric
handleObject(LVReaders & Readers,StringRef Filename,Binary & Binary)243bdd1243dSDimitry Andric Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
244bdd1243dSDimitry Andric Binary &Binary) {
245bdd1243dSDimitry Andric if (PdbOrObj Input = dyn_cast<ObjectFile>(&Binary))
246bdd1243dSDimitry Andric return createReader(Filename, Readers, Input,
24706c3fb27SDimitry Andric cast<ObjectFile *>(Input)->getFileFormatName());
248bdd1243dSDimitry Andric
249bdd1243dSDimitry Andric if (MachOUniversalBinary *Fat = dyn_cast<MachOUniversalBinary>(&Binary))
250bdd1243dSDimitry Andric return handleMach(Readers, Filename, *Fat);
251bdd1243dSDimitry Andric
252bdd1243dSDimitry Andric if (Archive *Arch = dyn_cast<Archive>(&Binary))
253bdd1243dSDimitry Andric return handleArchive(Readers, Filename, *Arch);
254bdd1243dSDimitry Andric
255bdd1243dSDimitry Andric return createStringError(errc::not_supported,
256bdd1243dSDimitry Andric "Binary object format in '%s' is not supported.",
257bdd1243dSDimitry Andric Filename.str().c_str());
258bdd1243dSDimitry Andric }
259bdd1243dSDimitry Andric
handleObject(LVReaders & Readers,StringRef Filename,StringRef Buffer,StringRef ExePath)26006c3fb27SDimitry Andric Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
26106c3fb27SDimitry Andric StringRef Buffer, StringRef ExePath) {
26206c3fb27SDimitry Andric std::unique_ptr<IPDBSession> Session;
26306c3fb27SDimitry Andric if (Error Err = loadDataForPDB(PDB_ReaderType::Native, Filename, Session))
26406c3fb27SDimitry Andric return createStringError(errorToErrorCode(std::move(Err)), "%s",
26506c3fb27SDimitry Andric Filename.str().c_str());
26606c3fb27SDimitry Andric
26706c3fb27SDimitry Andric std::unique_ptr<NativeSession> PdbSession;
26806c3fb27SDimitry Andric PdbSession.reset(static_cast<NativeSession *>(Session.release()));
26906c3fb27SDimitry Andric PdbOrObj Input = &PdbSession->getPDBFile();
27006c3fb27SDimitry Andric StringRef FileFormatName;
27106c3fb27SDimitry Andric size_t Pos = Buffer.find_first_of("\r\n");
27206c3fb27SDimitry Andric if (Pos)
27306c3fb27SDimitry Andric FileFormatName = Buffer.substr(0, Pos - 1);
27406c3fb27SDimitry Andric return createReader(Filename, Readers, Input, FileFormatName, ExePath);
27506c3fb27SDimitry Andric }
27606c3fb27SDimitry Andric
createReaders()277bdd1243dSDimitry Andric Error LVReaderHandler::createReaders() {
278bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "createReaders\n");
279bdd1243dSDimitry Andric for (std::string &Object : Objects) {
280bdd1243dSDimitry Andric LVReaders Readers;
281bdd1243dSDimitry Andric if (Error Err = createReader(Object, Readers))
282bdd1243dSDimitry Andric return Err;
28306c3fb27SDimitry Andric TheReaders.insert(TheReaders.end(),
28406c3fb27SDimitry Andric std::make_move_iterator(Readers.begin()),
28506c3fb27SDimitry Andric std::make_move_iterator(Readers.end()));
286bdd1243dSDimitry Andric }
287bdd1243dSDimitry Andric
288bdd1243dSDimitry Andric return Error::success();
289bdd1243dSDimitry Andric }
290bdd1243dSDimitry Andric
printReaders()291bdd1243dSDimitry Andric Error LVReaderHandler::printReaders() {
292bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "printReaders\n");
293bdd1243dSDimitry Andric if (options().getPrintExecute())
29406c3fb27SDimitry Andric for (const std::unique_ptr<LVReader> &Reader : TheReaders)
295bdd1243dSDimitry Andric if (Error Err = Reader->doPrint())
296bdd1243dSDimitry Andric return Err;
297bdd1243dSDimitry Andric
298bdd1243dSDimitry Andric return Error::success();
299bdd1243dSDimitry Andric }
300bdd1243dSDimitry Andric
compareReaders()301bdd1243dSDimitry Andric Error LVReaderHandler::compareReaders() {
302bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "compareReaders\n");
303bdd1243dSDimitry Andric size_t ReadersCount = TheReaders.size();
304bdd1243dSDimitry Andric if (options().getCompareExecute() && ReadersCount >= 2) {
305bdd1243dSDimitry Andric // If we have more than 2 readers, compare them by pairs.
306bdd1243dSDimitry Andric size_t ViewPairs = ReadersCount / 2;
307bdd1243dSDimitry Andric LVCompare Compare(OS);
308bdd1243dSDimitry Andric for (size_t Pair = 0, Index = 0; Pair < ViewPairs; ++Pair) {
30906c3fb27SDimitry Andric if (Error Err = Compare.execute(TheReaders[Index].get(),
31006c3fb27SDimitry Andric TheReaders[Index + 1].get()))
311bdd1243dSDimitry Andric return Err;
312bdd1243dSDimitry Andric Index += 2;
313bdd1243dSDimitry Andric }
314bdd1243dSDimitry Andric }
315bdd1243dSDimitry Andric
316bdd1243dSDimitry Andric return Error::success();
317bdd1243dSDimitry Andric }
318bdd1243dSDimitry Andric
print(raw_ostream & OS) const319bdd1243dSDimitry Andric void LVReaderHandler::print(raw_ostream &OS) const { OS << "ReaderHandler\n"; }
320