llvm.org GIT mirror llvm / bffd929
dwarfgen: Add support for generating the debug_str_offsets section, take 3 Previous version of this patch failed on darwin targets because of different handling of cross-debug-section relocations. This fixes the tests to emit the DW_AT_str_offsets_base attribute correctly in both cases. Since doing this is a non-trivial amount of code, and I'm going to need it in more than one test, I've added a helper function to the dwarfgen DIE class to do it. Original commit message follows: The motivation for this is D49493, where we'd like to test details of debug_str_offsets behavior which is difficult to trigger from a traditional test. This adds the plubming necessary for dwarfgen to generate this section. The more interesting changes are: - I've moved emitStringOffsetsTableHeader function from DwarfFile to DwarfStringPool, so I can generate the section header more easily from the unit test. - added a new addAttribute overload taking an MCExpr*. This is used to generate the DW_AT_str_offsets_base, which links a compile unit to the offset table. I've also added a basic test for reading and writing DW_form_strx forms. Reviewers: dblaikie, JDevlieghere, probinson Subscribers: llvm-commits, aprantl Differential Revision: https://reviews.llvm.org/D49670 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@338031 91177308-0d34-0410-b5e6-96231b3b80d8 Pavel Labath 1 year, 2 months ago
8 changed file(s) with 138 addition(s) and 32 deletion(s). Raw diff Collapse all Expand all
15051505
15061506 void DwarfDebug::emitStringOffsetsTableHeader() {
15071507 DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder;
1508 Holder.emitStringOffsetsTableHeader(
1509 Asm->getObjFileLowering().getDwarfStrOffSection());
1508 Holder.getStringPool().emitStringOffsetsTableHeader(
1509 *Asm, Asm->getObjFileLowering().getDwarfStrOffSection(),
1510 Holder.getStringOffsetsStartSym());
15101511 }
15111512
15121513 template
22912292
22922293 void DwarfDebug::emitStringOffsetsTableHeaderDWO() {
22932294 assert(useSplitDwarf() && "No split dwarf?");
2294 InfoHolder.emitStringOffsetsTableHeader(
2295 Asm->getObjFileLowering().getDwarfStrOffDWOSection());
2295 InfoHolder.getStringPool().emitStringOffsetsTableHeader(
2296 *Asm, Asm->getObjFileLowering().getDwarfStrOffDWOSection(),
2297 InfoHolder.getStringOffsetsStartSym());
22962298 }
22972299
22982300 // Emit the .debug_str.dwo section for separated dwarf. This contains the
2525
2626 void DwarfFile::addUnit(std::unique_ptr U) {
2727 CUs.push_back(std::move(U));
28 }
29
30 void DwarfFile::emitStringOffsetsTableHeader(MCSection *Section) {
31 if (StrPool.empty())
32 return;
33 Asm->OutStreamer->SwitchSection(Section);
34 unsigned EntrySize = 4;
35 // FIXME: DWARF64
36 // We are emitting the header for a contribution to the string offsets
37 // table. The header consists of an entry with the contribution's
38 // size (not including the size of the length field), the DWARF version and
39 // 2 bytes of padding.
40 Asm->emitInt32(StrPool.size() * EntrySize + 4);
41 Asm->emitInt16(Asm->getDwarfVersion());
42 Asm->emitInt16(0);
43 // Define the symbol that marks the start of the contribution. It is
44 // referenced by most unit headers via DW_AT_str_offsets_base.
45 // Split units do not use the attribute.
46 if (StringOffsetsStartSym)
47 Asm->OutStreamer->EmitLabel(StringOffsetsStartSym);
4828 }
4929
5030 // Emit the various dwarf units to the unit section USection with
9090 /// Add a unit to the list of CUs.
9191 void addUnit(std::unique_ptr U);
9292
93 /// Emit the string table offsets header.
94 void emitStringOffsetsTableHeader(MCSection *Section);
95
9693 /// Emit all of the units to the section listed with the given
9794 /// abbreviation section.
9895 void emitUnits(bool UseOffsets);
3636 assert(NumBytes > Entry.Offset && "Unexpected overflow");
3737 }
3838 return EntryRef(*I.first);
39 }
40
41 void DwarfStringPool::emitStringOffsetsTableHeader(AsmPrinter &Asm,
42 MCSection *Section,
43 MCSymbol *StartSym) {
44 if (empty())
45 return;
46 Asm.OutStreamer->SwitchSection(Section);
47 unsigned EntrySize = 4;
48 // FIXME: DWARF64
49 // We are emitting the header for a contribution to the string offsets
50 // table. The header consists of an entry with the contribution's
51 // size (not including the size of the length field), the DWARF version and
52 // 2 bytes of padding.
53 Asm.emitInt32(size() * EntrySize + 4);
54 Asm.emitInt16(Asm.getDwarfVersion());
55 Asm.emitInt16(0);
56 // Define the symbol that marks the start of the contribution. It is
57 // referenced by most unit headers via DW_AT_str_offsets_base.
58 // Split units do not use the attribute.
59 if (StartSym)
60 Asm.OutStreamer->EmitLabel(StartSym);
3961 }
4062
4163 void DwarfStringPool::emit(AsmPrinter &Asm, MCSection *StrSection,
1818
1919 class AsmPrinter;
2020 class MCSection;
21 class MCSymbol;
2122
2223 // Collection of strings for this unit and assorted symbols.
2324 // A String->Symbol mapping of strings used by indirect
3536
3637 DwarfStringPool(BumpPtrAllocator &A, AsmPrinter &Asm, StringRef Prefix);
3738
39 void emitStringOffsetsTableHeader(AsmPrinter &Asm, MCSection *OffsetSection,
40 MCSymbol *StartSym);
41
3842 void emit(AsmPrinter &Asm, MCSection *StrSection,
3943 MCSection *OffsetSection = nullptr,
4044 bool UseRelativeOffsets = false);
6666 const uint32_t Dwarf32Values[] = {1, 2, 3, 4, 5, 6, 7, 8};
6767 const char *StringValue = "Hello";
6868 const char *StrpValue = "World";
69 const char *StrxValue = "Indexed";
70 const char *Strx1Value = "Indexed1";
71 const char *Strx2Value = "Indexed2";
72 const char *Strx3Value = "Indexed3";
73 const char *Strx4Value = "Indexed4";
6974
7075 auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
7176 ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
7277 dwarfgen::Generator *DG = ExpectedDG.get().get();
7378 dwarfgen::CompileUnit &CU = DG->addCompileUnit();
7479 dwarfgen::DIE CUDie = CU.getUnitDIE();
80
81 if (Version >= 5)
82 CUDie.addStrOffsetsBaseAttribute();
83
7584 uint16_t Attr = DW_AT_lo_user;
7685
7786 //----------------------------------------------------------------------
120129 //----------------------------------------------------------------------
121130 const auto Attr_DW_FORM_string = static_cast(Attr++);
122131 CUDie.addAttribute(Attr_DW_FORM_string, DW_FORM_string, StringValue);
132
133 const auto Attr_DW_FORM_strx = static_cast(Attr++);
134 const auto Attr_DW_FORM_strx1 = static_cast(Attr++);
135 const auto Attr_DW_FORM_strx2 = static_cast(Attr++);
136 const auto Attr_DW_FORM_strx3 = static_cast(Attr++);
137 const auto Attr_DW_FORM_strx4 = static_cast(Attr++);
138 if (Version >= 5) {
139 CUDie.addAttribute(Attr_DW_FORM_strx, DW_FORM_strx, StrxValue);
140 CUDie.addAttribute(Attr_DW_FORM_strx1, DW_FORM_strx1, Strx1Value);
141 CUDie.addAttribute(Attr_DW_FORM_strx2, DW_FORM_strx2, Strx2Value);
142 CUDie.addAttribute(Attr_DW_FORM_strx3, DW_FORM_strx3, Strx3Value);
143 CUDie.addAttribute(Attr_DW_FORM_strx4, DW_FORM_strx4, Strx4Value);
144 }
123145
124146 const auto Attr_DW_FORM_strp = static_cast(Attr++);
125147 CUDie.addAttribute(Attr_DW_FORM_strp, DW_FORM_strp, StrpValue);
280302 //----------------------------------------------------------------------
281303 auto ExtractedStringValue = toString(DieDG.find(Attr_DW_FORM_string));
282304 EXPECT_TRUE((bool)ExtractedStringValue);
283 EXPECT_TRUE(strcmp(StringValue, *ExtractedStringValue) == 0);
305 EXPECT_STREQ(StringValue, *ExtractedStringValue);
306
307 if (Version >= 5) {
308 auto ExtractedStrxValue = toString(DieDG.find(Attr_DW_FORM_strx));
309 EXPECT_TRUE((bool)ExtractedStrxValue);
310 EXPECT_STREQ(StrxValue, *ExtractedStrxValue);
311
312 auto ExtractedStrx1Value = toString(DieDG.find(Attr_DW_FORM_strx1));
313 EXPECT_TRUE((bool)ExtractedStrx1Value);
314 EXPECT_STREQ(Strx1Value, *ExtractedStrx1Value);
315
316 auto ExtractedStrx2Value = toString(DieDG.find(Attr_DW_FORM_strx2));
317 EXPECT_TRUE((bool)ExtractedStrx2Value);
318 EXPECT_STREQ(Strx2Value, *ExtractedStrx2Value);
319
320 auto ExtractedStrx3Value = toString(DieDG.find(Attr_DW_FORM_strx3));
321 EXPECT_TRUE((bool)ExtractedStrx3Value);
322 EXPECT_STREQ(Strx3Value, *ExtractedStrx3Value);
323
324 auto ExtractedStrx4Value = toString(DieDG.find(Attr_DW_FORM_strx4));
325 EXPECT_TRUE((bool)ExtractedStrx4Value);
326 EXPECT_STREQ(Strx4Value, *ExtractedStrx4Value);
327 }
284328
285329 auto ExtractedStrpValue = toString(DieDG.find(Attr_DW_FORM_strp));
286330 EXPECT_TRUE((bool)ExtractedStrpValue);
287 EXPECT_TRUE(strcmp(StrpValue, *ExtractedStrpValue) == 0);
331 EXPECT_STREQ(StrpValue, *ExtractedStrpValue);
288332
289333 //----------------------------------------------------------------------
290334 // Test reference forms
5353 DIEInteger(U));
5454 }
5555
56 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, const MCExpr &Expr) {
57 auto &DG = CU->getGenerator();
58 Die->addValue(DG.getAllocator(), static_cast(A), Form,
59 DIEExpr(&Expr));
60 }
61
5662 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
5763 StringRef String) {
5864 auto &DG = CU->getGenerator();
59 if (Form == DW_FORM_string) {
65 switch (Form) {
66 case DW_FORM_string:
6067 Die->addValue(DG.getAllocator(), static_cast(A), Form,
6168 new (DG.getAllocator())
6269 DIEInlineString(String, DG.getAllocator()));
63 } else {
70 break;
71
72 case DW_FORM_strp:
73 case DW_FORM_GNU_str_index:
74 case DW_FORM_strx:
75 case DW_FORM_strx1:
76 case DW_FORM_strx2:
77 case DW_FORM_strx3:
78 case DW_FORM_strx4:
6479 Die->addValue(
6580 DG.getAllocator(), static_cast(A), Form,
6681 DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String)));
82 break;
83
84 default:
85 llvm_unreachable("Unhandled form!");
6786 }
6887 }
6988
94113 assert(Form == DW_FORM_flag_present);
95114 Die->addValue(DG.getAllocator(), static_cast(A), Form,
96115 DIEInteger(1));
116 }
117
118 void dwarfgen::DIE::addStrOffsetsBaseAttribute() {
119 auto &DG = CU->getGenerator();
120 auto &MC = *DG.getMCContext();
121 AsmPrinter *Asm = DG.getAsmPrinter();
122
123 const MCSymbol *SectionStart =
124 Asm->getObjFileLowering().getDwarfStrOffSection()->getBeginSymbol();
125
126 const MCExpr *Expr =
127 MCSymbolRefExpr::create(DG.getStringOffsetsStartSym(), MC);
128
129 if (!Asm->MAI->doesDwarfUseRelocationsAcrossSections())
130 Expr = MCBinaryExpr::createSub(
131 Expr, MCSymbolRefExpr::create(SectionStart, MC), MC);
132
133 addAttribute(dwarf::DW_AT_str_offsets_base, DW_FORM_sec_offset, *Expr);
97134 }
98135
99136 dwarfgen::DIE dwarfgen::DIE::addChild(dwarf::Tag Tag) {
428465 Asm->setDwarfVersion(Version);
429466
430467 StringPool = llvm::make_unique(Allocator, *Asm, StringRef());
468 StringOffsetsStartSym = Asm->createTempSymbol("str_offsets_base");
431469
432470 return Error::success();
433471 }
449487 CU->setLength(CUOffset - 4);
450488 }
451489 Abbreviations.Emit(Asm.get(), TLOF->getDwarfAbbrevSection());
452 StringPool->emit(*Asm, TLOF->getDwarfStrSection());
490
491 StringPool->emitStringOffsetsTableHeader(*Asm, TLOF->getDwarfStrOffSection(),
492 StringOffsetsStartSym);
493 StringPool->emit(*Asm, TLOF->getDwarfStrSection(),
494 TLOF->getDwarfStrOffSection());
495
453496 MS->SwitchSection(TLOF->getDwarfInfoSection());
454497 for (auto &CU : CompileUnits) {
455498 uint16_t Version = CU->getVersion();
8888 /// \param U the unsigned integer to encode.
8989 void addAttribute(uint16_t Attr, dwarf::Form Form, uint64_t U);
9090
91 /// Add an attribute value to be encoded as a DIEExpr
92 ///
93 /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
94 /// represents a user defined DWARF attribute.
95 /// \param Form the dwarf::Form to use when encoding the attribute.
96 /// \param Expr the MC expression used to compute the value.
97 void addAttribute(uint16_t Attr, dwarf::Form Form, const MCExpr &Expr);
98
9199 /// Add an attribute value to be encoded as a DIEString or DIEInlinedString.
92100 ///
93101 /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
121129 /// \param P a pointer to the data to store as the attribute value.
122130 /// \param S the size in bytes of the data pointed to by P .
123131 void addAttribute(uint16_t Attr, dwarf::Form Form, const void *P, size_t S);
132
133 /// Add a DW_AT_str_offsets_base attribute to this DIE.
134 void addStrOffsetsBaseAttribute();
124135
125136 /// Add a new child to this DIE object.
126137 ///
241252 std::vector> LineTables;
242253 DIEAbbrevSet Abbreviations;
243254
255 MCSymbol *StringOffsetsStartSym;
256
244257 SmallString<4096> FileBytes;
245258 /// The stream we use to generate the DWARF into as an ELF file.
246259 std::unique_ptr Stream;
292305 MCContext *getMCContext() const { return MC.get(); }
293306 DIEAbbrevSet &getAbbrevSet() { return Abbreviations; }
294307 DwarfStringPool &getStringPool() { return *StringPool; }
308 MCSymbol *getStringOffsetsStartSym() const { return StringOffsetsStartSym; }
295309
296310 /// Save the generated DWARF file to disk.
297311 ///