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