#ifndef LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H
#define LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include <cstdint>
#include <utility>
namespace llvm {
class raw_ostream;
class ScopedPrinter;
class DWARFAcceleratorTable {
protected:
DWARFDataExtractor AccelSection;
DataExtractor StringSection;
public:
class Entry {
protected:
SmallVector<DWARFFormValue, 3> Values;
Entry() = default;
Entry(const Entry &) = default;
Entry(Entry &&) = default;
Entry &operator=(const Entry &) = default;
Entry &operator=(Entry &&) = default;
~Entry() = default;
public:
virtual Optional<uint64_t> getCUOffset() const = 0;
virtual Optional<dwarf::Tag> getTag() const = 0;
ArrayRef<DWARFFormValue> getValues() const { return Values; }
};
DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection,
DataExtractor StringSection)
: AccelSection(AccelSection), StringSection(StringSection) {}
virtual ~DWARFAcceleratorTable();
virtual Error extract() = 0;
virtual void dump(raw_ostream &OS) const = 0;
DWARFAcceleratorTable(const DWARFAcceleratorTable &) = delete;
void operator=(const DWARFAcceleratorTable &) = delete;
};
class AppleAcceleratorTable : public DWARFAcceleratorTable {
struct Header {
uint32_t Magic;
uint16_t Version;
uint16_t HashFunction;
uint32_t BucketCount;
uint32_t HashCount;
uint32_t HeaderDataLength;
void dump(ScopedPrinter &W) const;
};
struct HeaderData {
using AtomType = uint16_t;
using Form = dwarf::Form;
uint64_t DIEOffsetBase;
SmallVector<std::pair<AtomType, Form>, 3> Atoms;
Optional<uint64_t> extractOffset(Optional<DWARFFormValue> Value) const;
};
struct Header Hdr;
struct HeaderData HdrData;
bool IsValid = false;
bool dumpName(ScopedPrinter &W, SmallVectorImpl<DWARFFormValue> &AtomForms,
uint64_t *DataOffset) const;
public:
class Entry final : public DWARFAcceleratorTable::Entry {
const HeaderData *HdrData = nullptr;
Entry(const HeaderData &Data);
Entry() = default;
void extract(const AppleAcceleratorTable &AccelTable, uint64_t *Offset);
public:
Optional<uint64_t> getCUOffset() const override;
Optional<uint64_t> getDIESectionOffset() const;
Optional<dwarf::Tag> getTag() const override;
Optional<DWARFFormValue> lookup(HeaderData::AtomType Atom) const;
friend class AppleAcceleratorTable;
friend class ValueIterator;
};
class ValueIterator {
const AppleAcceleratorTable *AccelTable = nullptr;
Entry Current; uint64_t DataOffset = 0; unsigned Data = 0; unsigned NumData = 0;
void Next();
public:
using iterator_category = std::input_iterator_tag;
using value_type = Entry;
using difference_type = std::ptrdiff_t;
using pointer = value_type *;
using reference = value_type &;
ValueIterator(const AppleAcceleratorTable &AccelTable, uint64_t DataOffset);
ValueIterator() = default;
const Entry &operator*() const { return Current; }
ValueIterator &operator++() { Next(); return *this; }
ValueIterator operator++(int) {
ValueIterator I = *this;
Next();
return I;
}
friend bool operator==(const ValueIterator &A, const ValueIterator &B) {
return A.NumData == B.NumData && A.DataOffset == B.DataOffset;
}
friend bool operator!=(const ValueIterator &A, const ValueIterator &B) {
return !(A == B);
}
};
AppleAcceleratorTable(const DWARFDataExtractor &AccelSection,
DataExtractor StringSection)
: DWARFAcceleratorTable(AccelSection, StringSection) {}
Error extract() override;
uint32_t getNumBuckets();
uint32_t getNumHashes();
uint32_t getSizeHdr();
uint32_t getHeaderDataLength();
ArrayRef<std::pair<HeaderData::AtomType, HeaderData::Form>> getAtomsDesc();
bool validateForms();
std::pair<uint64_t, dwarf::Tag> readAtoms(uint64_t *HashDataOffset);
void dump(raw_ostream &OS) const override;
iterator_range<ValueIterator> equal_range(StringRef Key) const;
};
class DWARFDebugNames : public DWARFAcceleratorTable {
public:
class NameIndex;
class NameIterator;
class ValueIterator;
struct Header {
uint64_t UnitLength;
dwarf::DwarfFormat Format;
uint16_t Version;
uint32_t CompUnitCount;
uint32_t LocalTypeUnitCount;
uint32_t ForeignTypeUnitCount;
uint32_t BucketCount;
uint32_t NameCount;
uint32_t AbbrevTableSize;
uint32_t AugmentationStringSize;
SmallString<8> AugmentationString;
Error extract(const DWARFDataExtractor &AS, uint64_t *Offset);
void dump(ScopedPrinter &W) const;
};
struct AttributeEncoding {
dwarf::Index Index;
dwarf::Form Form;
constexpr AttributeEncoding(dwarf::Index Index, dwarf::Form Form)
: Index(Index), Form(Form) {}
friend bool operator==(const AttributeEncoding &LHS,
const AttributeEncoding &RHS) {
return LHS.Index == RHS.Index && LHS.Form == RHS.Form;
}
};
struct Abbrev {
uint32_t Code; dwarf::Tag Tag; std::vector<AttributeEncoding> Attributes;
Abbrev(uint32_t Code, dwarf::Tag Tag,
std::vector<AttributeEncoding> Attributes)
: Code(Code), Tag(Tag), Attributes(std::move(Attributes)) {}
void dump(ScopedPrinter &W) const;
};
class Entry final : public DWARFAcceleratorTable::Entry {
const NameIndex *NameIdx;
const Abbrev *Abbr;
Entry(const NameIndex &NameIdx, const Abbrev &Abbr);
public:
Optional<uint64_t> getCUOffset() const override;
Optional<dwarf::Tag> getTag() const override { return tag(); }
Optional<uint64_t> getCUIndex() const;
dwarf::Tag tag() const { return Abbr->Tag; }
Optional<uint64_t> getDIEUnitOffset() const;
const Abbrev &getAbbrev() const { return *Abbr; }
Optional<DWARFFormValue> lookup(dwarf::Index Index) const;
void dump(ScopedPrinter &W) const;
friend class NameIndex;
friend class ValueIterator;
};
class SentinelError : public ErrorInfo<SentinelError> {
public:
static char ID;
void log(raw_ostream &OS) const override { OS << "Sentinel"; }
std::error_code convertToErrorCode() const override;
};
private:
struct AbbrevMapInfo {
static Abbrev getEmptyKey();
static Abbrev getTombstoneKey();
static unsigned getHashValue(uint32_t Code) {
return DenseMapInfo<uint32_t>::getHashValue(Code);
}
static unsigned getHashValue(const Abbrev &Abbr) {
return getHashValue(Abbr.Code);
}
static bool isEqual(uint32_t LHS, const Abbrev &RHS) {
return LHS == RHS.Code;
}
static bool isEqual(const Abbrev &LHS, const Abbrev &RHS) {
return LHS.Code == RHS.Code;
}
};
public:
class NameTableEntry {
DataExtractor StrData;
uint32_t Index;
uint64_t StringOffset;
uint64_t EntryOffset;
public:
NameTableEntry(const DataExtractor &StrData, uint32_t Index,
uint64_t StringOffset, uint64_t EntryOffset)
: StrData(StrData), Index(Index), StringOffset(StringOffset),
EntryOffset(EntryOffset) {}
uint32_t getIndex() const { return Index; }
uint64_t getStringOffset() const { return StringOffset; }
const char *getString() const {
uint64_t Off = StringOffset;
return StrData.getCStr(&Off);
}
uint64_t getEntryOffset() const { return EntryOffset; }
};
class NameIndex {
DenseSet<Abbrev, AbbrevMapInfo> Abbrevs;
struct Header Hdr;
const DWARFDebugNames &Section;
uint64_t Base;
uint64_t CUsBase;
uint64_t BucketsBase;
uint64_t HashesBase;
uint64_t StringOffsetsBase;
uint64_t EntryOffsetsBase;
uint64_t EntriesBase;
void dumpCUs(ScopedPrinter &W) const;
void dumpLocalTUs(ScopedPrinter &W) const;
void dumpForeignTUs(ScopedPrinter &W) const;
void dumpAbbreviations(ScopedPrinter &W) const;
bool dumpEntry(ScopedPrinter &W, uint64_t *Offset) const;
void dumpName(ScopedPrinter &W, const NameTableEntry &NTE,
Optional<uint32_t> Hash) const;
void dumpBucket(ScopedPrinter &W, uint32_t Bucket) const;
Expected<AttributeEncoding> extractAttributeEncoding(uint64_t *Offset);
Expected<std::vector<AttributeEncoding>>
extractAttributeEncodings(uint64_t *Offset);
Expected<Abbrev> extractAbbrev(uint64_t *Offset);
public:
NameIndex(const DWARFDebugNames &Section, uint64_t Base)
: Section(Section), Base(Base) {}
uint64_t getCUOffset(uint32_t CU) const;
uint32_t getCUCount() const { return Hdr.CompUnitCount; }
uint64_t getLocalTUOffset(uint32_t TU) const;
uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; }
uint64_t getForeignTUSignature(uint32_t TU) const;
uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; }
uint32_t getBucketArrayEntry(uint32_t Bucket) const;
uint32_t getBucketCount() const { return Hdr.BucketCount; }
uint32_t getHashArrayEntry(uint32_t Index) const;
NameTableEntry getNameTableEntry(uint32_t Index) const;
uint32_t getNameCount() const { return Hdr.NameCount; }
const DenseSet<Abbrev, AbbrevMapInfo> &getAbbrevs() const {
return Abbrevs;
}
Expected<Entry> getEntry(uint64_t *Offset) const;
iterator_range<ValueIterator> equal_range(StringRef Key) const;
NameIterator begin() const { return NameIterator(this, 1); }
NameIterator end() const { return NameIterator(this, getNameCount() + 1); }
Error extract();
uint64_t getUnitOffset() const { return Base; }
uint64_t getNextUnitOffset() const {
return Base + dwarf::getUnitLengthFieldByteSize(Hdr.Format) +
Hdr.UnitLength;
}
void dump(ScopedPrinter &W) const;
friend class DWARFDebugNames;
};
class ValueIterator {
public:
using iterator_category = std::input_iterator_tag;
using value_type = Entry;
using difference_type = std::ptrdiff_t;
using pointer = value_type *;
using reference = value_type &;
private:
const NameIndex *CurrentIndex = nullptr;
bool IsLocal;
Optional<Entry> CurrentEntry;
uint64_t DataOffset = 0; std::string Key; Optional<uint32_t> Hash;
bool getEntryAtCurrentOffset();
Optional<uint64_t> findEntryOffsetInCurrentIndex();
bool findInCurrentIndex();
void searchFromStartOfCurrentIndex();
void next();
void setEnd() { *this = ValueIterator(); }
public:
ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key);
ValueIterator(const NameIndex &NI, StringRef Key);
ValueIterator() = default;
const Entry &operator*() const { return *CurrentEntry; }
ValueIterator &operator++() {
next();
return *this;
}
ValueIterator operator++(int) {
ValueIterator I = *this;
next();
return I;
}
friend bool operator==(const ValueIterator &A, const ValueIterator &B) {
return A.CurrentIndex == B.CurrentIndex && A.DataOffset == B.DataOffset;
}
friend bool operator!=(const ValueIterator &A, const ValueIterator &B) {
return !(A == B);
}
};
class NameIterator {
const NameIndex *CurrentIndex;
uint32_t CurrentName;
void next() {
assert(CurrentName <= CurrentIndex->getNameCount());
++CurrentName;
}
public:
using iterator_category = std::input_iterator_tag;
using value_type = NameTableEntry;
using difference_type = uint32_t;
using pointer = NameTableEntry *;
using reference = NameTableEntry;
NameIterator(const NameIndex *CurrentIndex, uint32_t CurrentName)
: CurrentIndex(CurrentIndex), CurrentName(CurrentName) {}
NameTableEntry operator*() const {
return CurrentIndex->getNameTableEntry(CurrentName);
}
NameIterator &operator++() {
next();
return *this;
}
NameIterator operator++(int) {
NameIterator I = *this;
next();
return I;
}
friend bool operator==(const NameIterator &A, const NameIterator &B) {
return A.CurrentIndex == B.CurrentIndex && A.CurrentName == B.CurrentName;
}
friend bool operator!=(const NameIterator &A, const NameIterator &B) {
return !(A == B);
}
};
private:
SmallVector<NameIndex, 0> NameIndices;
DenseMap<uint64_t, const NameIndex *> CUToNameIndex;
public:
DWARFDebugNames(const DWARFDataExtractor &AccelSection,
DataExtractor StringSection)
: DWARFAcceleratorTable(AccelSection, StringSection) {}
Error extract() override;
void dump(raw_ostream &OS) const override;
iterator_range<ValueIterator> equal_range(StringRef Key) const;
using const_iterator = SmallVector<NameIndex, 0>::const_iterator;
const_iterator begin() const { return NameIndices.begin(); }
const_iterator end() const { return NameIndices.end(); }
const NameIndex *getCUNameIndex(uint64_t CUOffset);
};
}
#endif