1e94042caSEugene Zelenko //===- DWARFAcceleratorTable.cpp ------------------------------------------===// 282af9438SZachary Turner // 382af9438SZachary Turner // The LLVM Compiler Infrastructure 482af9438SZachary Turner // 582af9438SZachary Turner // This file is distributed under the University of Illinois Open Source 682af9438SZachary Turner // License. See LICENSE.TXT for details. 782af9438SZachary Turner // 882af9438SZachary Turner //===----------------------------------------------------------------------===// 982af9438SZachary Turner 1082af9438SZachary Turner #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" 11264b5d9eSZachary Turner 126bda14b3SChandler Carruth #include "llvm/ADT/SmallVector.h" 13264b5d9eSZachary Turner #include "llvm/BinaryFormat/Dwarf.h" 14e94042caSEugene Zelenko #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" 15e94042caSEugene Zelenko #include "llvm/Support/Compiler.h" 1682af9438SZachary Turner #include "llvm/Support/Format.h" 1782af9438SZachary Turner #include "llvm/Support/raw_ostream.h" 18e94042caSEugene Zelenko #include <cstddef> 19e94042caSEugene Zelenko #include <cstdint> 20e94042caSEugene Zelenko #include <utility> 2182af9438SZachary Turner 22e94042caSEugene Zelenko using namespace llvm; 2382af9438SZachary Turner 24ba915897SJonas Devlieghere llvm::Error DWARFAcceleratorTable::extract() { 2582af9438SZachary Turner uint32_t Offset = 0; 2682af9438SZachary Turner 2782af9438SZachary Turner // Check that we can at least read the header. 2882af9438SZachary Turner if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength)+4)) 29ba915897SJonas Devlieghere return make_error<StringError>("Section too small: cannot read header.", 30ba915897SJonas Devlieghere inconvertibleErrorCode()); 3182af9438SZachary Turner 3282af9438SZachary Turner Hdr.Magic = AccelSection.getU32(&Offset); 3382af9438SZachary Turner Hdr.Version = AccelSection.getU16(&Offset); 3482af9438SZachary Turner Hdr.HashFunction = AccelSection.getU16(&Offset); 3582af9438SZachary Turner Hdr.NumBuckets = AccelSection.getU32(&Offset); 3682af9438SZachary Turner Hdr.NumHashes = AccelSection.getU32(&Offset); 3782af9438SZachary Turner Hdr.HeaderDataLength = AccelSection.getU32(&Offset); 3882af9438SZachary Turner 3982af9438SZachary Turner // Check that we can read all the hashes and offsets from the 4082af9438SZachary Turner // section (see SourceLevelDebugging.rst for the structure of the index). 41ba915897SJonas Devlieghere // We need to substract one because we're checking for an *offset* which is 42ba915897SJonas Devlieghere // equal to the size for an empty table and hence pointer after the section. 4382af9438SZachary Turner if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength + 44ba915897SJonas Devlieghere Hdr.NumBuckets * 4 + Hdr.NumHashes * 8 - 1)) 45ba915897SJonas Devlieghere return make_error<StringError>( 46ba915897SJonas Devlieghere "Section too small: cannot read buckets and hashes.", 47ba915897SJonas Devlieghere inconvertibleErrorCode()); 4882af9438SZachary Turner 4982af9438SZachary Turner HdrData.DIEOffsetBase = AccelSection.getU32(&Offset); 5082af9438SZachary Turner uint32_t NumAtoms = AccelSection.getU32(&Offset); 5182af9438SZachary Turner 5282af9438SZachary Turner for (unsigned i = 0; i < NumAtoms; ++i) { 5382af9438SZachary Turner uint16_t AtomType = AccelSection.getU16(&Offset); 546c273763SGreg Clayton auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset)); 5582af9438SZachary Turner HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm)); 5682af9438SZachary Turner } 5782af9438SZachary Turner 5899fdb9d9SAdrian Prantl IsValid = true; 59ba915897SJonas Devlieghere return Error::success(); 6082af9438SZachary Turner } 6182af9438SZachary Turner 62e41823bbSSpyridoula Gravani uint32_t DWARFAcceleratorTable::getNumBuckets() { return Hdr.NumBuckets; } 63e41823bbSSpyridoula Gravani uint32_t DWARFAcceleratorTable::getNumHashes() { return Hdr.NumHashes; } 64e41823bbSSpyridoula Gravani uint32_t DWARFAcceleratorTable::getSizeHdr() { return sizeof(Hdr); } 65e41823bbSSpyridoula Gravani uint32_t DWARFAcceleratorTable::getHeaderDataLength() { 66e41823bbSSpyridoula Gravani return Hdr.HeaderDataLength; 67e41823bbSSpyridoula Gravani } 68e41823bbSSpyridoula Gravani 69837c110cSSpyridoula Gravani ArrayRef<std::pair<DWARFAcceleratorTable::HeaderData::AtomType, 70837c110cSSpyridoula Gravani DWARFAcceleratorTable::HeaderData::Form>> 71837c110cSSpyridoula Gravani DWARFAcceleratorTable::getAtomsDesc() { 72837c110cSSpyridoula Gravani return HdrData.Atoms; 73837c110cSSpyridoula Gravani } 74837c110cSSpyridoula Gravani 75837c110cSSpyridoula Gravani bool DWARFAcceleratorTable::validateForms() { 76837c110cSSpyridoula Gravani for (auto Atom : getAtomsDesc()) { 77837c110cSSpyridoula Gravani DWARFFormValue FormValue(Atom.second); 78837c110cSSpyridoula Gravani switch (Atom.first) { 79837c110cSSpyridoula Gravani case dwarf::DW_ATOM_die_offset: 8070d35e10SSpyridoula Gravani case dwarf::DW_ATOM_die_tag: 8170d35e10SSpyridoula Gravani case dwarf::DW_ATOM_type_flags: 82837c110cSSpyridoula Gravani if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) && 83837c110cSSpyridoula Gravani !FormValue.isFormClass(DWARFFormValue::FC_Flag)) || 84837c110cSSpyridoula Gravani FormValue.getForm() == dwarf::DW_FORM_sdata) 85837c110cSSpyridoula Gravani return false; 86*0e6694d1SAdrian Prantl break; 87837c110cSSpyridoula Gravani default: 88837c110cSSpyridoula Gravani break; 89837c110cSSpyridoula Gravani } 90837c110cSSpyridoula Gravani } 91837c110cSSpyridoula Gravani return true; 92837c110cSSpyridoula Gravani } 93837c110cSSpyridoula Gravani 9470d35e10SSpyridoula Gravani std::pair<uint32_t, dwarf::Tag> 9570d35e10SSpyridoula Gravani DWARFAcceleratorTable::readAtoms(uint32_t &HashDataOffset) { 96837c110cSSpyridoula Gravani uint32_t DieOffset = dwarf::DW_INVALID_OFFSET; 9770d35e10SSpyridoula Gravani dwarf::Tag DieTag = dwarf::DW_TAG_null; 98e5400f8aSPaul Robinson DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; 99837c110cSSpyridoula Gravani 100837c110cSSpyridoula Gravani for (auto Atom : getAtomsDesc()) { 101837c110cSSpyridoula Gravani DWARFFormValue FormValue(Atom.second); 102e5400f8aSPaul Robinson FormValue.extractValue(AccelSection, &HashDataOffset, FormParams); 103837c110cSSpyridoula Gravani switch (Atom.first) { 104837c110cSSpyridoula Gravani case dwarf::DW_ATOM_die_offset: 105837c110cSSpyridoula Gravani DieOffset = *FormValue.getAsUnsignedConstant(); 106837c110cSSpyridoula Gravani break; 10770d35e10SSpyridoula Gravani case dwarf::DW_ATOM_die_tag: 10870d35e10SSpyridoula Gravani DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant(); 10970d35e10SSpyridoula Gravani break; 110837c110cSSpyridoula Gravani default: 111837c110cSSpyridoula Gravani break; 112837c110cSSpyridoula Gravani } 113837c110cSSpyridoula Gravani } 11470d35e10SSpyridoula Gravani return {DieOffset, DieTag}; 115837c110cSSpyridoula Gravani } 116837c110cSSpyridoula Gravani 1178c209aa8SMatthias Braun LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const { 11899fdb9d9SAdrian Prantl if (!IsValid) 11999fdb9d9SAdrian Prantl return; 12099fdb9d9SAdrian Prantl 12182af9438SZachary Turner // Dump the header. 12282af9438SZachary Turner OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n' 12382af9438SZachary Turner << "Version = " << format("0x%04x", Hdr.Version) << '\n' 12482af9438SZachary Turner << "Hash function = " << format("0x%08x", Hdr.HashFunction) << '\n' 12582af9438SZachary Turner << "Bucket count = " << Hdr.NumBuckets << '\n' 12682af9438SZachary Turner << "Hashes count = " << Hdr.NumHashes << '\n' 12782af9438SZachary Turner << "HeaderData length = " << Hdr.HeaderDataLength << '\n' 12882af9438SZachary Turner << "DIE offset base = " << HdrData.DIEOffsetBase << '\n' 12982af9438SZachary Turner << "Number of atoms = " << HdrData.Atoms.size() << '\n'; 13082af9438SZachary Turner 13182af9438SZachary Turner unsigned i = 0; 13282af9438SZachary Turner SmallVector<DWARFFormValue, 3> AtomForms; 13382af9438SZachary Turner for (const auto &Atom: HdrData.Atoms) { 13482af9438SZachary Turner OS << format("Atom[%d] Type: ", i++); 135149f6eaeSMehdi Amini auto TypeString = dwarf::AtomTypeString(Atom.first); 136149f6eaeSMehdi Amini if (!TypeString.empty()) 13782af9438SZachary Turner OS << TypeString; 13882af9438SZachary Turner else 13982af9438SZachary Turner OS << format("DW_ATOM_Unknown_0x%x", Atom.first); 14082af9438SZachary Turner OS << " Form: "; 141149f6eaeSMehdi Amini auto FormString = dwarf::FormEncodingString(Atom.second); 142149f6eaeSMehdi Amini if (!FormString.empty()) 14382af9438SZachary Turner OS << FormString; 14482af9438SZachary Turner else 14582af9438SZachary Turner OS << format("DW_FORM_Unknown_0x%x", Atom.second); 14682af9438SZachary Turner OS << '\n'; 14782af9438SZachary Turner AtomForms.push_back(DWARFFormValue(Atom.second)); 14882af9438SZachary Turner } 14982af9438SZachary Turner 15082af9438SZachary Turner // Now go through the actual tables and dump them. 15182af9438SZachary Turner uint32_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength; 15282af9438SZachary Turner unsigned HashesBase = Offset + Hdr.NumBuckets * 4; 15382af9438SZachary Turner unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4; 154e5400f8aSPaul Robinson DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; 15582af9438SZachary Turner 15682af9438SZachary Turner for (unsigned Bucket = 0; Bucket < Hdr.NumBuckets; ++Bucket) { 15782af9438SZachary Turner unsigned Index = AccelSection.getU32(&Offset); 15882af9438SZachary Turner 15982af9438SZachary Turner OS << format("Bucket[%d]\n", Bucket); 16082af9438SZachary Turner if (Index == UINT32_MAX) { 16182af9438SZachary Turner OS << " EMPTY\n"; 16282af9438SZachary Turner continue; 16382af9438SZachary Turner } 16482af9438SZachary Turner 16582af9438SZachary Turner for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) { 16682af9438SZachary Turner unsigned HashOffset = HashesBase + HashIdx*4; 16782af9438SZachary Turner unsigned OffsetsOffset = OffsetsBase + HashIdx*4; 16882af9438SZachary Turner uint32_t Hash = AccelSection.getU32(&HashOffset); 16982af9438SZachary Turner 17082af9438SZachary Turner if (Hash % Hdr.NumBuckets != Bucket) 17182af9438SZachary Turner break; 17282af9438SZachary Turner 17382af9438SZachary Turner unsigned DataOffset = AccelSection.getU32(&OffsetsOffset); 17482af9438SZachary Turner OS << format(" Hash = 0x%08x Offset = 0x%08x\n", Hash, DataOffset); 17582af9438SZachary Turner if (!AccelSection.isValidOffset(DataOffset)) { 17682af9438SZachary Turner OS << " Invalid section offset\n"; 17782af9438SZachary Turner continue; 17882af9438SZachary Turner } 17982af9438SZachary Turner while (AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) { 18017536b93SPaul Robinson unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset); 18182af9438SZachary Turner if (!StringOffset) 18282af9438SZachary Turner break; 18382af9438SZachary Turner OS << format(" Name: %08x \"%s\"\n", StringOffset, 18482af9438SZachary Turner StringSection.getCStr(&StringOffset)); 18582af9438SZachary Turner unsigned NumData = AccelSection.getU32(&DataOffset); 18682af9438SZachary Turner for (unsigned Data = 0; Data < NumData; ++Data) { 18782af9438SZachary Turner OS << format(" Data[%d] => ", Data); 18882af9438SZachary Turner unsigned i = 0; 18982af9438SZachary Turner for (auto &Atom : AtomForms) { 19082af9438SZachary Turner OS << format("{Atom[%d]: ", i++); 191e5400f8aSPaul Robinson if (Atom.extractValue(AccelSection, &DataOffset, FormParams)) 192cddab279SGreg Clayton Atom.dump(OS); 19382af9438SZachary Turner else 19482af9438SZachary Turner OS << "Error extracting the value"; 19582af9438SZachary Turner OS << "} "; 19682af9438SZachary Turner } 19782af9438SZachary Turner OS << '\n'; 19882af9438SZachary Turner } 19982af9438SZachary Turner } 20082af9438SZachary Turner } 20182af9438SZachary Turner } 20282af9438SZachary Turner } 20399fdb9d9SAdrian Prantl 20499fdb9d9SAdrian Prantl DWARFAcceleratorTable::ValueIterator::ValueIterator( 20599fdb9d9SAdrian Prantl const DWARFAcceleratorTable &AccelTable, unsigned Offset) 20699fdb9d9SAdrian Prantl : AccelTable(&AccelTable), DataOffset(Offset) { 20799fdb9d9SAdrian Prantl if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) 20899fdb9d9SAdrian Prantl return; 20999fdb9d9SAdrian Prantl 21099fdb9d9SAdrian Prantl for (const auto &Atom : AccelTable.HdrData.Atoms) 21199fdb9d9SAdrian Prantl AtomForms.push_back(DWARFFormValue(Atom.second)); 21299fdb9d9SAdrian Prantl 21399fdb9d9SAdrian Prantl // Read the first entry. 21499fdb9d9SAdrian Prantl NumData = AccelTable.AccelSection.getU32(&DataOffset); 21599fdb9d9SAdrian Prantl Next(); 21699fdb9d9SAdrian Prantl } 21799fdb9d9SAdrian Prantl 21899fdb9d9SAdrian Prantl void DWARFAcceleratorTable::ValueIterator::Next() { 21999fdb9d9SAdrian Prantl assert(NumData > 0 && "attempted to increment iterator past the end"); 22099fdb9d9SAdrian Prantl auto &AccelSection = AccelTable->AccelSection; 22199fdb9d9SAdrian Prantl if (Data >= NumData || 22299fdb9d9SAdrian Prantl !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) { 22399fdb9d9SAdrian Prantl NumData = 0; 22499fdb9d9SAdrian Prantl return; 22599fdb9d9SAdrian Prantl } 226e5400f8aSPaul Robinson DWARFFormParams FormParams = {AccelTable->Hdr.Version, 0, 227e5400f8aSPaul Robinson dwarf::DwarfFormat::DWARF32}; 22899fdb9d9SAdrian Prantl for (auto &Atom : AtomForms) 229e5400f8aSPaul Robinson Atom.extractValue(AccelSection, &DataOffset, FormParams); 23099fdb9d9SAdrian Prantl ++Data; 23199fdb9d9SAdrian Prantl } 23299fdb9d9SAdrian Prantl 23399fdb9d9SAdrian Prantl iterator_range<DWARFAcceleratorTable::ValueIterator> 23499fdb9d9SAdrian Prantl DWARFAcceleratorTable::equal_range(StringRef Key) const { 23599fdb9d9SAdrian Prantl if (!IsValid) 23699fdb9d9SAdrian Prantl return make_range(ValueIterator(), ValueIterator()); 23799fdb9d9SAdrian Prantl 23899fdb9d9SAdrian Prantl // Find the bucket. 23999fdb9d9SAdrian Prantl unsigned HashValue = dwarf::djbHash(Key); 24099fdb9d9SAdrian Prantl unsigned Bucket = HashValue % Hdr.NumBuckets; 24199fdb9d9SAdrian Prantl unsigned BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength; 24299fdb9d9SAdrian Prantl unsigned HashesBase = BucketBase + Hdr.NumBuckets * 4; 24399fdb9d9SAdrian Prantl unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4; 24499fdb9d9SAdrian Prantl 24599fdb9d9SAdrian Prantl unsigned BucketOffset = BucketBase + Bucket * 4; 24699fdb9d9SAdrian Prantl unsigned Index = AccelSection.getU32(&BucketOffset); 24799fdb9d9SAdrian Prantl 24899fdb9d9SAdrian Prantl // Search through all hashes in the bucket. 24999fdb9d9SAdrian Prantl for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) { 25099fdb9d9SAdrian Prantl unsigned HashOffset = HashesBase + HashIdx * 4; 25199fdb9d9SAdrian Prantl unsigned OffsetsOffset = OffsetsBase + HashIdx * 4; 25299fdb9d9SAdrian Prantl uint32_t Hash = AccelSection.getU32(&HashOffset); 25399fdb9d9SAdrian Prantl 25499fdb9d9SAdrian Prantl if (Hash % Hdr.NumBuckets != Bucket) 25599fdb9d9SAdrian Prantl // We are already in the next bucket. 25699fdb9d9SAdrian Prantl break; 25799fdb9d9SAdrian Prantl 25899fdb9d9SAdrian Prantl unsigned DataOffset = AccelSection.getU32(&OffsetsOffset); 25999fdb9d9SAdrian Prantl unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset); 26099fdb9d9SAdrian Prantl if (!StringOffset) 26199fdb9d9SAdrian Prantl break; 26299fdb9d9SAdrian Prantl 26399fdb9d9SAdrian Prantl // Finally, compare the key. 26499fdb9d9SAdrian Prantl if (Key == StringSection.getCStr(&StringOffset)) 26599fdb9d9SAdrian Prantl return make_range({*this, DataOffset}, ValueIterator()); 26699fdb9d9SAdrian Prantl } 26799fdb9d9SAdrian Prantl return make_range(ValueIterator(), ValueIterator()); 26899fdb9d9SAdrian Prantl } 269