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 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