mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
Implement equal_range for the DWARF v5 accelerator table
Summary: This patch implements the name lookup functionality of the .debug_names accelerator table and hooks it up to "llvm-dwarfdump -find". To make the interface of the two kinds of accelerator tables more consistent, I've created an abstract "DWARFAcceleratorTable::Entry" class, which provides a consistent interface to access the common functionality of the table entries (such as getting the die offset, die tag, etc.). I've also modified the apple table to vend entries conforming to this interface. Reviewers: JDevlieghere, aprantl, probinson, dblaikie Subscribers: vleschuk, clayborg, echristo, llvm-commits Differential Revision: https://reviews.llvm.org/D43067 llvm-svn: 326003
This commit is contained in:
parent
1ee0de3c35
commit
396e9fac82
@ -35,6 +35,43 @@ protected:
|
||||
DataExtractor StringSection;
|
||||
|
||||
public:
|
||||
/// An abstract class representing a single entry in the accelerator tables.
|
||||
class Entry {
|
||||
protected:
|
||||
SmallVector<DWARFFormValue, 3> Values;
|
||||
|
||||
Entry() = default;
|
||||
|
||||
// Make these protected so only (final) subclasses can be copied around.
|
||||
Entry(const Entry &) = default;
|
||||
Entry(Entry &&) = default;
|
||||
Entry &operator=(const Entry &) = default;
|
||||
Entry &operator=(Entry &&) = default;
|
||||
~Entry() = default;
|
||||
|
||||
|
||||
public:
|
||||
/// Returns the Offset of the Compilation Unit associated with this
|
||||
/// Accelerator Entry or None if the Compilation Unit offset is not recorded
|
||||
/// in this Accelerator Entry.
|
||||
virtual Optional<uint64_t> getCUOffset() const = 0;
|
||||
|
||||
/// Returns the Offset of the Debug Info Entry associated with this
|
||||
/// Accelerator Entry or None if the DIE offset is not recorded in this
|
||||
/// Accelerator Entry.
|
||||
virtual Optional<uint64_t> getDIEOffset() const = 0;
|
||||
|
||||
/// Returns the Tag of the Debug Info Entry associated with this
|
||||
/// Accelerator Entry or None if the Tag is not recorded in this
|
||||
/// Accelerator Entry.
|
||||
virtual Optional<dwarf::Tag> getTag() const = 0;
|
||||
|
||||
/// Returns the raw values of fields in the Accelerator Entry. In general,
|
||||
/// these can only be interpreted with the help of the metadata in the
|
||||
/// owning Accelerator Table.
|
||||
ArrayRef<DWARFFormValue> getValues() const { return Values; }
|
||||
};
|
||||
|
||||
DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection,
|
||||
DataExtractor StringSection)
|
||||
: AccelSection(AccelSection), StringSection(StringSection) {}
|
||||
@ -79,13 +116,32 @@ class AppleAcceleratorTable : public DWARFAcceleratorTable {
|
||||
uint32_t *DataOffset) const;
|
||||
|
||||
public:
|
||||
/// An iterator for the entries associated with one key. Each entry can have
|
||||
/// multiple DWARFFormValues.
|
||||
class ValueIterator : public std::iterator<std::input_iterator_tag,
|
||||
ArrayRef<DWARFFormValue>> {
|
||||
const AppleAcceleratorTable *AccelTable = nullptr;
|
||||
SmallVector<DWARFFormValue, 3> AtomForms; ///< The decoded data entry.
|
||||
/// Apple-specific implementation of an Accelerator Entry.
|
||||
class Entry final : public DWARFAcceleratorTable::Entry {
|
||||
const HeaderData *HdrData = nullptr;
|
||||
|
||||
Entry(const HeaderData &Data);
|
||||
Entry() = default;
|
||||
|
||||
void extract(const AppleAcceleratorTable &AccelTable, uint32_t *Offset);
|
||||
|
||||
public:
|
||||
Entry(const Entry &RHS) : HdrData(RHS.HdrData) { Values = RHS.Values; }
|
||||
Optional<uint64_t> getCUOffset() const override;
|
||||
Optional<uint64_t> getDIEOffset() const override;
|
||||
Optional<dwarf::Tag> getTag() const override;
|
||||
|
||||
/// Returns the value of the Atom in this Accelerator Entry, if the Entry
|
||||
/// contains such Atom.
|
||||
Optional<DWARFFormValue> lookup(HeaderData::AtomType Atom) const;
|
||||
|
||||
friend class AppleAcceleratorTable;
|
||||
friend class ValueIterator;
|
||||
};
|
||||
|
||||
class ValueIterator : public std::iterator<std::input_iterator_tag, Entry> {
|
||||
const AppleAcceleratorTable *AccelTable = nullptr;
|
||||
Entry Current; ///< The current entry.
|
||||
unsigned DataOffset = 0; ///< Offset into the section.
|
||||
unsigned Data = 0; ///< Current data entry.
|
||||
unsigned NumData = 0; ///< Number of data entries.
|
||||
@ -98,9 +154,7 @@ public:
|
||||
/// End marker.
|
||||
ValueIterator() = default;
|
||||
|
||||
const ArrayRef<DWARFFormValue> operator*() const {
|
||||
return AtomForms;
|
||||
}
|
||||
const Entry &operator*() const { return Current; }
|
||||
ValueIterator &operator++() { Next(); return *this; }
|
||||
ValueIterator operator++(int) {
|
||||
ValueIterator I = *this;
|
||||
@ -124,6 +178,9 @@ public:
|
||||
uint32_t getNumHashes();
|
||||
uint32_t getSizeHdr();
|
||||
uint32_t getHeaderDataLength();
|
||||
|
||||
/// Return the Atom description, which can be used to interpret the raw values
|
||||
/// of the Accelerator Entries in this table.
|
||||
ArrayRef<std::pair<HeaderData::AtomType, HeaderData::Form>> getAtomsDesc();
|
||||
bool validateForms();
|
||||
|
||||
@ -179,6 +236,9 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
|
||||
};
|
||||
|
||||
public:
|
||||
class NameIndex;
|
||||
class ValueIterator;
|
||||
|
||||
/// Dwarf 5 Name Index header.
|
||||
struct Header : public HeaderPOD {
|
||||
SmallString<8> AugmentationString;
|
||||
@ -214,16 +274,41 @@ public:
|
||||
void dump(ScopedPrinter &W) const;
|
||||
};
|
||||
|
||||
/// A single entry in the Name Index.
|
||||
struct Entry {
|
||||
const Abbrev &Abbr;
|
||||
/// DWARF v5-specific implementation of an Accelerator Entry.
|
||||
class Entry final : public DWARFAcceleratorTable::Entry {
|
||||
const NameIndex *NameIdx;
|
||||
const Abbrev *Abbr;
|
||||
|
||||
/// Values of the index attributes described by Abbr.
|
||||
std::vector<DWARFFormValue> Values;
|
||||
Entry(const NameIndex &NameIdx, const Abbrev &Abbr);
|
||||
|
||||
Entry(const Abbrev &Abbr);
|
||||
/// Returns the Index into the Compilation Unit list of the owning Name
|
||||
/// Index or None if this Accelerator Entry does not have an associated
|
||||
/// Compilation Unit. It is up to the user to verify that the returned Index
|
||||
/// is valid in the owning NameIndex (or use getCUOffset(), which will
|
||||
/// handle that check itself).
|
||||
Optional<uint64_t> getCUIndex() const;
|
||||
|
||||
public:
|
||||
Optional<uint64_t> getCUOffset() const override;
|
||||
Optional<uint64_t> getDIEOffset() const override;
|
||||
Optional<dwarf::Tag> getTag() const override { return tag(); }
|
||||
|
||||
/// .debug_names-specific getter, which always succeeds (DWARF v5 index
|
||||
/// entries always have a tag).
|
||||
dwarf::Tag tag() const { return Abbr->Tag; }
|
||||
|
||||
/// Return the Abbreviation that can be used to interpret the raw values of
|
||||
/// this Accelerator Entry.
|
||||
const Abbrev &getAbbrev() const { return *Abbr; }
|
||||
|
||||
/// Returns the value of the Index Attribute in this Accelerator Entry, if
|
||||
/// the Entry contains such Attribute.
|
||||
Optional<DWARFFormValue> lookup(dwarf::Index Index) const;
|
||||
|
||||
void dump(ScopedPrinter &W) const;
|
||||
|
||||
friend class NameIndex;
|
||||
friend class ValueIterator;
|
||||
};
|
||||
|
||||
private:
|
||||
@ -280,15 +365,6 @@ public:
|
||||
uint32_t EntryOffsetsBase;
|
||||
uint32_t EntriesBase;
|
||||
|
||||
/// Reads offset of compilation unit CU. CU is 0-based.
|
||||
uint32_t getCUOffset(uint32_t CU) const;
|
||||
|
||||
/// Reads offset of local type unit TU, TU is 0-based.
|
||||
uint32_t getLocalTUOffset(uint32_t TU) const;
|
||||
|
||||
/// Reads signature of foreign type unit TU. TU is 0-based.
|
||||
uint64_t getForeignTUOffset(uint32_t TU) const;
|
||||
|
||||
/// Reads an entry in the Bucket Array for the given Bucket. The returned
|
||||
/// value is a (1-based) index into the Names, StringOffsets and
|
||||
/// EntryOffsets arrays. The input Bucket index is 0-based.
|
||||
@ -326,13 +402,76 @@ public:
|
||||
NameIndex(const DWARFDebugNames &Section, uint32_t Base)
|
||||
: Section(Section), Base(Base) {}
|
||||
|
||||
/// Reads offset of compilation unit CU. CU is 0-based.
|
||||
uint32_t getCUOffset(uint32_t CU) const;
|
||||
uint32_t getCUCount() const { return Hdr.CompUnitCount; }
|
||||
|
||||
/// Reads offset of local type unit TU, TU is 0-based.
|
||||
uint32_t getLocalTUOffset(uint32_t TU) const;
|
||||
uint32_t getLocalTUCount() const { return Hdr.LocalTypeUnitCount; }
|
||||
|
||||
/// Reads signature of foreign type unit TU. TU is 0-based.
|
||||
uint64_t getForeignTUSignature(uint32_t TU) const;
|
||||
uint32_t getForeignTUCount() const { return Hdr.ForeignTypeUnitCount; }
|
||||
|
||||
llvm::Error extract();
|
||||
uint32_t getNextUnitOffset() const { return Base + 4 + Hdr.UnitLength; }
|
||||
void dump(ScopedPrinter &W) const;
|
||||
|
||||
friend class DWARFDebugNames;
|
||||
};
|
||||
|
||||
class ValueIterator : public std::iterator<std::input_iterator_tag, Entry> {
|
||||
|
||||
/// The Name Index we are currently iterating through. The implementation
|
||||
/// relies on the fact that this can also be used as an iterator into the
|
||||
/// "NameIndices" vector in the Accelerator section.
|
||||
const NameIndex *CurrentIndex = nullptr;
|
||||
|
||||
Optional<Entry> CurrentEntry;
|
||||
unsigned DataOffset = 0; ///< Offset into the section.
|
||||
std::string Key; ///< The Key we are searching for.
|
||||
Optional<uint32_t> Hash; ///< Hash of Key, if it has been computed.
|
||||
|
||||
bool getEntryAtCurrentOffset();
|
||||
Optional<uint32_t> findEntryOffsetInCurrentIndex();
|
||||
bool findInCurrentIndex();
|
||||
void searchFromStartOfCurrentIndex();
|
||||
void next();
|
||||
|
||||
/// Set the iterator to the "end" state.
|
||||
void setEnd() { *this = ValueIterator(); }
|
||||
|
||||
public:
|
||||
/// Create a "begin" iterator for looping over all entries in the
|
||||
/// accelerator table matching Key. The iterator will run through all Name
|
||||
/// Indexes in the section in sequence.
|
||||
ValueIterator(const DWARFDebugNames &AccelTable, StringRef Key);
|
||||
|
||||
/// End marker.
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
std::vector<NameIndex> NameIndices;
|
||||
llvm::SmallVector<NameIndex, 0> NameIndices;
|
||||
|
||||
public:
|
||||
DWARFDebugNames(const DWARFDataExtractor &AccelSection,
|
||||
@ -341,6 +480,9 @@ public:
|
||||
|
||||
llvm::Error extract() override;
|
||||
void dump(raw_ostream &OS) const override;
|
||||
|
||||
/// Look up all entries in the accelerator table matching \c Key.
|
||||
iterator_range<ValueIterator> equal_range(StringRef Key) const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -248,15 +248,61 @@ LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const {
|
||||
}
|
||||
}
|
||||
|
||||
AppleAcceleratorTable::Entry::Entry(
|
||||
const AppleAcceleratorTable::HeaderData &HdrData)
|
||||
: HdrData(&HdrData) {
|
||||
Values.reserve(HdrData.Atoms.size());
|
||||
for (const auto &Atom : HdrData.Atoms)
|
||||
Values.push_back(DWARFFormValue(Atom.second));
|
||||
}
|
||||
|
||||
void AppleAcceleratorTable::Entry::extract(
|
||||
const AppleAcceleratorTable &AccelTable, uint32_t *Offset) {
|
||||
|
||||
DWARFFormParams FormParams = {AccelTable.Hdr.Version, 0,
|
||||
dwarf::DwarfFormat::DWARF32};
|
||||
for (auto &Atom : Values)
|
||||
Atom.extractValue(AccelTable.AccelSection, Offset, FormParams);
|
||||
}
|
||||
|
||||
Optional<DWARFFormValue>
|
||||
AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType Atom) const {
|
||||
assert(HdrData && "Dereferencing end iterator?");
|
||||
assert(HdrData->Atoms.size() == Values.size());
|
||||
for (const auto &Tuple : zip_first(HdrData->Atoms, Values)) {
|
||||
if (std::get<0>(Tuple).first == Atom)
|
||||
return std::get<1>(Tuple);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
Optional<uint64_t> AppleAcceleratorTable::Entry::getDIEOffset() const {
|
||||
if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_ATOM_die_offset))
|
||||
return Off->getAsSectionOffset();
|
||||
return None;
|
||||
}
|
||||
|
||||
Optional<uint64_t> AppleAcceleratorTable::Entry::getCUOffset() const {
|
||||
if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_ATOM_cu_offset))
|
||||
return Off->getAsSectionOffset();
|
||||
return None;
|
||||
}
|
||||
|
||||
Optional<dwarf::Tag> AppleAcceleratorTable::Entry::getTag() const {
|
||||
Optional<DWARFFormValue> Tag = lookup(dwarf::DW_ATOM_die_tag);
|
||||
if (!Tag)
|
||||
return None;
|
||||
if (Optional<uint64_t> Value = Tag->getAsUnsignedConstant())
|
||||
return dwarf::Tag(*Value);
|
||||
return None;
|
||||
}
|
||||
|
||||
AppleAcceleratorTable::ValueIterator::ValueIterator(
|
||||
const AppleAcceleratorTable &AccelTable, unsigned Offset)
|
||||
: AccelTable(&AccelTable), DataOffset(Offset) {
|
||||
: AccelTable(&AccelTable), Current(AccelTable.HdrData), DataOffset(Offset) {
|
||||
if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4))
|
||||
return;
|
||||
|
||||
for (const auto &Atom : AccelTable.HdrData.Atoms)
|
||||
AtomForms.push_back(DWARFFormValue(Atom.second));
|
||||
|
||||
// Read the first entry.
|
||||
NumData = AccelTable.AccelSection.getU32(&DataOffset);
|
||||
Next();
|
||||
@ -270,10 +316,7 @@ void AppleAcceleratorTable::ValueIterator::Next() {
|
||||
NumData = 0;
|
||||
return;
|
||||
}
|
||||
DWARFFormParams FormParams = {AccelTable->Hdr.Version, 0,
|
||||
dwarf::DwarfFormat::DWARF32};
|
||||
for (auto &Atom : AtomForms)
|
||||
Atom.extractValue(AccelSection, &DataOffset, FormParams);
|
||||
Current.extract(*AccelTable, &DataOffset);
|
||||
++Data;
|
||||
}
|
||||
|
||||
@ -475,8 +518,8 @@ Error DWARFDebugNames::NameIndex::extract() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DWARFDebugNames::Entry::Entry(const Abbrev &Abbr) : Abbr(Abbr) {
|
||||
DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr)
|
||||
: NameIdx(&NameIdx), Abbr(&Abbr) {
|
||||
// This merely creates form values. It is up to the caller
|
||||
// (NameIndex::getEntry) to populate them.
|
||||
Values.reserve(Abbr.Attributes.size());
|
||||
@ -484,14 +527,43 @@ DWARFDebugNames::Entry::Entry(const Abbrev &Abbr) : Abbr(Abbr) {
|
||||
Values.emplace_back(Attr.Form);
|
||||
}
|
||||
|
||||
void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
|
||||
W.printHex("Abbrev", Abbr.Code);
|
||||
W.startLine() << "Tag: " << formatTag(Abbr.Tag) << "\n";
|
||||
Optional<DWARFFormValue>
|
||||
DWARFDebugNames::Entry::lookup(dwarf::Index Index) const {
|
||||
assert(Abbr->Attributes.size() == Values.size());
|
||||
for (const auto &Tuple : zip_first(Abbr->Attributes, Values)) {
|
||||
if (std::get<0>(Tuple).Index == Index)
|
||||
return std::get<1>(Tuple);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
assert(Abbr.Attributes.size() == Values.size());
|
||||
for (uint32_t I = 0, E = Values.size(); I < E; ++I) {
|
||||
W.startLine() << formatIndex(Abbr.Attributes[I].Index) << ": ";
|
||||
Values[I].dump(W.getOStream());
|
||||
Optional<uint64_t> DWARFDebugNames::Entry::getDIEOffset() const {
|
||||
if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset))
|
||||
return Off->getAsSectionOffset();
|
||||
return None;
|
||||
}
|
||||
|
||||
Optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const {
|
||||
if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit))
|
||||
return Off->getAsUnsignedConstant();
|
||||
return None;
|
||||
}
|
||||
|
||||
Optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const {
|
||||
Optional<uint64_t> Index = getCUIndex();
|
||||
if (!Index || *Index >= NameIdx->getCUCount())
|
||||
return None;
|
||||
return NameIdx->getCUOffset(*Index);
|
||||
}
|
||||
|
||||
void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
|
||||
W.printHex("Abbrev", Abbr->Code);
|
||||
W.startLine() << "Tag: " << formatTag(Abbr->Tag) << "\n";
|
||||
|
||||
assert(Abbr->Attributes.size() == Values.size());
|
||||
for (const auto &Tuple : zip_first(Abbr->Attributes, Values)) {
|
||||
W.startLine() << formatIndex(std::get<0>(Tuple).Index) << ": ";
|
||||
std::get<1>(Tuple).dump(W.getOStream());
|
||||
W.getOStream() << '\n';
|
||||
}
|
||||
}
|
||||
@ -513,7 +585,7 @@ uint32_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const {
|
||||
return Section.AccelSection.getRelocatedValue(4, &Offset);
|
||||
}
|
||||
|
||||
uint64_t DWARFDebugNames::NameIndex::getForeignTUOffset(uint32_t TU) const {
|
||||
uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU) const {
|
||||
assert(TU < Hdr.ForeignTypeUnitCount);
|
||||
uint32_t Offset = CUsBase + (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) * 4;
|
||||
return Section.AccelSection.getU64(&Offset);
|
||||
@ -535,7 +607,7 @@ DWARFDebugNames::NameIndex::getEntry(uint32_t *Offset) const {
|
||||
return make_error<StringError>("Invalid abbreviation",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
Entry E(*AbbrevIt);
|
||||
Entry E(*this, *AbbrevIt);
|
||||
|
||||
DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
|
||||
for (auto &Value : E.Values) {
|
||||
@ -629,7 +701,7 @@ void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const {
|
||||
ListScope TUScope(W, "Foreign Type Unit signatures");
|
||||
for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) {
|
||||
W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU,
|
||||
getForeignTUOffset(TU));
|
||||
getForeignTUSignature(TU));
|
||||
}
|
||||
}
|
||||
|
||||
@ -697,3 +769,89 @@ LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const {
|
||||
for (const NameIndex &NI : NameIndices)
|
||||
NI.dump(W);
|
||||
}
|
||||
|
||||
Optional<uint32_t>
|
||||
DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() {
|
||||
const Header &Hdr = CurrentIndex->Hdr;
|
||||
if (Hdr.BucketCount == 0) {
|
||||
// No Hash Table, We need to search through all names in the Name Index.
|
||||
for (uint32_t Index = 1; Index <= Hdr.NameCount; ++Index) {
|
||||
NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index);
|
||||
if (CurrentIndex->Section.StringSection.getCStr(&NTE.StringOffset) == Key)
|
||||
return NTE.EntryOffset;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
// The Name Index has a Hash Table, so use that to speed up the search.
|
||||
// Compute the Key Hash, if it has not been done already.
|
||||
if (!Hash)
|
||||
Hash = caseFoldingDjbHash(Key);
|
||||
uint32_t Bucket = *Hash % Hdr.BucketCount;
|
||||
uint32_t Index = CurrentIndex->getBucketArrayEntry(Bucket);
|
||||
if (Index == 0)
|
||||
return None; // Empty bucket
|
||||
|
||||
for (; Index <= Hdr.NameCount; ++Index) {
|
||||
uint32_t Hash = CurrentIndex->getHashArrayEntry(Index);
|
||||
if (Hash % Hdr.BucketCount != Bucket)
|
||||
return None; // End of bucket
|
||||
|
||||
NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index);
|
||||
if (CurrentIndex->Section.StringSection.getCStr(&NTE.StringOffset) == Key)
|
||||
return NTE.EntryOffset;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
bool DWARFDebugNames::ValueIterator::getEntryAtCurrentOffset() {
|
||||
auto EntryOr = CurrentIndex->getEntry(&DataOffset);
|
||||
if (!EntryOr) {
|
||||
consumeError(EntryOr.takeError());
|
||||
return false;
|
||||
}
|
||||
CurrentEntry = std::move(*EntryOr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DWARFDebugNames::ValueIterator::findInCurrentIndex() {
|
||||
Optional<uint32_t> Offset = findEntryOffsetInCurrentIndex();
|
||||
if (!Offset)
|
||||
return false;
|
||||
DataOffset = *Offset;
|
||||
return getEntryAtCurrentOffset();
|
||||
}
|
||||
|
||||
void DWARFDebugNames::ValueIterator::searchFromStartOfCurrentIndex() {
|
||||
for (const NameIndex *End = CurrentIndex->Section.NameIndices.end();
|
||||
CurrentIndex != End; ++CurrentIndex) {
|
||||
if (findInCurrentIndex())
|
||||
return;
|
||||
}
|
||||
setEnd();
|
||||
}
|
||||
|
||||
void DWARFDebugNames::ValueIterator::next() {
|
||||
assert(CurrentIndex && "Incrementing an end() iterator?");
|
||||
|
||||
// First try the next entry in the current Index.
|
||||
if (getEntryAtCurrentOffset())
|
||||
return;
|
||||
|
||||
// Try the next Name Index.
|
||||
++CurrentIndex;
|
||||
searchFromStartOfCurrentIndex();
|
||||
}
|
||||
|
||||
DWARFDebugNames::ValueIterator::ValueIterator(const DWARFDebugNames &AccelTable,
|
||||
StringRef Key)
|
||||
: CurrentIndex(AccelTable.NameIndices.begin()), Key(Key) {
|
||||
searchFromStartOfCurrentIndex();
|
||||
}
|
||||
|
||||
iterator_range<DWARFDebugNames::ValueIterator>
|
||||
DWARFDebugNames::equal_range(StringRef Key) const {
|
||||
if (NameIndices.empty())
|
||||
return make_range(ValueIterator(), ValueIterator());
|
||||
return make_range(ValueIterator(*this, Key), ValueIterator());
|
||||
}
|
||||
|
182
test/tools/llvm-dwarfdump/X86/debug-names-find.s
Normal file
182
test/tools/llvm-dwarfdump/X86/debug-names-find.s
Normal file
@ -0,0 +1,182 @@
|
||||
# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj -o %t
|
||||
# RUN: llvm-dwarfdump -find=foo %t | FileCheck --check-prefix=FOO %s
|
||||
# RUN: llvm-dwarfdump -find=baz %t | FileCheck --check-prefix=BAZ %s
|
||||
# RUN: llvm-dwarfdump -find=missing %t | FileCheck --check-prefix=MISSING %s
|
||||
|
||||
# FOO: DW_TAG_subprogram
|
||||
# FOO-NEXT: DW_AT_name ("foo")
|
||||
# FOO-NEXT: DW_AT_external
|
||||
|
||||
# BAZ: DW_TAG_subprogram
|
||||
# BAZ-NEXT: DW_AT_name ("baz")
|
||||
# BAZ-NEXT: DW_AT_external
|
||||
|
||||
# MISSING-NOT: foo
|
||||
# MISSING-NOT: bar
|
||||
# MISSING-NOT: baz
|
||||
# MISSING-NOT: bazz
|
||||
|
||||
.section .debug_str,"MS",@progbits,1
|
||||
.Lstring_foo:
|
||||
.asciz "foo"
|
||||
.Lstring_foo_mangled:
|
||||
.asciz "_Z3foov"
|
||||
.Lstring_bar:
|
||||
.asciz "bar"
|
||||
.Lstring_baz:
|
||||
.asciz "baz"
|
||||
.Lstring_bazz:
|
||||
.asciz "bazz"
|
||||
.Lstring_producer:
|
||||
.asciz "Hand-written dwarf"
|
||||
|
||||
.section .debug_abbrev,"",@progbits
|
||||
.Lsection_abbrev:
|
||||
.byte 1 # Abbreviation Code
|
||||
.byte 17 # DW_TAG_compile_unit
|
||||
.byte 1 # DW_CHILDREN_yes
|
||||
.byte 37 # DW_AT_producer
|
||||
.byte 14 # DW_FORM_strp
|
||||
.byte 19 # DW_AT_language
|
||||
.byte 5 # DW_FORM_data2
|
||||
.byte 0 # EOM(1)
|
||||
.byte 0 # EOM(2)
|
||||
.byte 2 # Abbreviation Code
|
||||
.byte 46 # DW_TAG_subprogram
|
||||
.byte 0 # DW_CHILDREN_no
|
||||
.byte 3 # DW_AT_name
|
||||
.byte 14 # DW_FORM_strp
|
||||
.byte 63 # DW_AT_external
|
||||
.byte 25 # DW_FORM_flag_present
|
||||
.byte 0 # EOM(1)
|
||||
.byte 0 # EOM(2)
|
||||
.byte 0 # EOM(3)
|
||||
|
||||
.section .debug_info,"",@progbits
|
||||
.Lcu_begin0:
|
||||
.long .Lcu_end0-.Lcu_start0 # Length of Unit
|
||||
.Lcu_start0:
|
||||
.short 4 # DWARF version number
|
||||
.long .Lsection_abbrev # Offset Into Abbrev. Section
|
||||
.byte 8 # Address Size (in bytes)
|
||||
.byte 1 # Abbrev [1] DW_TAG_compile_unit
|
||||
.long .Lstring_producer # DW_AT_producer
|
||||
.short 12 # DW_AT_language
|
||||
.Ldie_foo:
|
||||
.byte 2 # Abbrev [2] DW_TAG_subprogram
|
||||
.long .Lstring_foo # DW_AT_name
|
||||
# DW_AT_external
|
||||
.Ldie_bar:
|
||||
.byte 2 # Abbrev [2] DW_TAG_subprogram
|
||||
.long .Lstring_bar # DW_AT_name
|
||||
# DW_AT_external
|
||||
.byte 0 # End Of Children Mark
|
||||
.Lcu_end0:
|
||||
|
||||
.Lcu_begin1:
|
||||
.long .Lcu_end1-.Lcu_start1 # Length of Unit
|
||||
.Lcu_start1:
|
||||
.short 4 # DWARF version number
|
||||
.long .Lsection_abbrev # Offset Into Abbrev. Section
|
||||
.byte 8 # Address Size (in bytes)
|
||||
.byte 1 # Abbrev [1] DW_TAG_compile_unit
|
||||
.long .Lstring_producer # DW_AT_producer
|
||||
.short 12 # DW_AT_language
|
||||
.Ldie_baz:
|
||||
.byte 2 # Abbrev [2] DW_TAG_subprogram
|
||||
.long .Lstring_baz # DW_AT_name
|
||||
# DW_AT_external
|
||||
.Ldie_bazz:
|
||||
.byte 2 # Abbrev [2] DW_TAG_subprogram
|
||||
.long .Lstring_bazz # DW_AT_name
|
||||
# DW_AT_external
|
||||
.byte 0 # End Of Children Mark
|
||||
.Lcu_end1:
|
||||
|
||||
.section .debug_names,"",@progbits
|
||||
.long .Lnames_end0-.Lnames_start0 # Header: contribution length
|
||||
.Lnames_start0:
|
||||
.short 5 # Header: version
|
||||
.short 0 # Header: padding
|
||||
.long 1 # Header: compilation unit count
|
||||
.long 0 # Header: local type unit count
|
||||
.long 0 # Header: foreign type unit count
|
||||
.long 2 # Header: bucket count
|
||||
.long 3 # Header: name count
|
||||
.long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
|
||||
.long 0 # Header: augmentation length
|
||||
.long .Lcu_begin0 # Compilation unit 0
|
||||
.long 1 # Bucket 0
|
||||
.long 2 # Bucket 1
|
||||
.long 193487034 # Hash in Bucket 0
|
||||
.long 193491849 # Hash in Bucket 1
|
||||
.long -1257882357 # Hash in Bucket 1
|
||||
.long .Lstring_bar # String in Bucket 1: bar
|
||||
.long .Lstring_foo # String in Bucket 1: foo
|
||||
.long .Lstring_foo_mangled # String in Bucket 1: _Z3foov
|
||||
.long .Lnames0-.Lnames_entries0 # Offset in Bucket 1
|
||||
.long .Lnames1-.Lnames_entries0 # Offset in Bucket 1
|
||||
.long .Lnames2-.Lnames_entries0 # Offset in Bucket 1
|
||||
.Lnames_abbrev_start0:
|
||||
.byte 46 # Abbrev code
|
||||
.byte 46 # DW_TAG_subprogram
|
||||
.byte 3 # DW_IDX_die_offset
|
||||
.byte 6 # DW_FORM_data4
|
||||
.byte 0 # End of abbrev
|
||||
.byte 0 # End of abbrev
|
||||
.byte 0 # End of abbrev list
|
||||
.Lnames_abbrev_end0:
|
||||
.Lnames_entries0:
|
||||
.Lnames0:
|
||||
.byte 46 # Abbrev code
|
||||
.long .Ldie_bar # DW_IDX_die_offset
|
||||
.long 0 # End of list: bar
|
||||
.Lnames1:
|
||||
.byte 46 # Abbrev code
|
||||
.long .Ldie_foo # DW_IDX_die_offset
|
||||
.long 0 # End of list: foo
|
||||
.Lnames2:
|
||||
.byte 46 # Abbrev code
|
||||
.long .Ldie_foo # DW_IDX_die_offset
|
||||
.long 0 # End of list: _Z3foov
|
||||
.p2align 2
|
||||
.Lnames_end0:
|
||||
|
||||
# Index of compilation unit 1. This one has no hash table.
|
||||
.long .Lnames_end1-.Lnames_start1 # Header: contribution length
|
||||
.Lnames_start1:
|
||||
.short 5 # Header: version
|
||||
.short 0 # Header: padding
|
||||
.long 1 # Header: compilation unit count
|
||||
.long 0 # Header: local type unit count
|
||||
.long 0 # Header: foreign type unit count
|
||||
.long 0 # Header: bucket count
|
||||
.long 2 # Header: name count
|
||||
.long .Lnames_abbrev_end1-.Lnames_abbrev_start1 # Header: abbreviation table size
|
||||
.long 0 # Header: augmentation length
|
||||
.long .Lcu_begin1 # Compilation unit 0
|
||||
.long .Lstring_baz # String in Bucket 1: baz
|
||||
.long .Lstring_bazz # String in Bucket 1: bazz
|
||||
.long .Lnames3-.Lnames_entries1 # Offset in Bucket 1
|
||||
.long .Lnames4-.Lnames_entries1 # Offset in Bucket 1
|
||||
.Lnames_abbrev_start1:
|
||||
.byte 46 # Abbrev code
|
||||
.byte 46 # DW_TAG_subprogram
|
||||
.byte 3 # DW_IDX_die_offset
|
||||
.byte 6 # DW_FORM_data4
|
||||
.byte 0 # End of abbrev
|
||||
.byte 0 # End of abbrev
|
||||
.byte 0 # End of abbrev list
|
||||
.Lnames_abbrev_end1:
|
||||
.Lnames_entries1:
|
||||
.Lnames3:
|
||||
.byte 46 # Abbrev code
|
||||
.long .Ldie_baz # DW_IDX_die_offset
|
||||
.long 0 # End of list: baz
|
||||
.p2align 2
|
||||
.Lnames4:
|
||||
.byte 46 # Abbrev code
|
||||
.long .Ldie_bazz # DW_IDX_die_offset
|
||||
.long 0 # End of list: baz
|
||||
.p2align 2
|
||||
.Lnames_end1:
|
@ -336,6 +336,15 @@ static bool lookup(DWARFContext &DICtx, uint64_t Address, raw_ostream &OS) {
|
||||
bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
|
||||
Twine Filename, raw_ostream &OS);
|
||||
|
||||
template <typename AccelTable>
|
||||
static Optional<uint64_t> getDIEOffset(const AccelTable &Accel,
|
||||
StringRef Name) {
|
||||
for (const auto &Entry : Accel.equal_range(Name))
|
||||
if (Optional<uint64_t> Off = Entry.getDIEOffset())
|
||||
return *Off;
|
||||
return None;
|
||||
}
|
||||
|
||||
static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename,
|
||||
raw_ostream &OS) {
|
||||
logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(),
|
||||
@ -363,21 +372,14 @@ static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename,
|
||||
if (!Find.empty()) {
|
||||
DumpOffsets[DIDT_ID_DebugInfo] = [&]() -> llvm::Optional<uint64_t> {
|
||||
for (auto Name : Find) {
|
||||
auto find = [&](const AppleAcceleratorTable &Accel)
|
||||
-> llvm::Optional<uint64_t> {
|
||||
for (auto Entry : Accel.equal_range(Name))
|
||||
for (auto Atom : Entry)
|
||||
if (auto Offset = Atom.getAsSectionOffset())
|
||||
return Offset;
|
||||
return None;
|
||||
};
|
||||
if (auto Offset = find(DICtx.getAppleNames()))
|
||||
if (auto Offset = getDIEOffset(DICtx.getAppleNames(), Name))
|
||||
return DumpOffsets[DIDT_ID_DebugInfo] = *Offset;
|
||||
if (auto Offset = find(DICtx.getAppleTypes()))
|
||||
if (auto Offset = getDIEOffset(DICtx.getAppleTypes(), Name))
|
||||
return DumpOffsets[DIDT_ID_DebugInfo] = *Offset;
|
||||
if (auto Offset = find(DICtx.getAppleNamespaces()))
|
||||
if (auto Offset = getDIEOffset(DICtx.getAppleNamespaces(), Name))
|
||||
return DumpOffsets[DIDT_ID_DebugInfo] = *Offset;
|
||||
if (auto Offset = getDIEOffset(DICtx.getDebugNames(), Name))
|
||||
return DumpOffsets[DIDT_ID_DebugInfo] = *Offset;
|
||||
// TODO: Add .debug_names support
|
||||
}
|
||||
return None;
|
||||
}();
|
||||
|
Loading…
Reference in New Issue
Block a user