1 //===- llvm/unittest/DebugInfo/DWARFDieTest.cpp ---------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/BinaryFormat/Dwarf.h"
10 #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
11 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
12 #include "llvm/ObjectYAML/DWARFEmitter.h"
13 #include "llvm/Testing/Support/Error.h"
14 #include "gtest/gtest.h"
17 using namespace llvm::dwarf
;
21 TEST(DWARFDie
, getLocations
) {
22 const char *yamldata
= R
"(
26 Tag: DW_TAG_compile_unit
27 Children: DW_CHILDREN_no
29 - Attribute: DW_AT_location
30 Form: DW_FORM_sec_offset
31 - Attribute: DW_AT_data_member_location
33 - Attribute: DW_AT_vtable_elem_location
34 Form: DW_FORM_sec_offset
35 - Attribute: DW_AT_call_data_location
36 Form: DW_FORM_sec_offset
39 UnitType: DW_UT_compile
42 - AbbrCode: 0x00000001
45 - Value: 0x0000000000000001
54 - Operator: DW_LLE_start_length
55 Values: [ 0x01, 0x02 ]
56 - Operator: DW_LLE_end_of_list
58 - Operator: DW_LLE_startx_length
59 Values: [ 0x01, 0x02 ]
60 - Operator: DW_LLE_end_of_list
62 - Operator: DW_LLE_start_length
63 Values: [ 0x01, 0x02 ]
64 ## end_of_list intentionally missing.
66 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
67 DWARFYAML::emitDebugSections(StringRef(yamldata
),
68 /*IsLittleEndian=*/true,
69 /*Is64BitAddrSize=*/false);
70 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
71 std::unique_ptr
<DWARFContext
> Ctx
=
72 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
73 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
74 ASSERT_NE(nullptr, CU
);
75 DWARFDie Die
= CU
->getUnitDIE();
76 ASSERT_TRUE(Die
.isValid());
78 EXPECT_THAT_EXPECTED(Die
.getLocations(DW_AT_location
),
79 HasValue(testing::ElementsAre(DWARFLocationExpression
{
80 DWARFAddressRange
{1, 3}, {}})));
82 EXPECT_THAT_EXPECTED(Die
.getLocations(DW_AT_data_member_location
),
83 HasValue(testing::ElementsAre(
84 DWARFLocationExpression
{std::nullopt
, {0x47}})));
87 Die
.getLocations(DW_AT_vtable_elem_location
),
88 Failed
<ErrorInfoBase
>(testing::Property(
89 &ErrorInfoBase::message
,
90 "unable to resolve indirect address 1 for: DW_LLE_startx_length")));
93 Die
.getLocations(DW_AT_call_data_location
),
95 "unexpected end of data at offset 0x20 while reading [0x20, 0x21)"));
98 Die
.getLocations(DW_AT_call_data_value
),
99 Failed
<ErrorInfoBase
>(testing::Property(&ErrorInfoBase::message
,
100 "No DW_AT_call_data_value")));
103 TEST(DWARFDie
, getDeclFile
) {
104 const char *yamldata
= R
"(
111 Tag: DW_TAG_compile_unit
112 Children: DW_CHILDREN_yes
114 - Attribute: DW_AT_stmt_list
115 Form: DW_FORM_sec_offset
117 Tag: DW_TAG_subprogram
118 Children: DW_CHILDREN_no
120 - Attribute: DW_AT_decl_file
145 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
155 // Given DWARF like this:
157 // 0x0000000b: DW_TAG_compile_unit
158 // DW_AT_stmt_list (0x00000000)
160 // 0x00000010: DW_TAG_subprogram
161 // DW_AT_decl_file ("/tmp/main.cpp")
165 // This tests that we can extract the right DW_AT_decl_file from a DIE that
166 // has a DW_AT_decl_file attribute.
168 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
169 DWARFYAML::emitDebugSections(StringRef(yamldata
),
170 /*IsLittleEndian=*/true,
171 /*Is64BitAddrSize=*/true);
172 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
173 std::unique_ptr
<DWARFContext
> Ctx
=
174 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
175 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
176 ASSERT_NE(nullptr, CU
);
177 DWARFDie Die
= CU
->getUnitDIE(/*ExtractUnitDIEOnly=*/false);
178 ASSERT_TRUE(Die
.isValid());
180 DWARFDie MainDie
= Die
.getFirstChild();
181 ASSERT_TRUE(MainDie
.isValid());
183 std::string DeclFile
= MainDie
.getDeclFile(
184 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath
);
187 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str();
188 EXPECT_EQ(DeclFile
, Ref
);
191 TEST(DWARFDie
, getDeclFileAbstractOrigin
) {
192 const char *yamldata
= R
"(
199 Tag: DW_TAG_compile_unit
200 Children: DW_CHILDREN_yes
202 - Attribute: DW_AT_stmt_list
203 Form: DW_FORM_sec_offset
205 Tag: DW_TAG_subprogram
206 Children: DW_CHILDREN_no
208 - Attribute: DW_AT_abstract_origin
209 Form: DW_FORM_ref_addr
211 Tag: DW_TAG_subprogram
212 Children: DW_CHILDREN_no
214 - Attribute: DW_AT_decl_file
242 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
252 // Given DWARF like this:
254 // 0x0000000b: DW_TAG_compile_unit
255 // DW_AT_stmt_list (0x00000000)
257 // 0x00000010: DW_TAG_subprogram
258 // DW_AT_abstract_origin (0x0000000000000015)
260 // 0x00000015: DW_TAG_subprogram
261 // DW_AT_decl_file ("/tmp/main.cpp")
266 // The DIE at 0x00000010 uses a DW_AT_abstract_origin to point to the DIE at
267 // 0x00000015, make sure that DWARFDie::getDeclFile() succeeds by extracting
268 // the right file name of "/tmp/main.cpp".
270 // This tests that when we have a DW_AT_abstract_origin with a compile unit
271 // relative form (DW_FORM_ref4) to another DIE that we get the right
272 // DW_AT_decl_file value.
274 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
275 DWARFYAML::emitDebugSections(StringRef(yamldata
),
276 /*IsLittleEndian=*/true,
277 /*Is64BitAddrSize=*/true);
278 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
279 std::unique_ptr
<DWARFContext
> Ctx
=
280 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
281 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
282 ASSERT_NE(nullptr, CU
);
283 DWARFDie Die
= CU
->getUnitDIE(/*ExtractUnitDIEOnly=*/false);
284 ASSERT_TRUE(Die
.isValid());
286 DWARFDie MainDie
= Die
.getFirstChild();
287 ASSERT_TRUE(MainDie
.isValid());
289 std::string DeclFile
= MainDie
.getDeclFile(
290 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath
);
293 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str();
294 EXPECT_EQ(DeclFile
, Ref
);
297 TEST(DWARFDie
, getDeclFileSpecification
) {
298 const char *yamldata
= R
"(
305 Tag: DW_TAG_compile_unit
306 Children: DW_CHILDREN_yes
308 - Attribute: DW_AT_stmt_list
309 Form: DW_FORM_sec_offset
311 Tag: DW_TAG_subprogram
312 Children: DW_CHILDREN_no
314 - Attribute: DW_AT_specification
315 Form: DW_FORM_ref_addr
317 Tag: DW_TAG_subprogram
318 Children: DW_CHILDREN_no
320 - Attribute: DW_AT_decl_file
348 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
358 // Given DWARF like this:
360 // 0x0000000b: DW_TAG_compile_unit
361 // DW_AT_stmt_list (0x00000000)
363 // 0x00000010: DW_TAG_subprogram
364 // DW_AT_specification (0x0000000000000015)
366 // 0x00000015: DW_TAG_subprogram
367 // DW_AT_decl_file ("/tmp/main.cpp")
371 // The DIE at 0x00000010 uses a DW_AT_specification to point to the DIE at
372 // 0x00000015, make sure that DWARFDie::getDeclFile() succeeds by extracting
373 // the right file name of "/tmp/main.cpp".
375 // This tests that when we have a DW_AT_specification with a compile unit
376 // relative form (DW_FORM_ref4) to another DIE that we get the right
377 // DW_AT_decl_file value.
379 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
380 DWARFYAML::emitDebugSections(StringRef(yamldata
),
381 /*IsLittleEndian=*/true,
382 /*Is64BitAddrSize=*/true);
383 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
384 std::unique_ptr
<DWARFContext
> Ctx
=
385 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
386 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
387 ASSERT_NE(nullptr, CU
);
388 DWARFDie Die
= CU
->getUnitDIE(/*ExtractUnitDIEOnly=*/false);
389 ASSERT_TRUE(Die
.isValid());
391 DWARFDie MainDie
= Die
.getFirstChild();
392 ASSERT_TRUE(MainDie
.isValid());
394 std::string DeclFile
= MainDie
.getDeclFile(
395 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath
);
398 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str();
399 EXPECT_EQ(DeclFile
, Ref
);
402 TEST(DWARFDie
, getDeclFileAbstractOriginAcrossCUBoundary
) {
403 const char *yamldata
= R
"(
410 Tag: DW_TAG_compile_unit
411 Children: DW_CHILDREN_yes
413 Tag: DW_TAG_subprogram
414 Children: DW_CHILDREN_no
416 - Attribute: DW_AT_abstract_origin
417 Form: DW_FORM_ref_addr
419 Tag: DW_TAG_compile_unit
420 Children: DW_CHILDREN_yes
422 - Attribute: DW_AT_stmt_list
423 Form: DW_FORM_sec_offset
425 Tag: DW_TAG_subprogram
426 Children: DW_CHILDREN_no
428 - Attribute: DW_AT_decl_file
464 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
474 // Given DWARF like this:
476 // 0x0000000b: DW_TAG_compile_unit
478 // 0x0000000c: DW_TAG_subprogram
479 // DW_AT_abstract_origin (0x0000000000000022)
483 // 0x0000001d: DW_TAG_compile_unit
484 // DW_AT_stmt_list (0x00000000)
486 // 0x00000022: DW_TAG_subprogram
487 // DW_AT_decl_file ("/tmp/main.cpp")
491 // This tests that when we have a DW_AT_abstract_origin with a
492 // DW_FORM_ref_addr to another DIE in another compile unit that we use the
493 // right file table when converting the file index of the DW_AT_decl_file.
495 // The DIE at 0x0000000c uses a DW_AT_abstract_origin to point to the DIE at
496 // 0x00000022, make sure that DWARFDie::getDeclFile() succeeds by extracting
497 // the right file name of "/tmp/main.cpp". The DW_AT_decl_file must grab the
498 // file from the line table prologue of the compile unit at offset
501 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
502 DWARFYAML::emitDebugSections(StringRef(yamldata
),
503 /*IsLittleEndian=*/true,
504 /*Is64BitAddrSize=*/true);
505 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
506 std::unique_ptr
<DWARFContext
> Ctx
=
507 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
508 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
509 ASSERT_NE(nullptr, CU
);
510 DWARFDie Die
= CU
->getUnitDIE(/*ExtractUnitDIEOnly=*/false);
511 ASSERT_TRUE(Die
.isValid());
513 DWARFDie MainDie
= Die
.getFirstChild();
514 ASSERT_TRUE(MainDie
.isValid());
516 std::string DeclFile
= MainDie
.getDeclFile(
517 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath
);
520 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str();
521 EXPECT_EQ(DeclFile
, Ref
);
524 TEST(DWARFDie
, getDeclFileSpecificationAcrossCUBoundary
) {
525 const char *yamldata
= R
"(
532 Tag: DW_TAG_compile_unit
533 Children: DW_CHILDREN_yes
535 Tag: DW_TAG_subprogram
536 Children: DW_CHILDREN_no
538 - Attribute: DW_AT_specification
539 Form: DW_FORM_ref_addr
541 Tag: DW_TAG_compile_unit
542 Children: DW_CHILDREN_yes
544 - Attribute: DW_AT_stmt_list
545 Form: DW_FORM_sec_offset
547 Tag: DW_TAG_subprogram
548 Children: DW_CHILDREN_no
550 - Attribute: DW_AT_decl_file
586 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
596 // Given DWARF like this:
598 // 0x0000000b: DW_TAG_compile_unit
600 // 0x0000000c: DW_TAG_subprogram
601 // DW_AT_specification (0x0000000000000022)
605 // 0x0000001d: DW_TAG_compile_unit
606 // DW_AT_stmt_list (0x00000000)
608 // 0x00000022: DW_TAG_subprogram
609 // DW_AT_decl_file ("/tmp/main.cpp")
613 // This tests that when we have a DW_AT_specification with a
614 // DW_FORM_ref_addr to another DIE in another compile unit that we use the
615 // right file table when converting the file index of the DW_AT_decl_file.
617 // The DIE at 0x0000000c uses a DW_AT_specification to point to the DIE at
618 // 0x00000022, make sure that DWARFDie::getDeclFile() succeeds by extracting
619 // the right file name of "/tmp/main.cpp". The DW_AT_decl_file must grab the
620 // file from the line table prologue of the compile unit at offset
623 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
624 DWARFYAML::emitDebugSections(StringRef(yamldata
),
625 /*IsLittleEndian=*/true,
626 /*Is64BitAddrSize=*/true);
627 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
628 std::unique_ptr
<DWARFContext
> Ctx
=
629 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
630 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
631 ASSERT_NE(nullptr, CU
);
632 DWARFDie Die
= CU
->getUnitDIE(/*ExtractUnitDIEOnly=*/false);
633 ASSERT_TRUE(Die
.isValid());
635 DWARFDie MainDie
= Die
.getFirstChild();
636 ASSERT_TRUE(MainDie
.isValid());
638 std::string DeclFile
= MainDie
.getDeclFile(
639 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath
);
642 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str();
643 EXPECT_EQ(DeclFile
, Ref
);
646 TEST(DWARFDie
, getNameFromTypeUnit
) {
647 const char *yamldata
= R
"(
652 Tag: DW_TAG_compile_unit
653 Children: DW_CHILDREN_yes
655 Tag: DW_TAG_structure_type
656 Children: DW_CHILDREN_no
658 - Attribute: DW_AT_signature
659 Form: DW_FORM_ref_sig8
661 Tag: DW_TAG_type_unit
662 Children: DW_CHILDREN_yes
664 Tag: DW_TAG_structure_type
665 Children: DW_CHILDREN_no
667 - Attribute: DW_AT_name
671 UnitType: DW_UT_compile
677 - Value: 0xdeadbeefbaadf00d
682 TypeSignature: 0xdeadbeefbaadf00d
692 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
693 DWARFYAML::emitDebugSections(StringRef(yamldata
),
694 /*IsLittleEndian=*/true,
695 /*Is64BitAddrSize=*/true);
696 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
697 std::unique_ptr
<DWARFContext
> Ctx
=
698 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
699 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
700 ASSERT_NE(nullptr, CU
);
701 DWARFDie Die
= CU
->getUnitDIE(/*ExtractUnitDIEOnly=*/false).getFirstChild();
702 ASSERT_TRUE(Die
.isValid());
704 ASSERT_STREQ(Die
.getName(DINameKind::ShortName
), "STRUCT");
707 } // end anonymous namespace