#ifndef LLVM_DEBUGINFO_DWARF_DWARFLISTTABLE_H
#define LLVM_DEBUGINFO_DWARF_DWARFLISTTABLE_H
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdint>
#include <map>
#include <vector>
namespace llvm {
struct DWARFListEntryBase {
uint64_t Offset;
uint8_t EntryKind;
uint64_t SectionIndex;
};
template <typename ListEntryType> class DWARFListType {
using EntryType = ListEntryType;
using ListEntries = std::vector<EntryType>;
protected:
ListEntries Entries;
public:
const ListEntries &getEntries() const { return Entries; }
bool empty() const { return Entries.empty(); }
void clear() { Entries.clear(); }
Error extract(DWARFDataExtractor Data, uint64_t HeaderOffset,
uint64_t *OffsetPtr, StringRef SectionName,
StringRef ListStringName);
};
class DWARFListTableHeader {
struct Header {
uint64_t Length = 0;
uint16_t Version;
uint8_t AddrSize;
uint8_t SegSize;
uint32_t OffsetEntryCount;
};
Header HeaderData;
dwarf::DwarfFormat Format;
uint64_t HeaderOffset;
StringRef SectionName;
StringRef ListTypeString;
public:
DWARFListTableHeader(StringRef SectionName, StringRef ListTypeString)
: SectionName(SectionName), ListTypeString(ListTypeString) {}
void clear() {
HeaderData = {};
}
uint64_t getHeaderOffset() const { return HeaderOffset; }
uint8_t getAddrSize() const { return HeaderData.AddrSize; }
uint64_t getLength() const { return HeaderData.Length; }
uint16_t getVersion() const { return HeaderData.Version; }
uint32_t getOffsetEntryCount() const { return HeaderData.OffsetEntryCount; }
StringRef getSectionName() const { return SectionName; }
StringRef getListTypeString() const { return ListTypeString; }
dwarf::DwarfFormat getFormat() const { return Format; }
static uint8_t getHeaderSize(dwarf::DwarfFormat Format) {
switch (Format) {
case dwarf::DwarfFormat::DWARF32:
return 12;
case dwarf::DwarfFormat::DWARF64:
return 20;
}
llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64");
}
void dump(DataExtractor Data, raw_ostream &OS,
DIDumpOptions DumpOpts = {}) const;
Optional<uint64_t> getOffsetEntry(DataExtractor Data, uint32_t Index) const {
if (Index >= HeaderData.OffsetEntryCount)
return None;
return getOffsetEntry(Data, getHeaderOffset() + getHeaderSize(Format), Format, Index);
}
static Optional<uint64_t> getOffsetEntry(DataExtractor Data,
uint64_t OffsetTableOffset,
dwarf::DwarfFormat Format,
uint32_t Index) {
uint8_t OffsetByteSize = Format == dwarf::DWARF64 ? 8 : 4;
uint64_t Offset = OffsetTableOffset + OffsetByteSize * Index;
auto R = Data.getUnsigned(&Offset, OffsetByteSize);
return R;
}
Error extract(DWARFDataExtractor Data, uint64_t *OffsetPtr);
uint64_t length() const;
};
template <typename DWARFListType> class DWARFListTableBase {
DWARFListTableHeader Header;
std::map<uint64_t, DWARFListType> ListMap;
StringRef HeaderString;
protected:
DWARFListTableBase(StringRef SectionName, StringRef HeaderString,
StringRef ListTypeString)
: Header(SectionName, ListTypeString), HeaderString(HeaderString) {}
public:
void clear() {
Header.clear();
ListMap.clear();
}
Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint64_t *OffsetPtr) {
return Header.extract(Data, OffsetPtr);
}
Error extract(DWARFDataExtractor Data, uint64_t *OffsetPtr);
Expected<DWARFListType> findList(DWARFDataExtractor Data,
uint64_t Offset) const;
uint64_t getHeaderOffset() const { return Header.getHeaderOffset(); }
uint8_t getAddrSize() const { return Header.getAddrSize(); }
uint32_t getOffsetEntryCount() const { return Header.getOffsetEntryCount(); }
dwarf::DwarfFormat getFormat() const { return Header.getFormat(); }
void dump(DWARFDataExtractor Data, raw_ostream &OS,
llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
LookupPooledAddress,
DIDumpOptions DumpOpts = {}) const;
Optional<uint64_t> getOffsetEntry(DataExtractor Data, uint32_t Index) const {
return Header.getOffsetEntry(Data, Index);
}
uint8_t getHeaderSize() const {
return DWARFListTableHeader::getHeaderSize(getFormat());
}
uint64_t length() { return Header.length(); }
};
template <typename DWARFListType>
Error DWARFListTableBase<DWARFListType>::extract(DWARFDataExtractor Data,
uint64_t *OffsetPtr) {
clear();
if (Error E = extractHeaderAndOffsets(Data, OffsetPtr))
return E;
Data.setAddressSize(Header.getAddrSize());
Data = DWARFDataExtractor(Data, getHeaderOffset() + Header.length());
while (Data.isValidOffset(*OffsetPtr)) {
DWARFListType CurrentList;
uint64_t Off = *OffsetPtr;
if (Error E = CurrentList.extract(Data, getHeaderOffset(), OffsetPtr,
Header.getSectionName(),
Header.getListTypeString()))
return E;
ListMap[Off] = CurrentList;
}
assert(*OffsetPtr == Data.size() &&
"mismatch between expected length of table and length "
"of extracted data");
return Error::success();
}
template <typename ListEntryType>
Error DWARFListType<ListEntryType>::extract(DWARFDataExtractor Data,
uint64_t HeaderOffset,
uint64_t *OffsetPtr,
StringRef SectionName,
StringRef ListTypeString) {
if (*OffsetPtr < HeaderOffset || *OffsetPtr >= Data.size())
return createStringError(errc::invalid_argument,
"invalid %s list offset 0x%" PRIx64,
ListTypeString.data(), *OffsetPtr);
Entries.clear();
while (Data.isValidOffset(*OffsetPtr)) {
ListEntryType Entry;
if (Error E = Entry.extract(Data, OffsetPtr))
return E;
Entries.push_back(Entry);
if (Entry.isSentinel())
return Error::success();
}
return createStringError(errc::illegal_byte_sequence,
"no end of list marker detected at end of %s table "
"starting at offset 0x%" PRIx64,
SectionName.data(), HeaderOffset);
}
template <typename DWARFListType>
void DWARFListTableBase<DWARFListType>::dump(
DWARFDataExtractor Data, raw_ostream &OS,
llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
LookupPooledAddress,
DIDumpOptions DumpOpts) const {
Header.dump(Data, OS, DumpOpts);
OS << HeaderString << "\n";
size_t MaxEncodingStringLength = 0;
if (DumpOpts.Verbose) {
for (const auto &List : ListMap)
for (const auto &Entry : List.second.getEntries())
MaxEncodingStringLength =
std::max(MaxEncodingStringLength,
dwarf::RangeListEncodingString(Entry.EntryKind).size());
}
uint64_t CurrentBase = 0;
for (const auto &List : ListMap)
for (const auto &Entry : List.second.getEntries())
Entry.dump(OS, getAddrSize(), MaxEncodingStringLength, CurrentBase,
DumpOpts, LookupPooledAddress);
}
template <typename DWARFListType>
Expected<DWARFListType>
DWARFListTableBase<DWARFListType>::findList(DWARFDataExtractor Data,
uint64_t Offset) const {
DWARFListType List;
if (Header.length())
Data = DWARFDataExtractor(Data, getHeaderOffset() + Header.length());
if (Error E =
List.extract(Data, Header.length() ? getHeaderOffset() : 0, &Offset,
Header.getSectionName(), Header.getListTypeString()))
return std::move(E);
return List;
}
}
#endif