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
;
18 using object::SectionedAddress
;
22 TEST(DWARFDie
, getLocations
) {
23 const char *yamldata
= R
"(
27 Tag: DW_TAG_compile_unit
28 Children: DW_CHILDREN_no
30 - Attribute: DW_AT_location
31 Form: DW_FORM_sec_offset
32 - Attribute: DW_AT_data_member_location
34 - Attribute: DW_AT_vtable_elem_location
35 Form: DW_FORM_sec_offset
36 - Attribute: DW_AT_call_data_location
37 Form: DW_FORM_sec_offset
40 UnitType: DW_UT_compile
43 - AbbrCode: 0x00000001
46 - Value: 0x0000000000000001
55 - Operator: DW_LLE_start_length
56 Values: [ 0x01, 0x02 ]
57 - Operator: DW_LLE_end_of_list
59 - Operator: DW_LLE_startx_length
60 Values: [ 0x01, 0x02 ]
61 - Operator: DW_LLE_end_of_list
63 - Operator: DW_LLE_start_length
64 Values: [ 0x01, 0x02 ]
65 ## end_of_list intentionally missing.
67 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
68 DWARFYAML::emitDebugSections(StringRef(yamldata
),
69 /*IsLittleEndian=*/true,
70 /*Is64BitAddrSize=*/false);
71 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
72 std::unique_ptr
<DWARFContext
> Ctx
=
73 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
74 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
75 ASSERT_NE(nullptr, CU
);
76 DWARFDie Die
= CU
->getUnitDIE();
77 ASSERT_TRUE(Die
.isValid());
79 EXPECT_THAT_EXPECTED(Die
.getLocations(DW_AT_location
),
80 HasValue(testing::ElementsAre(DWARFLocationExpression
{
81 DWARFAddressRange
{1, 3}, {}})));
84 Die
.getLocations(DW_AT_data_member_location
),
85 HasValue(testing::ElementsAre(DWARFLocationExpression
{None
, {0x47}})));
88 Die
.getLocations(DW_AT_vtable_elem_location
),
89 Failed
<ErrorInfoBase
>(testing::Property(
90 &ErrorInfoBase::message
,
91 "unable to resolve indirect address 1 for: DW_LLE_startx_length")));
94 Die
.getLocations(DW_AT_call_data_location
),
96 "unexpected end of data at offset 0x20 while reading [0x20, 0x21)"));
99 Die
.getLocations(DW_AT_call_data_value
),
100 Failed
<ErrorInfoBase
>(testing::Property(&ErrorInfoBase::message
,
101 "No DW_AT_call_data_value")));
104 TEST(DWARFDie
, getDeclFile
) {
105 const char *yamldata
= R
"(
112 Tag: DW_TAG_compile_unit
113 Children: DW_CHILDREN_yes
115 - Attribute: DW_AT_stmt_list
116 Form: DW_FORM_sec_offset
118 Tag: DW_TAG_subprogram
119 Children: DW_CHILDREN_no
121 - Attribute: DW_AT_decl_file
146 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
156 // Given DWARF like this:
158 // 0x0000000b: DW_TAG_compile_unit
159 // DW_AT_stmt_list (0x00000000)
161 // 0x00000010: DW_TAG_subprogram
162 // DW_AT_decl_file ("/tmp/main.cpp")
166 // This tests that we can extract the right DW_AT_decl_file from a DIE that
167 // has a DW_AT_decl_file attribute.
169 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
170 DWARFYAML::emitDebugSections(StringRef(yamldata
),
171 /*IsLittleEndian=*/true,
172 /*Is64BitAddrSize=*/true);
173 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
174 std::unique_ptr
<DWARFContext
> Ctx
=
175 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
176 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
177 ASSERT_NE(nullptr, CU
);
178 DWARFDie Die
= CU
->getUnitDIE(/*ExtractUnitDIEOnly=*/false);
179 ASSERT_TRUE(Die
.isValid());
181 DWARFDie MainDie
= Die
.getFirstChild();
182 ASSERT_TRUE(MainDie
.isValid());
184 std::string DeclFile
= MainDie
.getDeclFile(
185 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath
);
188 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str();
189 EXPECT_EQ(DeclFile
, Ref
);
192 TEST(DWARFDie
, getDeclFileAbstractOrigin
) {
193 const char *yamldata
= R
"(
200 Tag: DW_TAG_compile_unit
201 Children: DW_CHILDREN_yes
203 - Attribute: DW_AT_stmt_list
204 Form: DW_FORM_sec_offset
206 Tag: DW_TAG_subprogram
207 Children: DW_CHILDREN_no
209 - Attribute: DW_AT_abstract_origin
210 Form: DW_FORM_ref_addr
212 Tag: DW_TAG_subprogram
213 Children: DW_CHILDREN_no
215 - Attribute: DW_AT_decl_file
243 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
253 // Given DWARF like this:
255 // 0x0000000b: DW_TAG_compile_unit
256 // DW_AT_stmt_list (0x00000000)
258 // 0x00000010: DW_TAG_subprogram
259 // DW_AT_abstract_origin (0x0000000000000015)
261 // 0x00000015: DW_TAG_subprogram
262 // DW_AT_decl_file ("/tmp/main.cpp")
267 // The DIE at 0x00000010 uses a DW_AT_abstract_origin to point to the DIE at
268 // 0x00000015, make sure that DWARFDie::getDeclFile() succeeds by extracting
269 // the right file name of "/tmp/main.cpp".
271 // This tests that when we have a DW_AT_abstract_origin with a compile unit
272 // relative form (DW_FORM_ref4) to another DIE that we get the right
273 // DW_AT_decl_file value.
275 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
276 DWARFYAML::emitDebugSections(StringRef(yamldata
),
277 /*IsLittleEndian=*/true,
278 /*Is64BitAddrSize=*/true);
279 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
280 std::unique_ptr
<DWARFContext
> Ctx
=
281 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
282 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
283 ASSERT_NE(nullptr, CU
);
284 DWARFDie Die
= CU
->getUnitDIE(/*ExtractUnitDIEOnly=*/false);
285 ASSERT_TRUE(Die
.isValid());
287 DWARFDie MainDie
= Die
.getFirstChild();
288 ASSERT_TRUE(MainDie
.isValid());
290 std::string DeclFile
= MainDie
.getDeclFile(
291 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath
);
294 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str();
295 EXPECT_EQ(DeclFile
, Ref
);
298 TEST(DWARFDie
, getDeclFileSpecification
) {
299 const char *yamldata
= R
"(
306 Tag: DW_TAG_compile_unit
307 Children: DW_CHILDREN_yes
309 - Attribute: DW_AT_stmt_list
310 Form: DW_FORM_sec_offset
312 Tag: DW_TAG_subprogram
313 Children: DW_CHILDREN_no
315 - Attribute: DW_AT_specification
316 Form: DW_FORM_ref_addr
318 Tag: DW_TAG_subprogram
319 Children: DW_CHILDREN_no
321 - Attribute: DW_AT_decl_file
349 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
359 // Given DWARF like this:
361 // 0x0000000b: DW_TAG_compile_unit
362 // DW_AT_stmt_list (0x00000000)
364 // 0x00000010: DW_TAG_subprogram
365 // DW_AT_specification (0x0000000000000015)
367 // 0x00000015: DW_TAG_subprogram
368 // DW_AT_decl_file ("/tmp/main.cpp")
372 // The DIE at 0x00000010 uses a DW_AT_specification to point to the DIE at
373 // 0x00000015, make sure that DWARFDie::getDeclFile() succeeds by extracting
374 // the right file name of "/tmp/main.cpp".
376 // This tests that when we have a DW_AT_specification with a compile unit
377 // relative form (DW_FORM_ref4) to another DIE that we get the right
378 // DW_AT_decl_file value.
380 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
381 DWARFYAML::emitDebugSections(StringRef(yamldata
),
382 /*IsLittleEndian=*/true,
383 /*Is64BitAddrSize=*/true);
384 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
385 std::unique_ptr
<DWARFContext
> Ctx
=
386 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
387 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
388 ASSERT_NE(nullptr, CU
);
389 DWARFDie Die
= CU
->getUnitDIE(/*ExtractUnitDIEOnly=*/false);
390 ASSERT_TRUE(Die
.isValid());
392 DWARFDie MainDie
= Die
.getFirstChild();
393 ASSERT_TRUE(MainDie
.isValid());
395 std::string DeclFile
= MainDie
.getDeclFile(
396 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath
);
399 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str();
400 EXPECT_EQ(DeclFile
, Ref
);
403 TEST(DWARFDie
, getDeclFileAbstractOriginAcrossCUBoundary
) {
404 const char *yamldata
= R
"(
411 Tag: DW_TAG_compile_unit
412 Children: DW_CHILDREN_yes
414 Tag: DW_TAG_subprogram
415 Children: DW_CHILDREN_no
417 - Attribute: DW_AT_abstract_origin
418 Form: DW_FORM_ref_addr
420 Tag: DW_TAG_compile_unit
421 Children: DW_CHILDREN_yes
423 - Attribute: DW_AT_stmt_list
424 Form: DW_FORM_sec_offset
426 Tag: DW_TAG_subprogram
427 Children: DW_CHILDREN_no
429 - Attribute: DW_AT_decl_file
465 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
475 // Given DWARF like this:
477 // 0x0000000b: DW_TAG_compile_unit
479 // 0x0000000c: DW_TAG_subprogram
480 // DW_AT_abstract_origin (0x0000000000000022)
484 // 0x0000001d: DW_TAG_compile_unit
485 // DW_AT_stmt_list (0x00000000)
487 // 0x00000022: DW_TAG_subprogram
488 // DW_AT_decl_file ("/tmp/main.cpp")
492 // This tests that when we have a DW_AT_abstract_origin with a
493 // DW_FORM_ref_addr to another DIE in another compile unit that we use the
494 // right file table when converting the file index of the DW_AT_decl_file.
496 // The DIE at 0x0000000c uses a DW_AT_abstract_origin to point to the DIE at
497 // 0x00000022, make sure that DWARFDie::getDeclFile() succeeds by extracting
498 // the right file name of "/tmp/main.cpp". The DW_AT_decl_file must grab the
499 // file from the line table prologue of the compile unit at offset
502 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
503 DWARFYAML::emitDebugSections(StringRef(yamldata
),
504 /*IsLittleEndian=*/true,
505 /*Is64BitAddrSize=*/true);
506 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
507 std::unique_ptr
<DWARFContext
> Ctx
=
508 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
509 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
510 ASSERT_NE(nullptr, CU
);
511 DWARFDie Die
= CU
->getUnitDIE(/*ExtractUnitDIEOnly=*/false);
512 ASSERT_TRUE(Die
.isValid());
514 DWARFDie MainDie
= Die
.getFirstChild();
515 ASSERT_TRUE(MainDie
.isValid());
517 std::string DeclFile
= MainDie
.getDeclFile(
518 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath
);
521 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str();
522 EXPECT_EQ(DeclFile
, Ref
);
525 TEST(DWARFDie
, getDeclFileSpecificationAcrossCUBoundary
) {
526 const char *yamldata
= R
"(
533 Tag: DW_TAG_compile_unit
534 Children: DW_CHILDREN_yes
536 Tag: DW_TAG_subprogram
537 Children: DW_CHILDREN_no
539 - Attribute: DW_AT_specification
540 Form: DW_FORM_ref_addr
542 Tag: DW_TAG_compile_unit
543 Children: DW_CHILDREN_yes
545 - Attribute: DW_AT_stmt_list
546 Form: DW_FORM_sec_offset
548 Tag: DW_TAG_subprogram
549 Children: DW_CHILDREN_no
551 - Attribute: DW_AT_decl_file
587 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
597 // Given DWARF like this:
599 // 0x0000000b: DW_TAG_compile_unit
601 // 0x0000000c: DW_TAG_subprogram
602 // DW_AT_specification (0x0000000000000022)
606 // 0x0000001d: DW_TAG_compile_unit
607 // DW_AT_stmt_list (0x00000000)
609 // 0x00000022: DW_TAG_subprogram
610 // DW_AT_decl_file ("/tmp/main.cpp")
614 // This tests that when we have a DW_AT_specification with a
615 // DW_FORM_ref_addr to another DIE in another compile unit that we use the
616 // right file table when converting the file index of the DW_AT_decl_file.
618 // The DIE at 0x0000000c uses a DW_AT_specification to point to the DIE at
619 // 0x00000022, make sure that DWARFDie::getDeclFile() succeeds by extracting
620 // the right file name of "/tmp/main.cpp". The DW_AT_decl_file must grab the
621 // file from the line table prologue of the compile unit at offset
624 Expected
<StringMap
<std::unique_ptr
<MemoryBuffer
>>> Sections
=
625 DWARFYAML::emitDebugSections(StringRef(yamldata
),
626 /*IsLittleEndian=*/true,
627 /*Is64BitAddrSize=*/true);
628 ASSERT_THAT_EXPECTED(Sections
, Succeeded());
629 std::unique_ptr
<DWARFContext
> Ctx
=
630 DWARFContext::create(*Sections
, 4, /*isLittleEndian=*/true);
631 DWARFCompileUnit
*CU
= Ctx
->getCompileUnitForOffset(0);
632 ASSERT_NE(nullptr, CU
);
633 DWARFDie Die
= CU
->getUnitDIE(/*ExtractUnitDIEOnly=*/false);
634 ASSERT_TRUE(Die
.isValid());
636 DWARFDie MainDie
= Die
.getFirstChild();
637 ASSERT_TRUE(MainDie
.isValid());
639 std::string DeclFile
= MainDie
.getDeclFile(
640 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath
);
643 ("/tmp" + llvm::sys::path::get_separator() + "main.cpp").str();
644 EXPECT_EQ(DeclFile
, Ref
);
647 } // end anonymous namespace