1 //===- llvm/unittest/CodeGen/DIEHashTest.cpp ------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "../lib/CodeGen/AsmPrinter/DIEHash.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/BinaryFormat/Dwarf.h"
12 #include "llvm/CodeGen/DIE.h"
13 #include "llvm/CodeGen/DwarfStringPoolEntry.h"
14 #include "llvm/Support/Debug.h"
15 #include "llvm/Support/Format.h"
16 #include "gtest/gtest.h"
17 
18 using namespace llvm;
19 
20 namespace {
21 
22 // Test fixture
23 class DIEHashTest : public testing::Test {
24 public:
25   BumpPtrAllocator Alloc;
26 
27 private:
28   StringMap<DwarfStringPoolEntry> Pool;
29 
30 public:
31   DIEString getString(StringRef S) {
32     DwarfStringPoolEntry Entry = {nullptr, 1, 1};
33     return DIEString(DwarfStringPoolEntryRef(
34         *Pool.insert(std::make_pair(S, Entry)).first, Entry.isIndexed()));
35   }
36 };
37 
38 TEST_F(DIEHashTest, Data1) {
39   DIEHash Hash;
40   DIE &Die = *DIE::get(Alloc, dwarf::DW_TAG_base_type);
41   DIEInteger Size(4);
42   Die.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Size);
43   uint64_t MD5Res = Hash.computeTypeSignature(Die);
44   ASSERT_EQ(0x1AFE116E83701108ULL, MD5Res);
45 }
46 
47 // struct {};
48 TEST_F(DIEHashTest, TrivialType) {
49   DIE &Unnamed = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
50   DIEInteger One(1);
51   Unnamed.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
52 
53   // Line and file number are ignored.
54   Unnamed.addValue(Alloc, dwarf::DW_AT_decl_file, dwarf::DW_FORM_data1, One);
55   Unnamed.addValue(Alloc, dwarf::DW_AT_decl_line, dwarf::DW_FORM_data1, One);
56   uint64_t MD5Res = DIEHash().computeTypeSignature(Unnamed);
57 
58   // The exact same hash GCC produces for this DIE.
59   ASSERT_EQ(0x715305ce6cfd9ad1ULL, MD5Res);
60 }
61 
62 // struct foo { };
63 TEST_F(DIEHashTest, NamedType) {
64   DIE &Foo = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
65   DIEInteger One(1);
66   DIEString FooStr = getString("foo");
67   Foo.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
68   Foo.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
69 
70   uint64_t MD5Res = DIEHash().computeTypeSignature(Foo);
71 
72   // The exact same hash GCC produces for this DIE.
73   ASSERT_EQ(0xd566dbd2ca5265ffULL, MD5Res);
74 }
75 
76 // namespace space { struct foo { }; }
77 TEST_F(DIEHashTest, NamespacedType) {
78   DIE &CU = *DIE::get(Alloc, dwarf::DW_TAG_compile_unit);
79 
80   auto Space = DIE::get(Alloc, dwarf::DW_TAG_namespace);
81   DIEInteger One(1);
82   DIEString SpaceStr = getString("space");
83   Space->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, SpaceStr);
84   // DW_AT_declaration is ignored.
85   Space->addValue(Alloc, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag_present,
86                   One);
87   // sibling?
88 
89   auto Foo = DIE::get(Alloc, dwarf::DW_TAG_structure_type);
90   DIEString FooStr = getString("foo");
91   Foo->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
92   Foo->addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
93 
94   DIE &N = *Foo;
95   Space->addChild(std::move(Foo));
96   CU.addChild(std::move(Space));
97 
98   uint64_t MD5Res = DIEHash().computeTypeSignature(N);
99 
100   // The exact same hash GCC produces for this DIE.
101   ASSERT_EQ(0x7b80381fd17f1e33ULL, MD5Res);
102 }
103 
104 // struct { int member; };
105 TEST_F(DIEHashTest, TypeWithMember) {
106   DIE &Unnamed = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
107   DIEInteger Four(4);
108   Unnamed.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Four);
109 
110   DIE &Int = *DIE::get(Alloc, dwarf::DW_TAG_base_type);
111   DIEString IntStr = getString("int");
112   Int.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, IntStr);
113   Int.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Four);
114   DIEInteger Five(5);
115   Int.addValue(Alloc, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, Five);
116 
117   DIEEntry IntRef(Int);
118 
119   auto Member = DIE::get(Alloc, dwarf::DW_TAG_member);
120   DIEString MemberStr = getString("member");
121   Member->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, MemberStr);
122   DIEInteger Zero(0);
123   Member->addValue(Alloc, dwarf::DW_AT_data_member_location,
124                    dwarf::DW_FORM_data1, Zero);
125   Member->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, IntRef);
126 
127   Unnamed.addChild(std::move(Member));
128 
129   uint64_t MD5Res = DIEHash().computeTypeSignature(Unnamed);
130 
131   ASSERT_EQ(0x5646aa436b7e07c6ULL, MD5Res);
132 }
133 
134 // struct foo { int mem1, mem2; };
135 TEST_F(DIEHashTest, ReusedType) {
136   DIE &Unnamed = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
137   DIEInteger Eight(8);
138   Unnamed.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
139 
140   DIEInteger Four(4);
141   DIE &Int = *DIE::get(Alloc, dwarf::DW_TAG_base_type);
142   DIEString IntStr = getString("int");
143   Int.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, IntStr);
144   Int.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Four);
145   DIEInteger Five(5);
146   Int.addValue(Alloc, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, Five);
147 
148   DIEEntry IntRef(Int);
149 
150   auto Mem1 = DIE::get(Alloc, dwarf::DW_TAG_member);
151   DIEString Mem1Str = getString("mem1");
152   Mem1->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, Mem1Str);
153   DIEInteger Zero(0);
154   Mem1->addValue(Alloc, dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1,
155                  Zero);
156   Mem1->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, IntRef);
157 
158   Unnamed.addChild(std::move(Mem1));
159 
160   auto Mem2 = DIE::get(Alloc, dwarf::DW_TAG_member);
161   DIEString Mem2Str = getString("mem2");
162   Mem2->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, Mem2Str);
163   Mem2->addValue(Alloc, dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1,
164                  Four);
165   Mem2->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, IntRef);
166 
167   Unnamed.addChild(std::move(Mem2));
168 
169   uint64_t MD5Res = DIEHash().computeTypeSignature(Unnamed);
170 
171   ASSERT_EQ(0x3a7dc3ed7b76b2f8ULL, MD5Res);
172 }
173 
174 // struct foo { static foo f; };
175 TEST_F(DIEHashTest, RecursiveType) {
176   DIE &Foo = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
177   DIEInteger One(1);
178   Foo.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
179   DIEString FooStr = getString("foo");
180   Foo.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
181 
182   auto Mem = DIE::get(Alloc, dwarf::DW_TAG_member);
183   DIEString MemStr = getString("mem");
184   Mem->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, MemStr);
185   DIEEntry FooRef(Foo);
186   Mem->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, FooRef);
187   // DW_AT_external and DW_AT_declaration are ignored anyway, so skip them.
188 
189   Foo.addChild(std::move(Mem));
190 
191   uint64_t MD5Res = DIEHash().computeTypeSignature(Foo);
192 
193   ASSERT_EQ(0x73d8b25aef227b06ULL, MD5Res);
194 }
195 
196 // struct foo { foo *mem; };
197 TEST_F(DIEHashTest, Pointer) {
198   DIE &Foo = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
199   DIEInteger Eight(8);
200   Foo.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
201   DIEString FooStr = getString("foo");
202   Foo.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
203 
204   auto Mem = DIE::get(Alloc, dwarf::DW_TAG_member);
205   DIEString MemStr = getString("mem");
206   Mem->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, MemStr);
207   DIEInteger Zero(0);
208   Mem->addValue(Alloc, dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1,
209                 Zero);
210 
211   DIE &FooPtr = *DIE::get(Alloc, dwarf::DW_TAG_pointer_type);
212   FooPtr.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
213   DIEEntry FooRef(Foo);
214   FooPtr.addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, FooRef);
215 
216   DIEEntry FooPtrRef(FooPtr);
217   Mem->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, FooPtrRef);
218 
219   Foo.addChild(std::move(Mem));
220 
221   uint64_t MD5Res = DIEHash().computeTypeSignature(Foo);
222 
223   ASSERT_EQ(0x74ea73862e8708d2ULL, MD5Res);
224 }
225 
226 // struct foo { foo &mem; };
227 TEST_F(DIEHashTest, Reference) {
228   DIE &Foo = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
229   DIEInteger Eight(8);
230   Foo.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
231   DIEString FooStr = getString("foo");
232   Foo.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
233 
234   auto Mem = DIE::get(Alloc, dwarf::DW_TAG_member);
235   DIEString MemStr = getString("mem");
236   Mem->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, MemStr);
237   DIEInteger Zero(0);
238   Mem->addValue(Alloc, dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1,
239                 Zero);
240 
241   DIE &FooRef = *DIE::get(Alloc, dwarf::DW_TAG_reference_type);
242   FooRef.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
243   DIEEntry FooEntry(Foo);
244   FooRef.addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, FooEntry);
245 
246   DIE &FooRefConst = *DIE::get(Alloc, dwarf::DW_TAG_const_type);
247   DIEEntry FooRefRef(FooRef);
248   FooRefConst.addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4,
249                        FooRefRef);
250 
251   DIEEntry FooRefConstRef(FooRefConst);
252   Mem->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, FooRefConstRef);
253 
254   Foo.addChild(std::move(Mem));
255 
256   uint64_t MD5Res = DIEHash().computeTypeSignature(Foo);
257 
258   ASSERT_EQ(0xa0b15f467ad4525bULL, MD5Res);
259 }
260 
261 // struct foo { foo &&mem; };
262 TEST_F(DIEHashTest, RValueReference) {
263   DIE &Foo = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
264   DIEInteger Eight(8);
265   Foo.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
266   DIEString FooStr = getString("foo");
267   Foo.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
268 
269   auto Mem = DIE::get(Alloc, dwarf::DW_TAG_member);
270   DIEString MemStr = getString("mem");
271   Mem->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, MemStr);
272   DIEInteger Zero(0);
273   Mem->addValue(Alloc, dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1,
274                 Zero);
275 
276   DIE &FooRef = *DIE::get(Alloc, dwarf::DW_TAG_rvalue_reference_type);
277   FooRef.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
278   DIEEntry FooEntry(Foo);
279   FooRef.addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, FooEntry);
280 
281   DIE &FooRefConst = *DIE::get(Alloc, dwarf::DW_TAG_const_type);
282   DIEEntry FooRefRef(FooRef);
283   FooRefConst.addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4,
284                        FooRefRef);
285 
286   DIEEntry FooRefConstRef(FooRefConst);
287   Mem->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, FooRefConstRef);
288 
289   Foo.addChild(std::move(Mem));
290 
291   uint64_t MD5Res = DIEHash().computeTypeSignature(Foo);
292 
293   ASSERT_EQ(0xad211c8c3b31e57ULL, MD5Res);
294 }
295 
296 // struct foo { foo foo::*mem; };
297 TEST_F(DIEHashTest, PtrToMember) {
298   DIE &Foo = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
299   DIEInteger Eight(8);
300   Foo.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
301   DIEString FooStr = getString("foo");
302   Foo.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
303 
304   auto Mem = DIE::get(Alloc, dwarf::DW_TAG_member);
305   DIEString MemStr = getString("mem");
306   Mem->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, MemStr);
307   DIEInteger Zero(0);
308   Mem->addValue(Alloc, dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1,
309                 Zero);
310 
311   DIE &PtrToFooMem = *DIE::get(Alloc, dwarf::DW_TAG_ptr_to_member_type);
312   DIEEntry FooEntry(Foo);
313   PtrToFooMem.addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, FooEntry);
314   PtrToFooMem.addValue(Alloc, dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4,
315                        FooEntry);
316 
317   DIEEntry PtrToFooMemRef(PtrToFooMem);
318   Mem->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, PtrToFooMemRef);
319 
320   Foo.addChild(std::move(Mem));
321 
322   uint64_t MD5Res = DIEHash().computeTypeSignature(Foo);
323 
324   ASSERT_EQ(0x852e0c9ff7c04ebULL, MD5Res);
325 }
326 
327 // Check that the hash for a pointer-to-member matches regardless of whether the
328 // pointed-to type is a declaration or a definition.
329 //
330 //   struct bar; // { };
331 //   struct foo { bar foo::*mem; };
332 TEST_F(DIEHashTest, PtrToMemberDeclDefMatch) {
333   DIEInteger Zero(0);
334   DIEInteger One(1);
335   DIEInteger Eight(8);
336   DIEString FooStr = getString("foo");
337   DIEString BarStr = getString("bar");
338   DIEString MemStr = getString("mem");
339   uint64_t MD5ResDecl;
340   {
341     DIE &Bar = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
342     Bar.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, BarStr);
343     Bar.addValue(Alloc, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag_present,
344                  One);
345 
346     DIE &Foo = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
347     Foo.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
348     Foo.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
349 
350     auto Mem = DIE::get(Alloc, dwarf::DW_TAG_member);
351     Mem->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, MemStr);
352     Mem->addValue(Alloc, dwarf::DW_AT_data_member_location,
353                   dwarf::DW_FORM_data1, Zero);
354 
355     DIE &PtrToFooMem = *DIE::get(Alloc, dwarf::DW_TAG_ptr_to_member_type);
356     DIEEntry BarEntry(Bar);
357     PtrToFooMem.addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4,
358                          BarEntry);
359     DIEEntry FooEntry(Foo);
360     PtrToFooMem.addValue(Alloc, dwarf::DW_AT_containing_type,
361                          dwarf::DW_FORM_ref4, FooEntry);
362 
363     DIEEntry PtrToFooMemRef(PtrToFooMem);
364     Mem->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4,
365                   PtrToFooMemRef);
366 
367     Foo.addChild(std::move(Mem));
368 
369     MD5ResDecl = DIEHash().computeTypeSignature(Foo);
370   }
371   uint64_t MD5ResDef;
372   {
373     DIE &Bar = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
374     Bar.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, BarStr);
375     Bar.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
376 
377     DIE &Foo = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
378     Foo.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
379     Foo.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
380 
381     auto Mem = DIE::get(Alloc, dwarf::DW_TAG_member);
382     Mem->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, MemStr);
383     Mem->addValue(Alloc, dwarf::DW_AT_data_member_location,
384                   dwarf::DW_FORM_data1, Zero);
385 
386     DIE &PtrToFooMem = *DIE::get(Alloc, dwarf::DW_TAG_ptr_to_member_type);
387     DIEEntry BarEntry(Bar);
388     PtrToFooMem.addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4,
389                          BarEntry);
390     DIEEntry FooEntry(Foo);
391     PtrToFooMem.addValue(Alloc, dwarf::DW_AT_containing_type,
392                          dwarf::DW_FORM_ref4, FooEntry);
393 
394     DIEEntry PtrToFooMemRef(PtrToFooMem);
395     Mem->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4,
396                   PtrToFooMemRef);
397 
398     Foo.addChild(std::move(Mem));
399 
400     MD5ResDef = DIEHash().computeTypeSignature(Foo);
401   }
402   ASSERT_EQ(MD5ResDef, MD5ResDecl);
403 }
404 
405 // Check that the hash for a pointer-to-member matches regardless of whether the
406 // pointed-to type is a declaration or a definition.
407 //
408 //   struct bar; // { };
409 //   struct foo { bar bar::*mem; };
410 TEST_F(DIEHashTest, PtrToMemberDeclDefMisMatch) {
411   DIEInteger Zero(0);
412   DIEInteger One(1);
413   DIEInteger Eight(8);
414   DIEString FooStr = getString("foo");
415   DIEString BarStr = getString("bar");
416   DIEString MemStr = getString("mem");
417   uint64_t MD5ResDecl;
418   {
419     DIE &Bar = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
420     Bar.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, BarStr);
421     Bar.addValue(Alloc, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag_present,
422                  One);
423 
424     DIE &Foo = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
425     Foo.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
426     Foo.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
427 
428     auto Mem = DIE::get(Alloc, dwarf::DW_TAG_member);
429     Mem->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, MemStr);
430     Mem->addValue(Alloc, dwarf::DW_AT_data_member_location,
431                   dwarf::DW_FORM_data1, Zero);
432 
433     DIE &PtrToFooMem = *DIE::get(Alloc, dwarf::DW_TAG_ptr_to_member_type);
434     DIEEntry BarEntry(Bar);
435     PtrToFooMem.addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4,
436                          BarEntry);
437     PtrToFooMem.addValue(Alloc, dwarf::DW_AT_containing_type,
438                          dwarf::DW_FORM_ref4, BarEntry);
439 
440     DIEEntry PtrToFooMemRef(PtrToFooMem);
441     Mem->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4,
442                   PtrToFooMemRef);
443 
444     Foo.addChild(std::move(Mem));
445 
446     MD5ResDecl = DIEHash().computeTypeSignature(Foo);
447   }
448   uint64_t MD5ResDef;
449   {
450     DIE &Bar = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
451     Bar.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, BarStr);
452     Bar.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
453 
454     DIE &Foo = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
455     Foo.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
456     Foo.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
457 
458     auto Mem = DIE::get(Alloc, dwarf::DW_TAG_member);
459     Mem->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, MemStr);
460     Mem->addValue(Alloc, dwarf::DW_AT_data_member_location,
461                   dwarf::DW_FORM_data1, Zero);
462 
463     DIE &PtrToFooMem = *DIE::get(Alloc, dwarf::DW_TAG_ptr_to_member_type);
464     DIEEntry BarEntry(Bar);
465     PtrToFooMem.addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4,
466                          BarEntry);
467     PtrToFooMem.addValue(Alloc, dwarf::DW_AT_containing_type,
468                          dwarf::DW_FORM_ref4, BarEntry);
469 
470     DIEEntry PtrToFooMemRef(PtrToFooMem);
471     Mem->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4,
472                   PtrToFooMemRef);
473 
474     Foo.addChild(std::move(Mem));
475 
476     MD5ResDef = DIEHash().computeTypeSignature(Foo);
477   }
478   // FIXME: This seems to be a bug in the DWARF type hashing specification that
479   // only uses the brief name hashing for types referenced via DW_AT_type. In
480   // this case the type is referenced via DW_AT_containing_type and full hashing
481   // causes a hash to differ when the containing type is a declaration in one TU
482   // and a definition in another.
483   ASSERT_NE(MD5ResDef, MD5ResDecl);
484 }
485 
486 // struct { } a;
487 // struct foo { decltype(a) mem; };
488 TEST_F(DIEHashTest, RefUnnamedType) {
489   DIEInteger Zero(0);
490   DIEInteger One(1);
491   DIEInteger Eight(8);
492   DIEString FooStr = getString("foo");
493   DIEString MemStr = getString("mem");
494 
495   DIE &Unnamed = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
496   Unnamed.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
497 
498   DIE &Foo = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
499   Foo.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Eight);
500   Foo.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
501 
502   auto Mem = DIE::get(Alloc, dwarf::DW_TAG_member);
503   Mem->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, MemStr);
504   Mem->addValue(Alloc, dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1,
505                 Zero);
506 
507   DIE &UnnamedPtr = *DIE::get(Alloc, dwarf::DW_TAG_pointer_type);
508   UnnamedPtr.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1,
509                       Eight);
510   DIEEntry UnnamedRef(Unnamed);
511   UnnamedPtr.addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4,
512                       UnnamedRef);
513 
514   DIEEntry UnnamedPtrRef(UnnamedPtr);
515   Mem->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, UnnamedPtrRef);
516 
517   Foo.addChild(std::move(Mem));
518 
519   uint64_t MD5Res = DIEHash().computeTypeSignature(Foo);
520 
521   ASSERT_EQ(0x954e026f01c02529ULL, MD5Res);
522 }
523 
524 // struct { struct foo { }; };
525 TEST_F(DIEHashTest, NestedType) {
526   DIE &Unnamed = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
527   DIEInteger One(1);
528   Unnamed.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
529 
530   auto Foo = DIE::get(Alloc, dwarf::DW_TAG_structure_type);
531   DIEString FooStr = getString("foo");
532   Foo->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FooStr);
533   Foo->addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
534 
535   Unnamed.addChild(std::move(Foo));
536 
537   uint64_t MD5Res = DIEHash().computeTypeSignature(Unnamed);
538 
539   // The exact same hash GCC produces for this DIE.
540   ASSERT_EQ(0xde8a3b7b43807f4aULL, MD5Res);
541 }
542 
543 // struct { static void func(); };
544 TEST_F(DIEHashTest, MemberFunc) {
545   DIE &Unnamed = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
546   DIEInteger One(1);
547   Unnamed.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
548 
549   auto Func = DIE::get(Alloc, dwarf::DW_TAG_subprogram);
550   DIEString FuncStr = getString("func");
551   Func->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FuncStr);
552 
553   Unnamed.addChild(std::move(Func));
554 
555   uint64_t MD5Res = DIEHash().computeTypeSignature(Unnamed);
556 
557   // The exact same hash GCC produces for this DIE.
558   ASSERT_EQ(0xd36a1b6dfb604ba0ULL, MD5Res);
559 }
560 
561 // struct A {
562 //   static void func();
563 // };
564 TEST_F(DIEHashTest, MemberFuncFlag) {
565   DIE &A = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
566   DIEInteger One(1);
567   DIEString AStr = getString("A");
568   A.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, AStr);
569   A.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
570   A.addValue(Alloc, dwarf::DW_AT_decl_file, dwarf::DW_FORM_data1, One);
571   A.addValue(Alloc, dwarf::DW_AT_decl_line, dwarf::DW_FORM_data1, One);
572 
573   auto Func = DIE::get(Alloc, dwarf::DW_TAG_subprogram);
574   DIEString FuncStr = getString("func");
575   DIEString FuncLinkage = getString("_ZN1A4funcEv");
576   DIEInteger Two(2);
577   Func->addValue(Alloc, dwarf::DW_AT_external, dwarf::DW_FORM_flag_present,
578                  One);
579   Func->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FuncStr);
580   Func->addValue(Alloc, dwarf::DW_AT_decl_file, dwarf::DW_FORM_data1, One);
581   Func->addValue(Alloc, dwarf::DW_AT_decl_line, dwarf::DW_FORM_data1, Two);
582   Func->addValue(Alloc, dwarf::DW_AT_linkage_name, dwarf::DW_FORM_strp,
583                  FuncLinkage);
584   Func->addValue(Alloc, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag_present,
585                  One);
586 
587   A.addChild(std::move(Func));
588 
589   uint64_t MD5Res = DIEHash().computeTypeSignature(A);
590 
591   // The exact same hash GCC produces for this DIE.
592   ASSERT_EQ(0x8f78211ddce3df10ULL, MD5Res);
593 }
594 
595 // Derived from:
596 // struct A {
597 //   const static int PI = -3;
598 // };
599 // A a;
600 TEST_F(DIEHashTest, MemberSdata) {
601   DIE &A = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
602   DIEInteger One(1);
603   DIEString AStr = getString("A");
604   A.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, AStr);
605   A.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
606   A.addValue(Alloc, dwarf::DW_AT_decl_file, dwarf::DW_FORM_data1, One);
607   A.addValue(Alloc, dwarf::DW_AT_decl_line, dwarf::DW_FORM_data1, One);
608 
609   DIEInteger Four(4);
610   DIEInteger Five(5);
611   DIEString FStr = getString("int");
612   DIE &IntTyDIE = *DIE::get(Alloc, dwarf::DW_TAG_base_type);
613   IntTyDIE.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, Four);
614   IntTyDIE.addValue(Alloc, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, Five);
615   IntTyDIE.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FStr);
616 
617   DIEEntry IntTy(IntTyDIE);
618   auto PITyDIE = DIE::get(Alloc, dwarf::DW_TAG_const_type);
619   PITyDIE->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, IntTy);
620 
621   DIEEntry PITy(*PITyDIE);
622   auto PI = DIE::get(Alloc, dwarf::DW_TAG_member);
623   DIEString PIStr = getString("PI");
624   DIEInteger Two(2);
625   DIEInteger NegThree(-3);
626   PI->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, PIStr);
627   PI->addValue(Alloc, dwarf::DW_AT_decl_file, dwarf::DW_FORM_data1, One);
628   PI->addValue(Alloc, dwarf::DW_AT_decl_line, dwarf::DW_FORM_data1, Two);
629   PI->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, PITy);
630   PI->addValue(Alloc, dwarf::DW_AT_external, dwarf::DW_FORM_flag_present, One);
631   PI->addValue(Alloc, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag_present,
632                One);
633   PI->addValue(Alloc, dwarf::DW_AT_const_value, dwarf::DW_FORM_sdata, NegThree);
634 
635   A.addChild(std::move(PI));
636 
637   uint64_t MD5Res = DIEHash().computeTypeSignature(A);
638   ASSERT_EQ(0x9a216000dd3788a7ULL, MD5Res);
639 }
640 
641 // Derived from:
642 // struct A {
643 //   const static float PI = 3.14;
644 // };
645 // A a;
646 TEST_F(DIEHashTest, MemberBlock) {
647   DIE &A = *DIE::get(Alloc, dwarf::DW_TAG_structure_type);
648   DIEInteger One(1);
649   DIEString AStr = getString("A");
650   A.addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, AStr);
651   A.addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, One);
652   A.addValue(Alloc, dwarf::DW_AT_decl_file, dwarf::DW_FORM_data1, One);
653   A.addValue(Alloc, dwarf::DW_AT_decl_line, dwarf::DW_FORM_data1, One);
654 
655   DIEInteger Four(4);
656   DIEString FStr = getString("float");
657   auto FloatTyDIE = DIE::get(Alloc, dwarf::DW_TAG_base_type);
658   FloatTyDIE->addValue(Alloc, dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1,
659                        Four);
660   FloatTyDIE->addValue(Alloc, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1,
661                        Four);
662   FloatTyDIE->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, FStr);
663   DIEEntry FloatTy(*FloatTyDIE);
664   auto PITyDIE = DIE::get(Alloc, dwarf::DW_TAG_const_type);
665   PITyDIE->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, FloatTy);
666 
667   DIEEntry PITy(*PITyDIE);
668   auto PI = DIE::get(Alloc, dwarf::DW_TAG_member);
669   DIEString PIStr = getString("PI");
670   DIEInteger Two(2);
671   PI->addValue(Alloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp, PIStr);
672   PI->addValue(Alloc, dwarf::DW_AT_decl_file, dwarf::DW_FORM_data1, One);
673   PI->addValue(Alloc, dwarf::DW_AT_decl_line, dwarf::DW_FORM_data1, Two);
674   PI->addValue(Alloc, dwarf::DW_AT_type, dwarf::DW_FORM_ref4, PITy);
675   PI->addValue(Alloc, dwarf::DW_AT_external, dwarf::DW_FORM_flag_present, One);
676   PI->addValue(Alloc, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag_present,
677                One);
678 
679   DIEBlock PIBlock;
680   DIEInteger Blk1(0xc3);
681   DIEInteger Blk2(0xf5);
682   DIEInteger Blk3(0x48);
683   DIEInteger Blk4(0x40);
684 
685   PIBlock.addValue(Alloc, (dwarf::Attribute)0, dwarf::DW_FORM_data1, Blk1);
686   PIBlock.addValue(Alloc, (dwarf::Attribute)0, dwarf::DW_FORM_data1, Blk2);
687   PIBlock.addValue(Alloc, (dwarf::Attribute)0, dwarf::DW_FORM_data1, Blk3);
688   PIBlock.addValue(Alloc, (dwarf::Attribute)0, dwarf::DW_FORM_data1, Blk4);
689 
690   PI->addValue(Alloc, dwarf::DW_AT_const_value, dwarf::DW_FORM_block1,
691                &PIBlock);
692 
693   A.addChild(std::move(PI));
694 
695   uint64_t MD5Res = DIEHash().computeTypeSignature(A);
696   ASSERT_EQ(0x493af53ad3d3f651ULL, MD5Res);
697 }
698 }
699