1 //==-- llvm/CodeGen/DwarfAccelTable.h - Dwarf Accelerator Tables -*- C++ -*-==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains support for writing dwarf accelerator tables. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef CODEGEN_ASMPRINTER_DWARFACCELTABLE_H__ 15 #define CODEGEN_ASMPRINTER_DWARFACCELTABLE_H__ 16 17 #include "DIE.h" 18 #include "llvm/ADT/ArrayRef.h" 19 #include "llvm/ADT/StringMap.h" 20 #include "llvm/MC/MCSymbol.h" 21 #include "llvm/Support/Compiler.h" 22 #include "llvm/Support/DataTypes.h" 23 #include "llvm/Support/Debug.h" 24 #include "llvm/Support/Dwarf.h" 25 #include "llvm/Support/ErrorHandling.h" 26 #include "llvm/Support/Format.h" 27 #include "llvm/Support/FormattedStream.h" 28 #include <vector> 29 30 // The dwarf accelerator tables are an indirect hash table optimized 31 // for null lookup rather than access to known data. They are output into 32 // an on-disk format that looks like this: 33 // 34 // .-------------. 35 // | HEADER | 36 // |-------------| 37 // | BUCKETS | 38 // |-------------| 39 // | HASHES | 40 // |-------------| 41 // | OFFSETS | 42 // |-------------| 43 // | DATA | 44 // `-------------' 45 // 46 // where the header contains a magic number, version, type of hash function, 47 // the number of buckets, total number of hashes, and room for a special 48 // struct of data and the length of that struct. 49 // 50 // The buckets contain an index (e.g. 6) into the hashes array. The hashes 51 // section contains all of the 32-bit hash values in contiguous memory, and 52 // the offsets contain the offset into the data area for the particular 53 // hash. 54 // 55 // For a lookup example, we could hash a function name and take it modulo the 56 // number of buckets giving us our bucket. From there we take the bucket value 57 // as an index into the hashes table and look at each successive hash as long 58 // as the hash value is still the same modulo result (bucket value) as earlier. 59 // If we have a match we look at that same entry in the offsets table and 60 // grab the offset in the data for our final match. 61 62 namespace llvm { 63 64 class AsmPrinter; 65 class DwarfFile; 66 67 class DwarfAccelTable { 68 69 static uint32_t HashDJB(StringRef Str) { 70 uint32_t h = 5381; 71 for (unsigned i = 0, e = Str.size(); i != e; ++i) 72 h = ((h << 5) + h) + Str[i]; 73 return h; 74 } 75 76 // Helper function to compute the number of buckets needed based on 77 // the number of unique hashes. 78 void ComputeBucketCount(void); 79 80 struct TableHeader { 81 uint32_t magic; // 'HASH' magic value to allow endian detection 82 uint16_t version; // Version number. 83 uint16_t hash_function; // The hash function enumeration that was used. 84 uint32_t bucket_count; // The number of buckets in this hash table. 85 uint32_t hashes_count; // The total number of unique hash values 86 // and hash data offsets in this table. 87 uint32_t header_data_len; // The bytes to skip to get to the hash 88 // indexes (buckets) for correct alignment. 89 // Also written to disk is the implementation specific header data. 90 91 static const uint32_t MagicHash = 0x48415348; 92 93 TableHeader(uint32_t data_len) 94 : magic(MagicHash), version(1), 95 hash_function(dwarf::DW_hash_function_djb), bucket_count(0), 96 hashes_count(0), header_data_len(data_len) {} 97 98 #ifndef NDEBUG 99 void print(raw_ostream &O) { 100 O << "Magic: " << format("0x%x", magic) << "\n" 101 << "Version: " << version << "\n" 102 << "Hash Function: " << hash_function << "\n" 103 << "Bucket Count: " << bucket_count << "\n" 104 << "Header Data Length: " << header_data_len << "\n"; 105 } 106 void dump() { print(dbgs()); } 107 #endif 108 }; 109 110 public: 111 // The HeaderData describes the form of each set of data. In general this 112 // is as a list of atoms (atom_count) where each atom contains a type 113 // (AtomType type) of data, and an encoding form (form). In the case of 114 // data that is referenced via DW_FORM_ref_* the die_offset_base is 115 // used to describe the offset for all forms in the list of atoms. 116 // This also serves as a public interface of sorts. 117 // When written to disk this will have the form: 118 // 119 // uint32_t die_offset_base 120 // uint32_t atom_count 121 // atom_count Atoms 122 123 // Make these public so that they can be used as a general interface to 124 // the class. 125 struct Atom { 126 uint16_t type; // enum AtomType 127 uint16_t form; // DWARF DW_FORM_ defines 128 129 LLVM_CONSTEXPR Atom(uint16_t type, uint16_t form) 130 : type(type), form(form) {} 131 #ifndef NDEBUG 132 void print(raw_ostream &O) { 133 O << "Type: " << dwarf::AtomTypeString(type) << "\n" 134 << "Form: " << dwarf::FormEncodingString(form) << "\n"; 135 } 136 void dump() { print(dbgs()); } 137 #endif 138 }; 139 140 private: 141 struct TableHeaderData { 142 uint32_t die_offset_base; 143 SmallVector<Atom, 1> Atoms; 144 145 TableHeaderData(ArrayRef<Atom> AtomList, uint32_t offset = 0) 146 : die_offset_base(offset), Atoms(AtomList.begin(), AtomList.end()) {} 147 148 #ifndef NDEBUG 149 void print(raw_ostream &O) { 150 O << "die_offset_base: " << die_offset_base << "\n"; 151 for (size_t i = 0; i < Atoms.size(); i++) 152 Atoms[i].print(O); 153 } 154 void dump() { print(dbgs()); } 155 #endif 156 }; 157 158 // The data itself consists of a str_offset, a count of the DIEs in the 159 // hash and the offsets to the DIEs themselves. 160 // On disk each data section is ended with a 0 KeyType as the end of the 161 // hash chain. 162 // On output this looks like: 163 // uint32_t str_offset 164 // uint32_t hash_data_count 165 // HashData[hash_data_count] 166 public: 167 struct HashDataContents { 168 const DIE *Die; // Offsets 169 char Flags; // Specific flags to output 170 171 HashDataContents(const DIE *D, char Flags) : Die(D), Flags(Flags) {} 172 #ifndef NDEBUG 173 void print(raw_ostream &O) const { 174 O << " Offset: " << Die->getOffset() << "\n"; 175 O << " Tag: " << dwarf::TagString(Die->getTag()) << "\n"; 176 O << " Flags: " << Flags << "\n"; 177 } 178 #endif 179 }; 180 181 private: 182 // String Data 183 struct DataArray { 184 MCSymbol *StrSym; 185 std::vector<HashDataContents *> Values; 186 DataArray() : StrSym(nullptr) {} 187 }; 188 friend struct HashData; 189 struct HashData { 190 StringRef Str; 191 uint32_t HashValue; 192 MCSymbol *Sym; 193 DwarfAccelTable::DataArray &Data; // offsets 194 HashData(StringRef S, DwarfAccelTable::DataArray &Data) 195 : Str(S), Data(Data) { 196 HashValue = DwarfAccelTable::HashDJB(S); 197 } 198 #ifndef NDEBUG 199 void print(raw_ostream &O) { 200 O << "Name: " << Str << "\n"; 201 O << " Hash Value: " << format("0x%x", HashValue) << "\n"; 202 O << " Symbol: "; 203 if (Sym) 204 Sym->print(O); 205 else 206 O << "<none>"; 207 O << "\n"; 208 for (HashDataContents *C : Data.Values) { 209 O << " Offset: " << C->Die->getOffset() << "\n"; 210 O << " Tag: " << dwarf::TagString(C->Die->getTag()) << "\n"; 211 O << " Flags: " << C->Flags << "\n"; 212 } 213 } 214 void dump() { print(dbgs()); } 215 #endif 216 }; 217 218 DwarfAccelTable(const DwarfAccelTable &) LLVM_DELETED_FUNCTION; 219 void operator=(const DwarfAccelTable &) LLVM_DELETED_FUNCTION; 220 221 // Internal Functions 222 void EmitHeader(AsmPrinter *); 223 void EmitBuckets(AsmPrinter *); 224 void EmitHashes(AsmPrinter *); 225 void EmitOffsets(AsmPrinter *, MCSymbol *); 226 void EmitData(AsmPrinter *, DwarfFile *D); 227 228 // Allocator for HashData and HashDataContents. 229 BumpPtrAllocator Allocator; 230 231 // Output Variables 232 TableHeader Header; 233 TableHeaderData HeaderData; 234 std::vector<HashData *> Data; 235 236 typedef StringMap<DataArray, BumpPtrAllocator &> StringEntries; 237 StringEntries Entries; 238 239 // Buckets/Hashes/Offsets 240 typedef std::vector<HashData *> HashList; 241 typedef std::vector<HashList> BucketList; 242 BucketList Buckets; 243 HashList Hashes; 244 245 // Public Implementation 246 public: 247 DwarfAccelTable(ArrayRef<DwarfAccelTable::Atom>); 248 void AddName(StringRef Name, MCSymbol *StrSym, const DIE *Die, 249 char Flags = 0); 250 void FinalizeTable(AsmPrinter *, StringRef); 251 void Emit(AsmPrinter *, MCSymbol *, DwarfFile *); 252 #ifndef NDEBUG 253 void print(raw_ostream &O); 254 void dump() { print(dbgs()); } 255 #endif 256 }; 257 } 258 #endif 259