blob: 392f183f002f884789838bad9fcc4629a3d518b8 [file] [log] [blame]
//===- InputFile.h -------------------------------------------- *- C++ --*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_PDB_NATIVE_INPUTFILE_H
#define LLVM_DEBUGINFO_PDB_NATIVE_INPUTFILE_H
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/iterator.h"
#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
#include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Error.h"
namespace llvm {
namespace codeview {
class LazyRandomTypeCollection;
}
namespace object {
class COFFObjectFile;
} // namespace object
namespace pdb {
class InputFile;
class LinePrinter;
class PDBFile;
class NativeSession;
class SymbolGroupIterator;
class SymbolGroup;
class InputFile {
InputFile();
std::unique_ptr<NativeSession> PdbSession;
object::OwningBinary<object::Binary> CoffObject;
std::unique_ptr<MemoryBuffer> UnknownFile;
PointerUnion<PDBFile *, object::COFFObjectFile *, MemoryBuffer *> PdbOrObj;
using TypeCollectionPtr = std::unique_ptr<codeview::LazyRandomTypeCollection>;
TypeCollectionPtr Types;
TypeCollectionPtr Ids;
enum TypeCollectionKind { kTypes, kIds };
codeview::LazyRandomTypeCollection &
getOrCreateTypeCollection(TypeCollectionKind Kind);
public:
InputFile(PDBFile *Pdb) { PdbOrObj = Pdb; }
InputFile(object::COFFObjectFile *Obj) { PdbOrObj = Obj; }
InputFile(MemoryBuffer *Buffer) { PdbOrObj = Buffer; }
~InputFile();
InputFile(InputFile &&Other) = default;
static Expected<InputFile> open(StringRef Path,
bool AllowUnknownFile = false);
PDBFile &pdb();
const PDBFile &pdb() const;
object::COFFObjectFile &obj();
const object::COFFObjectFile &obj() const;
MemoryBuffer &unknown();
const MemoryBuffer &unknown() const;
StringRef getFilePath() const;
bool hasTypes() const;
bool hasIds() const;
codeview::LazyRandomTypeCollection &types();
codeview::LazyRandomTypeCollection &ids();
iterator_range<SymbolGroupIterator> symbol_groups();
SymbolGroupIterator symbol_groups_begin();
SymbolGroupIterator symbol_groups_end();
bool isPdb() const;
bool isObj() const;
bool isUnknown() const;
};
class SymbolGroup {
friend class SymbolGroupIterator;
public:
explicit SymbolGroup(InputFile *File, uint32_t GroupIndex = 0);
Expected<StringRef> getNameFromStringTable(uint32_t Offset) const;
Expected<StringRef> getNameFromChecksums(uint32_t Offset) const;
void formatFromFileName(LinePrinter &Printer, StringRef File,
bool Append = false) const;
void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset,
bool Append = false) const;
StringRef name() const;
codeview::DebugSubsectionArray getDebugSubsections() const {
return Subsections;
}
const ModuleDebugStreamRef &getPdbModuleStream() const;
const InputFile &getFile() const { return *File; }
InputFile &getFile() { return *File; }
bool hasDebugStream() const { return DebugStream != nullptr; }
private:
void initializeForPdb(uint32_t Modi);
void updatePdbModi(uint32_t Modi);
void updateDebugS(const codeview::DebugSubsectionArray &SS);
void rebuildChecksumMap();
InputFile *File = nullptr;
StringRef Name;
codeview::DebugSubsectionArray Subsections;
std::shared_ptr<ModuleDebugStreamRef> DebugStream;
codeview::StringsAndChecksumsRef SC;
StringMap<codeview::FileChecksumEntry> ChecksumsByFile;
};
class SymbolGroupIterator
: public iterator_facade_base<SymbolGroupIterator,
std::forward_iterator_tag, SymbolGroup> {
public:
SymbolGroupIterator();
explicit SymbolGroupIterator(InputFile &File);
SymbolGroupIterator(const SymbolGroupIterator &Other) = default;
SymbolGroupIterator &operator=(const SymbolGroupIterator &R) = default;
const SymbolGroup &operator*() const;
SymbolGroup &operator*();
bool operator==(const SymbolGroupIterator &R) const;
SymbolGroupIterator &operator++();
private:
void scanToNextDebugS();
bool isEnd() const;
uint32_t Index = 0;
Optional<object::section_iterator> SectionIter;
SymbolGroup Value;
};
Expected<ModuleDebugStreamRef>
getModuleDebugStream(PDBFile &File, StringRef &ModuleName, uint32_t Index);
Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
uint32_t Index);
bool shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group,
const FilterOptions &Filters);
// TODO: Change these callbacks to be function_refs (de-templatify them).
template <typename CallbackT>
Error iterateOneModule(InputFile &File, const PrintScope &HeaderScope,
const SymbolGroup &SG, uint32_t Modi,
CallbackT Callback) {
HeaderScope.P.formatLine(
"Mod {0:4} | `{1}`: ",
fmt_align(Modi, AlignStyle::Right, HeaderScope.LabelWidth), SG.name());
AutoIndent Indent(HeaderScope);
return Callback(Modi, SG);
}
template <typename CallbackT>
Error iterateSymbolGroups(InputFile &Input, const PrintScope &HeaderScope,
CallbackT Callback) {
AutoIndent Indent(HeaderScope);
FilterOptions Filters = HeaderScope.P.getFilters();
if (Filters.DumpModi) {
uint32_t Modi = Filters.DumpModi.getValue();
SymbolGroup SG(&Input, Modi);
return iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(Modi)),
SG, Modi, Callback);
}
uint32_t I = 0;
for (const auto &SG : Input.symbol_groups()) {
if (shouldDumpSymbolGroup(I, SG, Filters))
if (auto Err =
iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(I)),
SG, I, Callback))
return Err;
++I;
}
return Error::success();
}
template <typename SubsectionT>
Error iterateModuleSubsections(
InputFile &File, const PrintScope &HeaderScope,
llvm::function_ref<Error(uint32_t, const SymbolGroup &, SubsectionT &)>
Callback) {
return iterateSymbolGroups(
File, HeaderScope, [&](uint32_t Modi, const SymbolGroup &SG) -> Error {
for (const auto &SS : SG.getDebugSubsections()) {
SubsectionT Subsection;
if (SS.kind() != Subsection.kind())
continue;
BinaryStreamReader Reader(SS.getRecordData());
if (auto Err = Subsection.initialize(Reader))
continue;
if (auto Err = Callback(Modi, SG, Subsection))
return Err;
}
return Error::success();
});
}
} // namespace pdb
} // namespace llvm
#endif