Home | History | Annotate | Download | only in AsmPrinter
      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 LLVM_LIB_CODEGEN_ASMPRINTER_DWARFACCELTABLE_H
     15 #define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFACCELTABLE_H
     16 
     17 #include "llvm/ADT/ArrayRef.h"
     18 #include "llvm/ADT/StringMap.h"
     19 #include "llvm/CodeGen/DIE.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 DwarfDebug;
     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, 3> 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     DwarfStringPoolEntryRef Name;
    185     std::vector<HashDataContents *> Values;
    186   };
    187   friend struct HashData;
    188   struct HashData {
    189     StringRef Str;
    190     uint32_t HashValue;
    191     MCSymbol *Sym;
    192     DwarfAccelTable::DataArray &Data; // offsets
    193     HashData(StringRef S, DwarfAccelTable::DataArray &Data)
    194         : Str(S), Data(Data) {
    195       HashValue = DwarfAccelTable::HashDJB(S);
    196     }
    197 #ifndef NDEBUG
    198     void print(raw_ostream &O) {
    199       O << "Name: " << Str << "\n";
    200       O << "  Hash Value: " << format("0x%x", HashValue) << "\n";
    201       O << "  Symbol: ";
    202       if (Sym)
    203         O << *Sym;
    204       else
    205         O << "<none>";
    206       O << "\n";
    207       for (HashDataContents *C : Data.Values) {
    208         O << "  Offset: " << C->Die->getOffset() << "\n";
    209         O << "  Tag: " << dwarf::TagString(C->Die->getTag()) << "\n";
    210         O << "  Flags: " << C->Flags << "\n";
    211       }
    212     }
    213     void dump() { print(dbgs()); }
    214 #endif
    215   };
    216 
    217   DwarfAccelTable(const DwarfAccelTable &) = delete;
    218   void operator=(const DwarfAccelTable &) = delete;
    219 
    220   // Internal Functions
    221   void EmitHeader(AsmPrinter *);
    222   void EmitBuckets(AsmPrinter *);
    223   void EmitHashes(AsmPrinter *);
    224   void emitOffsets(AsmPrinter *, const MCSymbol *);
    225   void EmitData(AsmPrinter *, DwarfDebug *D);
    226 
    227   // Allocator for HashData and HashDataContents.
    228   BumpPtrAllocator Allocator;
    229 
    230   // Output Variables
    231   TableHeader Header;
    232   TableHeaderData HeaderData;
    233   std::vector<HashData *> Data;
    234 
    235   typedef StringMap<DataArray, BumpPtrAllocator &> StringEntries;
    236   StringEntries Entries;
    237 
    238   // Buckets/Hashes/Offsets
    239   typedef std::vector<HashData *> HashList;
    240   typedef std::vector<HashList> BucketList;
    241   BucketList Buckets;
    242   HashList Hashes;
    243 
    244   // Public Implementation
    245 public:
    246   DwarfAccelTable(ArrayRef<DwarfAccelTable::Atom>);
    247   void AddName(DwarfStringPoolEntryRef Name, const DIE *Die, char Flags = 0);
    248   void FinalizeTable(AsmPrinter *, StringRef);
    249   void emit(AsmPrinter *, const MCSymbol *, DwarfDebug *);
    250 #ifndef NDEBUG
    251   void print(raw_ostream &O);
    252   void dump() { print(dbgs()); }
    253 #endif
    254 };
    255 }
    256 #endif
    257