llvm.org GIT mirror llvm / 030afdf
dwarfgen: Add support for generating the debug_str_offsets section, take 2 This recommits r337910 after fixing an "ambiguous call to addAttribute" error with some compilers (gcc circa 4.9 and MSVC). It seems that these compilers will consider a "false -> pointer" conversion during overload resolution. This creates ambiguity because one I added an overload which takes a MCExpr * as an argument. I fix this by making the new overload take MCExpr&, which avoids the conversion. It also documents the fact that we expect a valid MCExpr object. 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@337933 91177308-0d34-0410-b5e6-96231b3b80d8 Pavel Labath 1 year, 2 months ago
8 changed file(s) with 120 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.addAttribute(dwarf::DW_AT_str_offsets_base, dwarf::DW_FORM_sec_offset,
83 *MCSymbolRefExpr::create(DG->getStringOffsetsStartSym(),
84 *DG->getMCContext()));
85
7586 uint16_t Attr = DW_AT_lo_user;
7687
7788 //----------------------------------------------------------------------
120131 //----------------------------------------------------------------------
121132 const auto Attr_DW_FORM_string = static_cast(Attr++);
122133 CUDie.addAttribute(Attr_DW_FORM_string, DW_FORM_string, StringValue);
134
135 const auto Attr_DW_FORM_strx = static_cast(Attr++);
136 const auto Attr_DW_FORM_strx1 = static_cast(Attr++);
137 const auto Attr_DW_FORM_strx2 = static_cast(Attr++);
138 const auto Attr_DW_FORM_strx3 = static_cast(Attr++);
139 const auto Attr_DW_FORM_strx4 = static_cast(Attr++);
140 if (Version >= 5) {
141 CUDie.addAttribute(Attr_DW_FORM_strx, DW_FORM_strx, StrxValue);
142 CUDie.addAttribute(Attr_DW_FORM_strx1, DW_FORM_strx1, Strx1Value);
143 CUDie.addAttribute(Attr_DW_FORM_strx2, DW_FORM_strx2, Strx2Value);
144 CUDie.addAttribute(Attr_DW_FORM_strx3, DW_FORM_strx3, Strx3Value);
145 CUDie.addAttribute(Attr_DW_FORM_strx4, DW_FORM_strx4, Strx4Value);
146 }
123147
124148 const auto Attr_DW_FORM_strp = static_cast(Attr++);
125149 CUDie.addAttribute(Attr_DW_FORM_strp, DW_FORM_strp, StrpValue);
280304 //----------------------------------------------------------------------
281305 auto ExtractedStringValue = toString(DieDG.find(Attr_DW_FORM_string));
282306 EXPECT_TRUE((bool)ExtractedStringValue);
283 EXPECT_TRUE(strcmp(StringValue, *ExtractedStringValue) == 0);
307 EXPECT_STREQ(StringValue, *ExtractedStringValue);
308
309 if (Version >= 5) {
310 auto ExtractedStrxValue = toString(DieDG.find(Attr_DW_FORM_strx));
311 EXPECT_TRUE((bool)ExtractedStrxValue);
312 EXPECT_STREQ(StrxValue, *ExtractedStrxValue);
313
314 auto ExtractedStrx1Value = toString(DieDG.find(Attr_DW_FORM_strx1));
315 EXPECT_TRUE((bool)ExtractedStrx1Value);
316 EXPECT_STREQ(Strx1Value, *ExtractedStrx1Value);
317
318 auto ExtractedStrx2Value = toString(DieDG.find(Attr_DW_FORM_strx2));
319 EXPECT_TRUE((bool)ExtractedStrx2Value);
320 EXPECT_STREQ(Strx2Value, *ExtractedStrx2Value);
321
322 auto ExtractedStrx3Value = toString(DieDG.find(Attr_DW_FORM_strx3));
323 EXPECT_TRUE((bool)ExtractedStrx3Value);
324 EXPECT_STREQ(Strx3Value, *ExtractedStrx3Value);
325
326 auto ExtractedStrx4Value = toString(DieDG.find(Attr_DW_FORM_strx4));
327 EXPECT_TRUE((bool)ExtractedStrx4Value);
328 EXPECT_STREQ(Strx4Value, *ExtractedStrx4Value);
329 }
284330
285331 auto ExtractedStrpValue = toString(DieDG.find(Attr_DW_FORM_strp));
286332 EXPECT_TRUE((bool)ExtractedStrpValue);
287 EXPECT_TRUE(strcmp(StrpValue, *ExtractedStrpValue) == 0);
333 EXPECT_STREQ(StrpValue, *ExtractedStrpValue);
288334
289335 //----------------------------------------------------------------------
290336 // Test reference forms
5353 }
5454
5555 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
56 const MCExpr &Expr) {
57 auto &DG = CU->getGenerator();
58 Die->addValue(DG.getAllocator(), static_cast(A), Form,
59 DIEExpr(&Expr));
60 }
61
62 void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
5663 StringRef String) {
5764 auto &DG = CU->getGenerator();
58 if (Form == DW_FORM_string) {
65 switch (Form) {
66 case DW_FORM_string:
5967 Die->addValue(DG.getAllocator(), static_cast(A), Form,
6068 new (DG.getAllocator())
6169 DIEInlineString(String, DG.getAllocator()));
62 } 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:
6379 Die->addValue(
6480 DG.getAllocator(), static_cast(A), Form,
6581 DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String)));
82 break;
83
84 default:
85 llvm_unreachable("Unhandled form!");
6686 }
6787 }
6888
426446 Asm->setDwarfVersion(Version);
427447
428448 StringPool = llvm::make_unique(Allocator, *Asm, StringRef());
449 StringOffsetsStartSym = Asm->createTempSymbol("str_offsets_base");
429450
430451 return Error::success();
431452 }
447468 CU->setLength(CUOffset - 4);
448469 }
449470 Abbreviations.Emit(Asm.get(), MOFI->getDwarfAbbrevSection());
450 StringPool->emit(*Asm, MOFI->getDwarfStrSection());
471
472 StringPool->emitStringOffsetsTableHeader(*Asm, MOFI->getDwarfStrOffSection(),
473 StringOffsetsStartSym);
474 StringPool->emit(*Asm, MOFI->getDwarfStrSection(),
475 MOFI->getDwarfStrOffSection());
476
451477 MS->SwitchSection(MOFI->getDwarfInfoSection());
452478 for (auto &CU : CompileUnits) {
453479 uint16_t Version = CU->getVersion();
8787 /// \param Form the dwarf::Form to use when encoding the attribute.
8888 /// \param U the unsigned integer to encode.
8989 void addAttribute(uint16_t Attr, dwarf::Form Form, uint64_t U);
90
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);
9098
9199 /// Add an attribute value to be encoded as a DIEString or DIEInlinedString.
92100 ///
241249 std::vector> LineTables;
242250 DIEAbbrevSet Abbreviations;
243251
252 MCSymbol *StringOffsetsStartSym;
253
244254 SmallString<4096> FileBytes;
245255 /// The stream we use to generate the DWARF into as an ELF file.
246256 std::unique_ptr Stream;
292302 MCContext *getMCContext() const { return MC.get(); }
293303 DIEAbbrevSet &getAbbrevSet() { return Abbreviations; }
294304 DwarfStringPool &getStringPool() { return *StringPool; }
305 MCSymbol *getStringOffsetsStartSym() const { return StringOffsetsStartSym; }
295306
296307 /// Save the generated DWARF file to disk.
297308 ///