1//===-- DWARFDIETest.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 "Plugins/SymbolFile/DWARF/DWARFDIE.h"
10#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
11#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
12#include "TestingSupport/Symbol/YAMLModuleTester.h"
13#include "lldb/Core/dwarf.h"
14#include "lldb/Symbol/Type.h"
15#include "lldb/lldb-private-enumerations.h"
16#include "llvm/ADT/STLExtras.h"
17#include "gmock/gmock.h"
18#include "gtest/gtest.h"
19
20using namespace lldb;
21using namespace lldb_private;
22using namespace lldb_private::plugin::dwarf;
23using namespace lldb_private::dwarf;
24
25TEST(DWARFDIETest, ChildIteration) {
26 // Tests DWARFDIE::child_iterator.
27
28 const char *yamldata = R"(
29--- !ELF
30FileHeader:
31 Class: ELFCLASS64
32 Data: ELFDATA2LSB
33 Type: ET_EXEC
34 Machine: EM_386
35DWARF:
36 debug_abbrev:
37 - Table:
38 - Code: 0x00000001
39 Tag: DW_TAG_compile_unit
40 Children: DW_CHILDREN_yes
41 Attributes:
42 - Attribute: DW_AT_language
43 Form: DW_FORM_data2
44 - Code: 0x00000002
45 Tag: DW_TAG_base_type
46 Children: DW_CHILDREN_no
47 Attributes:
48 - Attribute: DW_AT_encoding
49 Form: DW_FORM_data1
50 - Attribute: DW_AT_byte_size
51 Form: DW_FORM_data1
52 debug_info:
53 - Version: 4
54 AddrSize: 8
55 Entries:
56 - AbbrCode: 0x00000001
57 Values:
58 - Value: 0x000000000000000C
59 - AbbrCode: 0x00000002
60 Values:
61 - Value: 0x0000000000000007 # DW_ATE_unsigned
62 - Value: 0x0000000000000004
63 - AbbrCode: 0x00000002
64 Values:
65 - Value: 0x0000000000000007 # DW_ATE_unsigned
66 - Value: 0x0000000000000008
67 - AbbrCode: 0x00000002
68 Values:
69 - Value: 0x0000000000000005 # DW_ATE_signed
70 - Value: 0x0000000000000008
71 - AbbrCode: 0x00000000
72)";
73
74 YAMLModuleTester t(yamldata);
75 ASSERT_TRUE((bool)t.GetDwarfUnit());
76
77 DWARFUnit *unit = t.GetDwarfUnit();
78 const DWARFDebugInfoEntry *die_first = unit->DIE().GetDIE();
79
80 // Create a DWARFDIE that has three DW_TAG_base_type children.
81 DWARFDIE top_die(unit, die_first);
82
83 // Create the iterator range that has the three tags as elements.
84 llvm::iterator_range<DWARFDIE::child_iterator> children = top_die.children();
85
86 // Compare begin() to the first child DIE.
87 DWARFDIE::child_iterator child_iter = children.begin();
88 ASSERT_NE(child_iter, children.end());
89 const DWARFDebugInfoEntry *die_child0 = die_first->GetFirstChild();
90 EXPECT_EQ((*child_iter).GetDIE(), die_child0);
91
92 // Step to the second child DIE.
93 ++child_iter;
94 ASSERT_NE(child_iter, children.end());
95 const DWARFDebugInfoEntry *die_child1 = die_child0->GetSibling();
96 EXPECT_EQ((*child_iter).GetDIE(), die_child1);
97
98 // Step to the third child DIE.
99 ++child_iter;
100 ASSERT_NE(child_iter, children.end());
101 const DWARFDebugInfoEntry *die_child2 = die_child1->GetSibling();
102 EXPECT_EQ((*child_iter).GetDIE(), die_child2);
103
104 // Step to the end of the range.
105 ++child_iter;
106 EXPECT_EQ(child_iter, children.end());
107
108 // Take one of the DW_TAG_base_type DIEs (which has no children) and make
109 // sure the children range is now empty.
110 DWARFDIE no_children_die(unit, die_child0);
111 EXPECT_TRUE(no_children_die.children().empty());
112}
113
114TEST(DWARFDIETest, PeekName) {
115 const char *yamldata = R"(
116--- !ELF
117FileHeader:
118 Class: ELFCLASS64
119 Data: ELFDATA2LSB
120 Type: ET_EXEC
121 Machine: EM_386
122DWARF:
123 debug_str:
124 - 'NameType1'
125 - 'NameType2'
126 debug_abbrev:
127 - Table:
128 - Code: 0x00000001
129 Tag: DW_TAG_compile_unit
130 Children: DW_CHILDREN_yes
131 Attributes:
132 - Attribute: DW_AT_language
133 Form: DW_FORM_data2
134 - Code: 0x00000002
135 Tag: DW_TAG_base_type
136 Children: DW_CHILDREN_no
137 Attributes:
138 - Attribute: DW_AT_name
139 Form: DW_FORM_strp
140 - Code: 0x00000003
141 Tag: DW_TAG_base_type
142 Children: DW_CHILDREN_no
143 Attributes:
144 - Attribute: DW_AT_abstract_origin
145 Form: DW_FORM_ref1
146 - Code: 0x00000004
147 Tag: DW_TAG_base_type
148 Children: DW_CHILDREN_no
149 Attributes:
150 - Attribute: DW_AT_specification
151 Form: DW_FORM_ref1
152 debug_info:
153 - Version: 4
154 AddrSize: 8
155 Entries:
156 - AbbrCode: 0x00000001
157 Values:
158 - Value: 0x000000000000000C
159 - AbbrCode: 0x00000002
160 Values:
161 - Value: 0x0000000000000000 # Name = NameType1
162 - AbbrCode: 0x00000002
163 Values:
164 - Value: 0x000000000000000a # Name = NameType2
165 - AbbrCode: 0x00000003
166 Values:
167 - Value: 0x000000000000000e # Ref abstract origin to NameType1 DIE.
168 - AbbrCode: 0x00000004
169 Values:
170 - Value: 0x0000000000000013 # Ref specification to NameType2 DIE.
171 - AbbrCode: 0x00000000
172)";
173
174 YAMLModuleTester t(yamldata);
175 auto *symbol_file =
176 llvm::cast<SymbolFileDWARF>(Val: t.GetModule()->GetSymbolFile());
177 DWARFUnit *unit = symbol_file->DebugInfo().GetUnitAtIndex(idx: 0);
178
179 dw_offset_t first_die_offset = 11;
180 EXPECT_EQ(unit->PeekDIEName(first_die_offset), "");
181
182 dw_offset_t second_die_offset = 14;
183 EXPECT_EQ(unit->PeekDIEName(second_die_offset), "NameType1");
184
185 dw_offset_t third_die_offset = 19;
186 EXPECT_EQ(unit->PeekDIEName(third_die_offset), "NameType2");
187
188 dw_offset_t fourth_die_offset = 24;
189 EXPECT_EQ(unit->PeekDIEName(fourth_die_offset), "NameType1");
190
191 dw_offset_t fifth_die_offset = 26;
192 EXPECT_EQ(unit->PeekDIEName(fifth_die_offset), "NameType2");
193}
194
195TEST(DWARFDIETest, GetContext) {
196 const char *yamldata = R"(
197--- !ELF
198FileHeader:
199 Class: ELFCLASS64
200 Data: ELFDATA2LSB
201 Type: ET_EXEC
202 Machine: EM_386
203DWARF:
204 debug_abbrev:
205 - ID: 0
206 Table:
207 - Code: 0x1
208 Tag: DW_TAG_compile_unit
209 Children: DW_CHILDREN_yes
210 Attributes:
211 - Attribute: DW_AT_language
212 Form: DW_FORM_data2
213 - Code: 0x2
214 Tag: DW_TAG_namespace
215 Children: DW_CHILDREN_yes
216 Attributes:
217 - Attribute: DW_AT_name
218 Form: DW_FORM_string
219 - Code: 0x3
220 Tag: DW_TAG_structure_type
221 Children: DW_CHILDREN_no
222 Attributes:
223 - Attribute: DW_AT_name
224 Form: DW_FORM_string
225 - Code: 0x4
226 Tag: DW_TAG_namespace
227 Children: DW_CHILDREN_yes
228 debug_info:
229 - Version: 4
230 AddrSize: 8
231 Entries:
232 - AbbrCode: 0x1
233 Values:
234 - Value: 0x000000000000000C
235 - AbbrCode: 0x2
236 Values:
237 - CStr: NAMESPACE
238 - AbbrCode: 0x3
239 Values:
240 - CStr: STRUCT
241 - AbbrCode: 0x4
242 - AbbrCode: 0x3
243 Values:
244 - CStr: STRUCT
245 - AbbrCode: 0x0
246 - AbbrCode: 0x0
247 - AbbrCode: 0x0
248)";
249
250 YAMLModuleTester t(yamldata);
251 auto *symbol_file =
252 llvm::cast<SymbolFileDWARF>(Val: t.GetModule()->GetSymbolFile());
253 DWARFUnit *unit = symbol_file->DebugInfo().GetUnitAtIndex(idx: 0);
254 ASSERT_TRUE(unit);
255
256 auto make_namespace = [](const char *name) {
257 return CompilerContext(CompilerContextKind::Namespace, ConstString(name));
258 };
259 auto make_struct = [](const char *name) {
260 return CompilerContext(CompilerContextKind::ClassOrStruct,
261 ConstString(name));
262 };
263 DWARFDIE struct_die = unit->DIE().GetFirstChild().GetFirstChild();
264 ASSERT_TRUE(struct_die);
265 DWARFDIE anon_struct_die = struct_die.GetSibling().GetFirstChild();
266 ASSERT_TRUE(anon_struct_die);
267 EXPECT_THAT(
268 struct_die.GetDeclContext(),
269 testing::ElementsAre(make_namespace("NAMESPACE"), make_struct("STRUCT")));
270 EXPECT_THAT(
271 struct_die.GetTypeLookupContext(),
272 testing::ElementsAre(make_namespace("NAMESPACE"), make_struct("STRUCT")));
273 EXPECT_THAT(struct_die.GetDWARFDeclContext(),
274 DWARFDeclContext({{DW_TAG_structure_type, "STRUCT"},
275 {DW_TAG_namespace, "NAMESPACE"}}));
276 EXPECT_THAT(anon_struct_die.GetDeclContext(),
277 testing::ElementsAre(make_namespace("NAMESPACE"),
278 make_namespace(nullptr),
279 make_struct("STRUCT")));
280 EXPECT_THAT(anon_struct_die.GetTypeLookupContext(),
281 testing::ElementsAre(make_namespace("NAMESPACE"),
282 make_namespace(nullptr),
283 make_struct("STRUCT")));
284 EXPECT_THAT(anon_struct_die.GetDWARFDeclContext(),
285 DWARFDeclContext({{DW_TAG_structure_type, "STRUCT"},
286 {DW_TAG_namespace, nullptr},
287 {DW_TAG_namespace, "NAMESPACE"}}));
288}
289
290TEST(DWARFDIETest, GetContextInFunction) {
291 // Make sure we get the right context fo each "struct_t" type. The first
292 // should be "a::struct_t" and the one defined in the "foo" function should be
293 // "struct_t". Previous DWARFDIE::GetTypeLookupContext() function calls would
294 // have the "struct_t" in "foo" be "a::struct_t" because it would traverse the
295 // entire die parent tree and ignore DW_TAG_subprogram and keep traversing the
296 // parents.
297 //
298 // 0x0000000b: DW_TAG_compile_unit
299 // 0x0000000c: DW_TAG_namespace
300 // DW_AT_name("a")
301 // 0x0000000f: DW_TAG_structure_type
302 // DW_AT_name("struct_t")
303 // 0x00000019: DW_TAG_subprogram
304 // DW_AT_name("foo")
305 // 0x0000001e: DW_TAG_structure_type
306 // DW_AT_name("struct_t")
307 // 0x00000028: NULL
308 // 0x00000029: NULL
309 // 0x0000002a: NULL
310 const char *yamldata = R"(
311--- !ELF
312FileHeader:
313 Class: ELFCLASS64
314 Data: ELFDATA2LSB
315 Type: ET_EXEC
316 Machine: EM_386
317DWARF:
318 debug_str:
319 - ''
320 debug_abbrev:
321 - ID: 0
322 Table:
323 - Code: 0x1
324 Tag: DW_TAG_compile_unit
325 Children: DW_CHILDREN_yes
326 - Code: 0x2
327 Tag: DW_TAG_namespace
328 Children: DW_CHILDREN_yes
329 Attributes:
330 - Attribute: DW_AT_name
331 Form: DW_FORM_string
332 - Code: 0x3
333 Tag: DW_TAG_structure_type
334 Children: DW_CHILDREN_no
335 Attributes:
336 - Attribute: DW_AT_name
337 Form: DW_FORM_string
338 - Code: 0x4
339 Tag: DW_TAG_subprogram
340 Children: DW_CHILDREN_yes
341 Attributes:
342 - Attribute: DW_AT_name
343 Form: DW_FORM_string
344 debug_info:
345 - Length: 0x27
346 Version: 4
347 AbbrevTableID: 0
348 AbbrOffset: 0x0
349 AddrSize: 8
350 Entries:
351 - AbbrCode: 0x1
352 - AbbrCode: 0x2
353 Values:
354 - Value: 0xDEADBEEFDEADBEEF
355 CStr: a
356 - AbbrCode: 0x3
357 Values:
358 - Value: 0xDEADBEEFDEADBEEF
359 CStr: struct_t
360 - AbbrCode: 0x4
361 Values:
362 - Value: 0xDEADBEEFDEADBEEF
363 CStr: foo
364 - AbbrCode: 0x3
365 Values:
366 - Value: 0xDEADBEEFDEADBEEF
367 CStr: struct_t
368 - AbbrCode: 0x0
369 - AbbrCode: 0x0
370 - AbbrCode: 0x0)";
371
372 YAMLModuleTester t(yamldata);
373 auto *symbol_file =
374 llvm::cast<SymbolFileDWARF>(Val: t.GetModule()->GetSymbolFile());
375 DWARFUnit *unit = symbol_file->DebugInfo().GetUnitAtIndex(idx: 0);
376 ASSERT_TRUE(unit);
377
378 auto make_namespace = [](llvm::StringRef name) {
379 return CompilerContext(CompilerContextKind::Namespace, ConstString(name));
380 };
381 auto make_struct = [](llvm::StringRef name) {
382 return CompilerContext(CompilerContextKind::ClassOrStruct,
383 ConstString(name));
384 };
385 // Grab the "a::struct_t" type from the "a" namespace
386 DWARFDIE a_struct_die = unit->DIE().GetFirstChild().GetFirstChild();
387 ASSERT_TRUE(a_struct_die);
388 EXPECT_THAT(
389 a_struct_die.GetDeclContext(),
390 testing::ElementsAre(make_namespace("a"), make_struct("struct_t")));
391 // Grab the "struct_t" defined in the "foo" function.
392 DWARFDIE foo_struct_die =
393 unit->DIE().GetFirstChild().GetFirstChild().GetSibling().GetFirstChild();
394 EXPECT_THAT(foo_struct_die.GetTypeLookupContext(),
395 testing::ElementsAre(make_struct("struct_t")));
396}
397
398TEST(DWARFDIETest, GetAttributeValue_ImplicitConst) {
399 // Make sure we can correctly retrieve the value of an attribute
400 // that has a DW_FORM_implicit_const form.
401
402 const char *yamldata = R"(
403--- !ELF
404FileHeader:
405 Class: ELFCLASS64
406 Data: ELFDATA2LSB
407 Type: ET_EXEC
408 Machine: EM_386
409DWARF:
410 debug_str:
411 - ''
412 debug_abbrev:
413 - ID: 0
414 Table:
415 - Code: 0x1
416 Tag: DW_TAG_compile_unit
417 Children: DW_CHILDREN_yes
418 - Code: 0x2
419 Tag: DW_TAG_subprogram
420 Children: DW_CHILDREN_no
421 Attributes:
422 - Attribute: DW_AT_name
423 Form: DW_FORM_string
424 - Attribute: DW_AT_object_pointer
425 Form: DW_FORM_implicit_const
426 Value: 5
427 debug_info:
428 - Version: 5
429 UnitType: DW_UT_compile
430 AddrSize: 8
431 Entries:
432 - AbbrCode: 0x1
433 - AbbrCode: 0x2
434 Values:
435 - Value: 0xDEADBEEFDEADBEEF
436 CStr: func
437 - AbbrCode: 0x0)";
438
439 YAMLModuleTester t(yamldata);
440 auto *symbol_file =
441 llvm::cast<SymbolFileDWARF>(Val: t.GetModule()->GetSymbolFile());
442 DWARFUnit *unit = symbol_file->DebugInfo().GetUnitAtIndex(idx: 0);
443 ASSERT_TRUE(unit);
444
445 DWARFDIE subprogram = unit->DIE().GetFirstChild();
446 ASSERT_TRUE(subprogram);
447 dw_offset_t end_attr_offset;
448 DWARFFormValue form_value;
449 dw_offset_t offset = subprogram.GetDIE()->GetAttributeValue(
450 cu: unit, attr: DW_AT_object_pointer, formValue&: form_value, end_attr_offset_ptr: &end_attr_offset);
451 EXPECT_EQ(form_value.Unsigned(), 5U);
452 EXPECT_GT(offset, 0U);
453 EXPECT_GT(end_attr_offset, 0U);
454}
455
456struct GetAttributesTestFixture : public testing::TestWithParam<dw_attr_t> {};
457
458TEST_P(GetAttributesTestFixture, TestGetAttributes_IterationOrder) {
459 // Tests that we accumulate all current DIE's attributes first
460 // before checking the attributes of the specification.
461
462 const char *yamldata = R"(
463--- !ELF
464FileHeader:
465 Class: ELFCLASS64
466 Data: ELFDATA2LSB
467 Type: ET_EXEC
468 Machine: EM_AARCH64
469DWARF:
470 debug_str:
471 - func
472 debug_abbrev:
473 - ID: 0
474 Table:
475 - Code: 0x1
476 Tag: DW_TAG_compile_unit
477 Children: DW_CHILDREN_yes
478 Attributes:
479 - Attribute: DW_AT_language
480 Form: DW_FORM_data2
481 - Code: 0x2
482 Tag: DW_TAG_subprogram
483 Children: DW_CHILDREN_no
484 Attributes:
485 - Attribute: DW_AT_high_pc
486 Form: DW_FORM_data4
487 - Attribute: DW_AT_name
488 Form: DW_FORM_strp
489 - Attribute: DW_AT_declaration
490 Form: DW_FORM_flag_present
491 - Attribute: DW_AT_external
492 Form: DW_FORM_flag_present
493 - Attribute: DW_AT_low_pc
494 Form: DW_FORM_data4
495 - Code: 0x3
496 Tag: DW_TAG_subprogram
497 Children: DW_CHILDREN_no
498 Attributes:
499 - Attribute: DW_AT_high_pc
500 Form: DW_FORM_data4
501 - Attribute: {0}
502 Form: DW_FORM_ref4
503 - Attribute: DW_AT_low_pc
504 Form: DW_FORM_data4
505 debug_info:
506 - Version: 5
507 UnitType: DW_UT_compile
508 AddrSize: 8
509 Entries:
510
511# DW_TAG_compile_unit
512# DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
513
514 - AbbrCode: 0x1
515 Values:
516 - Value: 0x04
517
518# DW_TAG_subprogram
519# DW_AT_high_pc [DW_FORM_data4]
520# DW_AT_name [DW_FORM_strp] ("func")
521# DW_AT_low_pc [DW_FORM_data4]
522 - AbbrCode: 0x2
523 Values:
524 - Value: 0xdeadbeef
525 - Value: 0x0
526 - Value: 0x1
527 - Value: 0x1
528 - Value: 0xdeadbeef
529
530# DW_TAG_subprogram
531# DW_AT_high_pc [DW_FORM_data4]
532# DW_AT_specification [DW_FORM_ref4] ("func")
533# DW_AT_low_pc [DW_FORM_data4]
534 - AbbrCode: 0x3
535 Values:
536 - Value: 0xf00dcafe
537 - Value: 0xf
538 - Value: 0xf00dcafe
539
540 - AbbrCode: 0x0
541...
542)";
543 YAMLModuleTester t(llvm::formatv(Fmt: yamldata, Vals: GetParam()).str());
544
545 DWARFUnit *unit = t.GetDwarfUnit();
546 ASSERT_NE(unit, nullptr);
547 const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
548 ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
549 ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus);
550 DWARFDIE cu_die(unit, cu_entry);
551
552 auto declaration = cu_die.GetFirstChild();
553 ASSERT_TRUE(declaration.IsValid());
554 ASSERT_EQ(declaration.Tag(), DW_TAG_subprogram);
555
556 auto definition = declaration.GetSibling();
557 ASSERT_TRUE(definition.IsValid());
558 ASSERT_EQ(definition.Tag(), DW_TAG_subprogram);
559 ASSERT_FALSE(definition.GetAttributeValueAsOptionalUnsigned(DW_AT_external));
560
561 auto attrs = definition.GetAttributes(recurse: DWARFDebugInfoEntry::Recurse::yes);
562 EXPECT_EQ(attrs.Size(), 7U);
563
564 // Check that the attributes on the definition (that are also present
565 // on the declaration) take precedence.
566 for (auto attr : {DW_AT_low_pc, DW_AT_high_pc}) {
567 auto idx = attrs.FindAttributeIndex(attr);
568 EXPECT_NE(idx, UINT32_MAX);
569
570 DWARFFormValue form_value;
571 auto success = attrs.ExtractFormValueAtIndex(i: idx, form_value);
572 EXPECT_TRUE(success);
573
574 EXPECT_EQ(form_value.Unsigned(), 0xf00dcafe);
575 }
576}
577
578TEST_P(GetAttributesTestFixture, TestGetAttributes_Cycle) {
579 // Tests that GetAttributes can deal with cycles in
580 // specifications/abstract origins.
581 //
582 // Contrived example:
583 //
584 // func1 -> func3
585 // ^ |
586 // | v
587 // +------func2
588
589 const char *yamldata = R"(
590--- !ELF
591FileHeader:
592 Class: ELFCLASS64
593 Data: ELFDATA2LSB
594 Type: ET_EXEC
595 Machine: EM_AARCH64
596DWARF:
597 debug_abbrev:
598 - ID: 0
599 Table:
600 - Code: 0x1
601 Tag: DW_TAG_compile_unit
602 Children: DW_CHILDREN_yes
603 Attributes:
604 - Attribute: DW_AT_language
605 Form: DW_FORM_data2
606 - Code: 0x2
607 Tag: DW_TAG_subprogram
608 Children: DW_CHILDREN_no
609 Attributes:
610 - Attribute: {0}
611 Form: DW_FORM_ref4
612 debug_info:
613 - Version: 5
614 UnitType: DW_UT_compile
615 AddrSize: 8
616 Entries:
617
618 - AbbrCode: 0x1
619 Values:
620 - Value: 0x04
621
622 - AbbrCode: 0x2
623 Values:
624 - Value: 0x19
625
626 - AbbrCode: 0x2
627 Values:
628 - Value: 0xf
629
630 - AbbrCode: 0x2
631 Values:
632 - Value: 0x14
633
634 - AbbrCode: 0x0
635...
636)";
637 YAMLModuleTester t(llvm::formatv(Fmt: yamldata, Vals: GetParam()).str());
638
639 DWARFUnit *unit = t.GetDwarfUnit();
640 ASSERT_NE(unit, nullptr);
641 const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
642 ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
643 ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus);
644 DWARFDIE cu_die(unit, cu_entry);
645
646 auto func1 = cu_die.GetFirstChild();
647 ASSERT_TRUE(func1.IsValid());
648 ASSERT_EQ(func1.Tag(), DW_TAG_subprogram);
649
650 auto func2 = func1.GetSibling();
651 ASSERT_TRUE(func2.IsValid());
652 ASSERT_EQ(func2.Tag(), DW_TAG_subprogram);
653
654 auto func3 = func2.GetSibling();
655 ASSERT_TRUE(func3.IsValid());
656 ASSERT_EQ(func3.Tag(), DW_TAG_subprogram);
657
658 auto attrs = func1.GetAttributes(recurse: DWARFDebugInfoEntry::Recurse::yes);
659 EXPECT_EQ(attrs.Size(), 3U);
660
661 // Confirm that the specifications do form a cycle.
662 {
663 DWARFFormValue form_value;
664 auto success = attrs.ExtractFormValueAtIndex(i: 0, form_value);
665 ASSERT_TRUE(success);
666
667 EXPECT_EQ(form_value.Reference(), func3);
668 }
669
670 {
671 DWARFFormValue form_value;
672 auto success = attrs.ExtractFormValueAtIndex(i: 1, form_value);
673 ASSERT_TRUE(success);
674
675 EXPECT_EQ(form_value.Reference(), func2);
676 }
677
678 {
679 DWARFFormValue form_value;
680 auto success = attrs.ExtractFormValueAtIndex(i: 2, form_value);
681 ASSERT_TRUE(success);
682
683 EXPECT_EQ(form_value.Reference(), func1);
684 }
685}
686
687TEST_P(GetAttributesTestFixture,
688 TestGetAttributes_SkipNonApplicableAttributes) {
689 // Tests that GetAttributes will omit attributes found through
690 // specifications/abstract origins which are not applicable.
691
692 const char *yamldata = R"(
693--- !ELF
694FileHeader:
695 Class: ELFCLASS64
696 Data: ELFDATA2LSB
697 Type: ET_EXEC
698 Machine: EM_AARCH64
699DWARF:
700 debug_str:
701 - func
702 debug_abbrev:
703 - ID: 0
704 Table:
705 - Code: 0x1
706 Tag: DW_TAG_compile_unit
707 Children: DW_CHILDREN_yes
708 Attributes:
709 - Attribute: DW_AT_language
710 Form: DW_FORM_data2
711 - Code: 0x2
712 Tag: DW_TAG_subprogram
713 Children: DW_CHILDREN_no
714 Attributes:
715 - Attribute: DW_AT_declaration
716 Form: DW_FORM_flag_present
717 - Attribute: DW_AT_name
718 Form: DW_FORM_strp
719 - Attribute: DW_AT_sibling
720 Form: DW_FORM_ref4
721 - Code: 0x3
722 Tag: DW_TAG_subprogram
723 Children: DW_CHILDREN_no
724 Attributes:
725 - Attribute: DW_AT_declaration
726 Form: DW_FORM_flag_present
727 - Attribute: {0}
728 Form: DW_FORM_ref4
729 - Attribute: DW_AT_sibling
730 Form: DW_FORM_ref4
731 debug_info:
732 - Version: 5
733 UnitType: DW_UT_compile
734 AddrSize: 8
735 Entries:
736
737# DW_TAG_compile_unit
738# DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
739
740 - AbbrCode: 0x1
741 Values:
742 - Value: 0x04
743
744# DW_TAG_subprogram
745# DW_AT_declaration
746# DW_AT_name [DW_FORM_strp] ("func")
747# DW_AT_sibling
748 - AbbrCode: 0x2
749 Values:
750 - Value: 0x1
751 - Value: 0x0
752 - Value: 0x18
753
754# DW_TAG_subprogram
755# DW_AT_declaration
756# DW_AT_specification [DW_FORM_ref4] ("func")
757# DW_AT_sibling
758 - AbbrCode: 0x3
759 Values:
760 - Value: 0x1
761 - Value: 0xf
762 - Value: 0xdeadbeef
763
764 - AbbrCode: 0x0
765...
766)";
767 YAMLModuleTester t(llvm::formatv(Fmt: yamldata, Vals: GetParam()).str());
768
769 DWARFUnit *unit = t.GetDwarfUnit();
770 ASSERT_NE(unit, nullptr);
771 const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
772 ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
773 ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus);
774 DWARFDIE cu_die(unit, cu_entry);
775
776 auto declaration = cu_die.GetFirstChild();
777 ASSERT_TRUE(declaration.IsValid());
778 ASSERT_EQ(declaration.Tag(), DW_TAG_subprogram);
779
780 auto definition = declaration.GetSibling();
781 ASSERT_TRUE(definition.IsValid());
782 ASSERT_EQ(definition.Tag(), DW_TAG_subprogram);
783
784 auto attrs = definition.GetAttributes(recurse: DWARFDebugInfoEntry::Recurse::yes);
785 EXPECT_EQ(attrs.Size(), 4U);
786 EXPECT_NE(attrs.FindAttributeIndex(DW_AT_name), UINT32_MAX);
787 EXPECT_NE(attrs.FindAttributeIndex(GetParam()), UINT32_MAX);
788
789 auto sibling_idx = attrs.FindAttributeIndex(attr: DW_AT_sibling);
790 EXPECT_NE(sibling_idx, UINT32_MAX);
791
792 DWARFFormValue form_value;
793 auto success = attrs.ExtractFormValueAtIndex(i: sibling_idx, form_value);
794 ASSERT_TRUE(success);
795
796 EXPECT_EQ(form_value.Unsigned(), 0xdeadbeef);
797}
798
799TEST_P(GetAttributesTestFixture, TestGetAttributes_NoRecurse) {
800 // Tests that GetAttributes will not recurse if Recurse::No is passed to it.
801
802 const char *yamldata = R"(
803--- !ELF
804FileHeader:
805 Class: ELFCLASS64
806 Data: ELFDATA2LSB
807 Type: ET_EXEC
808 Machine: EM_AARCH64
809DWARF:
810 debug_str:
811 - func
812 debug_abbrev:
813 - ID: 0
814 Table:
815 - Code: 0x1
816 Tag: DW_TAG_compile_unit
817 Children: DW_CHILDREN_yes
818 Attributes:
819 - Attribute: DW_AT_language
820 Form: DW_FORM_data2
821 - Code: 0x2
822 Tag: DW_TAG_subprogram
823 Children: DW_CHILDREN_no
824 Attributes:
825 - Attribute: DW_AT_name
826 Form: DW_FORM_strp
827 - Code: 0x3
828 Tag: DW_TAG_subprogram
829 Children: DW_CHILDREN_no
830 Attributes:
831 - Attribute: DW_AT_low_pc
832 Form: DW_FORM_data4
833 - Attribute: {0}
834 Form: DW_FORM_ref4
835 debug_info:
836 - Version: 5
837 UnitType: DW_UT_compile
838 AddrSize: 8
839 Entries:
840
841# DW_TAG_compile_unit
842# DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
843
844 - AbbrCode: 0x1
845 Values:
846 - Value: 0x04
847
848# DW_TAG_subprogram
849# DW_AT_name [DW_FORM_strp] ("func")
850 - AbbrCode: 0x2
851 Values:
852 - Value: 0x0
853
854# DW_TAG_subprogram
855# DW_AT_low_pc [DW_FORM_data4]
856# DW_AT_specification [DW_FORM_ref4]
857 - AbbrCode: 0x3
858 Values:
859 - Value: 0xdeadbeef
860 - Value: 0xf
861
862 - AbbrCode: 0x0
863...
864)";
865 YAMLModuleTester t(llvm::formatv(Fmt: yamldata, Vals: GetParam()).str());
866
867 DWARFUnit *unit = t.GetDwarfUnit();
868 ASSERT_NE(unit, nullptr);
869 const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
870 ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
871 ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus);
872 DWARFDIE cu_die(unit, cu_entry);
873
874 auto declaration = cu_die.GetFirstChild();
875 ASSERT_TRUE(declaration.IsValid());
876 ASSERT_EQ(declaration.Tag(), DW_TAG_subprogram);
877
878 auto definition = declaration.GetSibling();
879 ASSERT_TRUE(definition.IsValid());
880 ASSERT_EQ(definition.Tag(), DW_TAG_subprogram);
881
882 auto attrs = definition.GetAttributes(recurse: DWARFDebugInfoEntry::Recurse::no);
883 EXPECT_EQ(attrs.Size(), 2U);
884 EXPECT_EQ(attrs.FindAttributeIndex(DW_AT_name), UINT32_MAX);
885 EXPECT_NE(attrs.FindAttributeIndex(GetParam()), UINT32_MAX);
886 EXPECT_NE(attrs.FindAttributeIndex(DW_AT_low_pc), UINT32_MAX);
887}
888
889TEST_P(GetAttributesTestFixture, TestGetAttributes_InvalidSpec) {
890 // Test that GetAttributes doesn't try following invalid
891 // specifications (but still add it to the list of attributes).
892
893 const char *yamldata = R"(
894--- !ELF
895FileHeader:
896 Class: ELFCLASS64
897 Data: ELFDATA2LSB
898 Type: ET_EXEC
899 Machine: EM_AARCH64
900DWARF:
901 debug_str:
902 - func
903 debug_abbrev:
904 - ID: 0
905 Table:
906 - Code: 0x1
907 Tag: DW_TAG_compile_unit
908 Children: DW_CHILDREN_yes
909 Attributes:
910 - Attribute: DW_AT_language
911 Form: DW_FORM_data2
912 - Code: 0x2
913 Tag: DW_TAG_subprogram
914 Children: DW_CHILDREN_no
915 Attributes:
916 - Attribute: DW_AT_name
917 Form: DW_FORM_strp
918 - Code: 0x3
919 Tag: DW_TAG_subprogram
920 Children: DW_CHILDREN_no
921 Attributes:
922 - Attribute: {0}
923 Form: DW_FORM_ref4
924 debug_info:
925 - Version: 5
926 UnitType: DW_UT_compile
927 AddrSize: 8
928 Entries:
929
930# DW_TAG_compile_unit
931# DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
932
933 - AbbrCode: 0x1
934 Values:
935 - Value: 0x04
936
937# DW_TAG_subprogram
938# DW_AT_name [DW_FORM_strp] ("func")
939 - AbbrCode: 0x2
940 Values:
941 - Value: 0x0
942
943# DW_TAG_subprogram
944# DW_AT_specification [DW_FORM_ref4]
945 - AbbrCode: 0x3
946 Values:
947 - Value: 0xdeadbeef
948
949 - AbbrCode: 0x0
950...
951)";
952 YAMLModuleTester t(llvm::formatv(Fmt: yamldata, Vals: GetParam()).str());
953
954 DWARFUnit *unit = t.GetDwarfUnit();
955 ASSERT_NE(unit, nullptr);
956 const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
957 ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
958 ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus);
959 DWARFDIE cu_die(unit, cu_entry);
960
961 auto declaration = cu_die.GetFirstChild();
962 ASSERT_TRUE(declaration.IsValid());
963 ASSERT_EQ(declaration.Tag(), DW_TAG_subprogram);
964
965 auto definition = declaration.GetSibling();
966 ASSERT_TRUE(definition.IsValid());
967 ASSERT_EQ(definition.Tag(), DW_TAG_subprogram);
968
969 auto attrs = definition.GetAttributes(recurse: DWARFDebugInfoEntry::Recurse::yes);
970 EXPECT_EQ(attrs.Size(), 1U);
971 EXPECT_EQ(attrs.FindAttributeIndex(DW_AT_name), UINT32_MAX);
972 EXPECT_NE(attrs.FindAttributeIndex(GetParam()), UINT32_MAX);
973}
974
975TEST(DWARFDIETest, TestGetAttributes_Worklist) {
976 // Test that GetAttributes will follow both the abstract origin
977 // and specification on a single DIE correctly (omitting non-applicable
978 // attributes in the process).
979
980 // Contrived example where
981 // f1---> f2 --> f4
982 // `-> f3 `-> f5
983 //
984 const char *yamldata = R"(
985--- !ELF
986FileHeader:
987 Class: ELFCLASS64
988 Data: ELFDATA2LSB
989 Type: ET_EXEC
990 Machine: EM_AARCH64
991DWARF:
992 debug_str:
993 - foo
994 - bar
995 debug_abbrev:
996 - ID: 0
997 Table:
998 - Code: 0x1
999 Tag: DW_TAG_compile_unit
1000 Children: DW_CHILDREN_yes
1001 Attributes:
1002 - Attribute: DW_AT_language
1003 Form: DW_FORM_data2
1004 - Code: 0x2
1005 Tag: DW_TAG_subprogram
1006 Children: DW_CHILDREN_no
1007 Attributes:
1008 - Attribute: DW_AT_specification
1009 Form: DW_FORM_ref4
1010 - Attribute: DW_AT_abstract_origin
1011 Form: DW_FORM_ref4
1012 - Code: 0x3
1013 Tag: DW_TAG_subprogram
1014 Children: DW_CHILDREN_no
1015 Attributes:
1016 - Attribute: DW_AT_declaration
1017 Form: DW_FORM_flag_present
1018 - Attribute: DW_AT_artificial
1019 Form: DW_FORM_flag_present
1020
1021 debug_info:
1022 - Version: 5
1023 UnitType: DW_UT_compile
1024 AddrSize: 8
1025 Entries:
1026
1027 - AbbrCode: 0x1
1028 Values:
1029 - Value: 0x04
1030
1031# DW_TAG_subprogram ("f1")
1032# DW_AT_specification [DW_FORM_ref4] ("f2")
1033# DW_AT_abstract_origin [DW_FORM_ref4] ("f3")
1034 - AbbrCode: 0x2
1035 Values:
1036 - Value: 0x18
1037 - Value: 0x21
1038
1039# DW_TAG_subprogram ("f2")
1040# DW_AT_specification [DW_FORM_ref4] ("f4")
1041# DW_AT_abstract_origin [DW_FORM_ref4] ("f5")
1042 - AbbrCode: 0x2
1043 Values:
1044 - Value: 0x22
1045 - Value: 0x23
1046
1047# DW_TAG_subprogram ("f3")
1048# DW_AT_declaration [DW_FORM_flag_present]
1049# DW_AT_artificial [DW_FORM_flag_present]
1050 - AbbrCode: 0x3
1051 Values:
1052 - Value: 0x1
1053 - Value: 0x1
1054
1055# DW_TAG_subprogram ("f4")
1056# DW_AT_declaration [DW_FORM_flag_present]
1057# DW_AT_artificial [DW_FORM_flag_present]
1058 - AbbrCode: 0x3
1059 Values:
1060 - Value: 0x1
1061 - Value: 0x1
1062
1063# DW_TAG_subprogram ("f5")
1064# DW_AT_declaration [DW_FORM_flag_present]
1065# DW_AT_artificial [DW_FORM_flag_present]
1066 - AbbrCode: 0x3
1067 Values:
1068 - Value: 0x1
1069 - Value: 0x1
1070
1071 - AbbrCode: 0x0
1072...
1073)";
1074 YAMLModuleTester t(yamldata);
1075
1076 DWARFUnit *unit = t.GetDwarfUnit();
1077 ASSERT_NE(unit, nullptr);
1078 const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
1079 ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
1080 ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus);
1081 DWARFDIE cu_die(unit, cu_entry);
1082
1083 auto f1 = cu_die.GetFirstChild();
1084 ASSERT_TRUE(f1.IsValid());
1085 ASSERT_EQ(f1.Tag(), DW_TAG_subprogram);
1086
1087 auto attrs = f1.GetAttributes(recurse: DWARFDebugInfoEntry::Recurse::yes);
1088 EXPECT_EQ(attrs.Size(), 7U);
1089 EXPECT_EQ(attrs.FindAttributeIndex(DW_AT_declaration), UINT32_MAX);
1090}
1091
1092INSTANTIATE_TEST_SUITE_P(GetAttributeTests, GetAttributesTestFixture,
1093 testing::Values(DW_AT_specification,
1094 DW_AT_abstract_origin));
1095

source code of lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp