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