1 //===-- HashedNameToDIE.h ---------------------------------------*- 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 #ifndef SymbolFileDWARF_HashedNameToDIE_h_
11 #define SymbolFileDWARF_HashedNameToDIE_h_
12 
13 #include <vector>
14 #include "lldb/lldb-defines.h"
15 #include "lldb/Core/dwarf.h"
16 
17 class SymbolFileDWARF;
18 
19 typedef std::vector<dw_offset_t> DIEArray;
20 
21 class HashedNameToDIE
22 {
23 public:
24     enum NameFlags
25     {
26         eNameFlagIsExternal         = (1u << 0),
27         eNameFlagIsClassCXX         = (1u << 1),
28         eNameFlagIsClassObjC        = (1u << 2),
29         eNameFlagIsClassObjCMaster  = (1u << 3)
30     };
31 
32     enum TypeFlags
33     {
34         eTypeFlagIsExternal         = (1u << 0)
35     };
36 
37     enum HashFunctionType
38     {
39         eHashFunctionDJB        = 0u,   // Daniel J Bernstein hash function that is also used by the ELF GNU_HASH sections
40     };
41 
42     static const uint32_t HASH_MAGIC = 0x48415348u;
43 
44     struct Header
45 	{
46         uint32_t magic;              // 'HASH' magic value to allow endian detection
47         uint16_t version;            // Version number
48         uint8_t  addr_bytesize;      // Size in bytes of an address
49 		uint8_t  hash_function;      // The hash function enumeration that was used
50 		uint32_t bucket_count;       // The number of buckets in this hash table
51 		uint32_t hashes_count;       // The total number of unique hash values and hash data offsets in this table
52         uint32_t prologue_length;    // The length of the prologue
53 
54 		Header (uint32_t _prologue_length) :
55             magic (HASH_MAGIC),
56             version (1),
57             addr_bytesize (4),
58             hash_function (eHashFunctionDJB),
59             bucket_count (0),
60             hashes_count (0),
61             prologue_length (_prologue_length)
62 		{
63 		}
64 
65         virtual
66         ~Header ()
67         {
68         }
69 
70         virtual size_t
71         GetByteSize() const
72         {
73             return  sizeof(magic) +
74             sizeof(version) +
75             sizeof(addr_bytesize) +
76             sizeof(hash_function) +
77             sizeof(bucket_count) +
78             sizeof(hashes_count) +
79             sizeof(prologue_length) +
80             prologue_length;
81         }
82 
83         virtual void
84         Dump (lldb_private::Stream &s);
85 
86         virtual uint32_t
87         Read (const lldb_private::DataExtractor &data, uint32_t offset);
88 	};
89 
90     struct DWARF
91     {
92         enum AtomType
93         {
94             eAtomTypeNULL       = 0u,
95             eAtomTypeHashString = 1u,   // String value for hash, use DW_FORM_strp (preferred) or DW_FORM_string
96             eAtomTypeHashLength = 2u,   // Length of data for the previous string refered by the last eAtomTypeHashString atom
97             eAtomTypeArraySize  = 3u,   // A count that specifies a number of atoms that follow this entry, the next atom defines what the atom type for the array is
98             eAtomTypeDIEOffset  = 4u,   // DIE offset, check form for encoding. If DW_FORM_ref1,2,4,8 or DW_FORM_ref_udata, then this value is added to the prologue
99             eAtomTypeTag        = 5u,   // DW_TAG_xxx value, should be encoded as DW_FORM_data1 (if no tags exceed 255) or DW_FORM_data2
100             eAtomTypeNameFlags  = 6u,   // Flags from enum NameFlags
101             eAtomTypeTypeFlags  = 7u,   // Flags from enum TypeFlags
102         };
103 
104         struct Atom
105         {
106             uint16_t type;
107             dw_form_t form;
108 
109             Atom (uint16_t t = eAtomTypeNULL, dw_form_t f = 0) :
110                 type (t),
111                 form (f)
112             {
113             }
114         };
115 
116         typedef std::vector<Atom> AtomArray;
117 
118 
119         static const char *
120         GetAtomTypeName (uint16_t atom)
121         {
122             switch (atom)
123             {
124                 case eAtomTypeNULL:         return "NULL";
125                 case eAtomTypeHashString:   return "hash-string";
126                 case eAtomTypeHashLength:   return "hash-data-length";
127                 case eAtomTypeArraySize:    return "array-size";
128                 case eAtomTypeDIEOffset:    return "die-offset";
129                 case eAtomTypeTag:          return "die-tag";
130                 case eAtomTypeNameFlags:    return "name-flags";
131                 case eAtomTypeTypeFlags:    return "type-flags";
132             }
133             return "<invalid>";
134         }
135         struct Prologue
136         {
137             // DIE offset base so die offsets in hash_data can be CU relative
138             dw_offset_t die_base_offset;
139             AtomArray atoms;
140 
141             Prologue (dw_offset_t _die_base_offset = 0) :
142                 die_base_offset (_die_base_offset)
143             {
144                 // Define an array of DIE offsets by first defining an array,
145                 // and then define the atom type for the array, in this case
146                 // we have an array of DIE offsets
147                 atoms.push_back (Atom(eAtomTypeArraySize, DW_FORM_data4));
148                 atoms.push_back (Atom(eAtomTypeDIEOffset, DW_FORM_data4));
149             }
150 
151             virtual
152             ~Prologue ()
153             {
154             }
155 
156 
157             virtual void
158             Clear ()
159             {
160                 die_base_offset = 0;
161                 atoms.clear();
162             }
163 
164             virtual void
165             Dump (lldb_private::Stream &s);
166 
167             virtual uint32_t
168             Read (const lldb_private::DataExtractor &data, uint32_t offset);
169 
170             size_t
171             GetByteSize () const
172             {
173                 // Add an extra count to the atoms size for the zero termination Atom that gets
174                 // written to disk
175                 return sizeof(die_base_offset) + ((atoms.size() + 1) * sizeof(Atom));
176             }
177         };
178 
179         struct Header : public HashedNameToDIE::Header
180         {
181             Header (dw_offset_t _die_base_offset = 0) :
182                 HashedNameToDIE::Header (sizeof(Prologue)),
183                 dwarf_prologue (_die_base_offset)
184             {
185             }
186 
187             virtual
188             ~Header ()
189             {
190             }
191 
192             Prologue dwarf_prologue;
193 
194             virtual void
195             Dump (lldb_private::Stream &s);
196 
197             virtual uint32_t
198             Read (const lldb_private::DataExtractor &data, uint32_t offset);
199         };
200 
201     };
202 
203 
204     class MemoryTable
205     {
206     public:
207 
208         MemoryTable (SymbolFileDWARF *dwarf,
209                      const lldb_private::DataExtractor &data,
210                      bool is_apple_names);
211 
212         ~MemoryTable ()
213         {
214         }
215 
216         bool
217         Initialize ();
218 
219         bool
220         IsValid () const
221         {
222             return m_header.version > 0;
223         }
224 
225         uint32_t
226         GetOffsetOfBucketEntry (uint32_t idx) const
227         {
228             if (idx < m_header.bucket_count)
229                 return m_header.GetByteSize() + 4 * idx;
230             return UINT32_MAX;
231         }
232 
233         uint32_t
234         GetOffsetOfHashValue (uint32_t idx) const
235         {
236             if (idx < m_header.hashes_count)
237                 return  m_header.GetByteSize() +
238                 4 * m_header.bucket_count +
239                 4 * idx;
240             return UINT32_MAX;
241         }
242 
243         uint32_t
244         GetOffsetOfHashDataOffset (uint32_t idx) const
245         {
246             if (idx < m_header.hashes_count)
247             {
248                 return  m_header.GetByteSize() +
249                 4 * m_header.bucket_count +
250                 4 * m_header.hashes_count +
251                 4 * idx;
252             }
253             return UINT32_MAX;
254         }
255 
256         void
257         Dump (lldb_private::Stream &s);
258 
259         size_t
260         Find (const char *name, DIEArray &die_ofsets) const;
261 
262     protected:
263         const lldb_private::DataExtractor &m_data;
264         const lldb_private::DataExtractor &m_string_table;
265         bool m_is_apple_names; // true => .apple_names, false => .apple_types
266         DWARF::Header m_header;
267     };
268 };
269 
270 #endif  // SymbolFileDWARF_HashedNameToDIE_h_
271