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