llvm.org GIT mirror llvm / 23332c5
[DebugInfo] Reduce debug_str_offsets section size Summary: The accelerator tables use the debug_str section to store their strings. However, they do not support the indirect method of access that is available for the debug_info section (DW_FORM_strx et al.). Currently our code is assuming that all strings can/will be referenced indirectly, and puts all of them into the debug_str_offsets section. This is generally true for regular (unsplit) dwarf, but in the DWO case, most of the strings in the debug_str section will only be used from the accelerator tables. Therefore the contents of the debug_str_offsets section will be largely unused and bloating the main executable. This patch rectifies this by teaching the DwarfStringPool to differentiate between strings accessed directly and indirectly. When a user inserts a string into the pool it has to declare whether that string will be referenced directly or not. If at least one user requsts indirect access, that string will be assigned an index ID and put into debug_str_offsets table. Otherwise, the offset table is skipped. This approach reduces the overall binary size (when compiled with -gdwarf-5 -gsplit-dwarf) in my tests by about 2% (debug_str_offsets is shrunk by 99%). Reviewers: probinson, dblaikie, JDevlieghere Subscribers: aprantl, mgrang, llvm-commits Differential Revision: https://reviews.llvm.org/D49493 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@339122 91177308-0d34-0410-b5e6-96231b3b80d8 Pavel Labath 1 year, 2 months ago
14 changed file(s) with 298 addition(s) and 56 deletion(s). Raw diff Collapse all Expand all
99 #ifndef LLVM_CODEGEN_DWARFSTRINGPOOLENTRY_H
1010 #define LLVM_CODEGEN_DWARFSTRINGPOOLENTRY_H
1111
12 #include "llvm/ADT/PointerIntPair.h"
1213 #include "llvm/ADT/StringMap.h"
1314
1415 namespace llvm {
1718
1819 /// Data for a string pool entry.
1920 struct DwarfStringPoolEntry {
21 static constexpr unsigned NotIndexed = -1;
22
2023 MCSymbol *Symbol;
2124 unsigned Offset;
2225 unsigned Index;
26
27 bool isIndexed() const { return Index != NotIndexed; }
2328 };
2429
2530 /// String pool entry reference.
26 struct DwarfStringPoolEntryRef {
27 const StringMapEntry *I = nullptr;
31 class DwarfStringPoolEntryRef {
32 PointerIntPair *, 1, bool>
33 MapEntryAndIndexed;
34
35 const StringMapEntry *getMapEntry() const {
36 return MapEntryAndIndexed.getPointer();
37 }
2838
2939 public:
3040 DwarfStringPoolEntryRef() = default;
31 explicit DwarfStringPoolEntryRef(
32 const StringMapEntry &I)
33 : I(&I) {}
41 DwarfStringPoolEntryRef(const StringMapEntry &Entry,
42 bool Indexed)
43 : MapEntryAndIndexed(&Entry, Indexed) {}
3444
35 explicit operator bool() const { return I; }
45 explicit operator bool() const { return getMapEntry(); }
3646 MCSymbol *getSymbol() const {
37 assert(I->second.Symbol && "No symbol available!");
38 return I->second.Symbol;
47 assert(getMapEntry()->second.Symbol && "No symbol available!");
48 return getMapEntry()->second.Symbol;
3949 }
40 unsigned getOffset() const { return I->second.Offset; }
41 unsigned getIndex() const { return I->second.Index; }
42 StringRef getString() const { return I->first(); }
50 unsigned getOffset() const { return getMapEntry()->second.Offset; }
51 bool isIndexed() const { return MapEntryAndIndexed.getInt(); }
52 unsigned getIndex() const {
53 assert(isIndexed());
54 assert(getMapEntry()->getValue().isIndexed());
55 return getMapEntry()->second.Index;
56 }
57 StringRef getString() const { return getMapEntry()->first(); }
4358 /// Return the entire string pool entry for convenience.
44 DwarfStringPoolEntry getEntry() const { return I->getValue(); }
59 DwarfStringPoolEntry getEntry() const { return getMapEntry()->getValue(); }
4560
46 bool operator==(const DwarfStringPoolEntryRef &X) const { return I == X.I; }
47 bool operator!=(const DwarfStringPoolEntryRef &X) const { return I != X.I; }
61 bool operator==(const DwarfStringPoolEntryRef &X) const {
62 return getMapEntry() == X.getMapEntry();
63 }
64 bool operator!=(const DwarfStringPoolEntryRef &X) const {
65 return getMapEntry() != X.getMapEntry();
66 }
4867 };
4968
5069 } // end namespace llvm
24362436 return;
24372437
24382438 DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder;
2439 DwarfStringPoolEntryRef Ref =
2440 Holder.getStringPool().getEntry(*Asm, Name);
2439 DwarfStringPoolEntryRef Ref = Holder.getStringPool().getEntry(*Asm, Name);
24412440
24422441 switch (getAccelTableKind()) {
24432442 case AccelTableKind::Apple:
2323 : Pool(A), Prefix(Prefix),
2424 ShouldCreateSymbols(Asm.MAI->doesDwarfUseRelocationsAcrossSections()) {}
2525
26 DwarfStringPool::EntryRef DwarfStringPool::getEntry(AsmPrinter &Asm,
27 StringRef Str) {
26 StringMapEntry &
27 DwarfStringPool::getEntryImpl(AsmPrinter &Asm, StringRef Str) {
2828 auto I = Pool.insert(std::make_pair(Str, EntryTy()));
29 auto &Entry = I.first->second;
2930 if (I.second) {
30 auto &Entry = I.first->second;
31 Entry.Index = Pool.size() - 1;
31 Entry.Index = EntryTy::NotIndexed;
3232 Entry.Offset = NumBytes;
3333 Entry.Symbol = ShouldCreateSymbols ? Asm.createTempSymbol(Prefix) : nullptr;
3434
3535 NumBytes += Str.size() + 1;
3636 assert(NumBytes > Entry.Offset && "Unexpected overflow");
3737 }
38 return EntryRef(*I.first);
38 return *I.first;
39 }
40
41 DwarfStringPool::EntryRef DwarfStringPool::getEntry(AsmPrinter &Asm,
42 StringRef Str) {
43 auto &MapEntry = getEntryImpl(Asm, Str);
44 return EntryRef(MapEntry, false);
45 }
46
47 DwarfStringPool::EntryRef DwarfStringPool::getIndexedEntry(AsmPrinter &Asm,
48 StringRef Str) {
49 auto &MapEntry = getEntryImpl(Asm, Str);
50 if (!MapEntry.getValue().isIndexed())
51 MapEntry.getValue().Index = NumIndexedStrings++;
52 return EntryRef(MapEntry, true);
3953 }
4054
4155 void DwarfStringPool::emitStringOffsetsTableHeader(AsmPrinter &Asm,
4256 MCSection *Section,
4357 MCSymbol *StartSym) {
44 if (empty())
58 if (getNumIndexedStrings() == 0)
4559 return;
4660 Asm.OutStreamer->SwitchSection(Section);
4761 unsigned EntrySize = 4;
5064 // table. The header consists of an entry with the contribution's
5165 // size (not including the size of the length field), the DWARF version and
5266 // 2 bytes of padding.
53 Asm.emitInt32(size() * EntrySize + 4);
67 Asm.emitInt32(getNumIndexedStrings() * EntrySize + 4);
5468 Asm.emitInt16(Asm.getDwarfVersion());
5569 Asm.emitInt16(0);
5670 // Define the symbol that marks the start of the contribution. It is
6882 // Start the dwarf str section.
6983 Asm.OutStreamer->SwitchSection(StrSection);
7084
71 // Get all of the string pool entries and put them in an array by their ID so
72 // we can sort them.
73 SmallVector *, 64> Entries(Pool.size());
85 // Get all of the string pool entries and sort them by their offset.
86 SmallVector *, 64> Entries;
87 Entries.reserve(Pool.size());
7488
7589 for (const auto &E : Pool)
76 Entries[E.getValue().Index] = &E;
90 Entries.push_back(&E);
91
92 llvm::sort(
93 Entries.begin(), Entries.end(),
94 [](const StringMapEntry *A, const StringMapEntry *B) {
95 return A->getValue().Offset < B->getValue().Offset;
96 });
7797
7898 for (const auto &Entry : Entries) {
7999 assert(ShouldCreateSymbols == static_cast(Entry->getValue().Symbol) &&
92112
93113 // If we've got an offset section go ahead and emit that now as well.
94114 if (OffsetSection) {
115 // Now only take the indexed entries and put them in an array by their ID so
116 // we can emit them in order.
117 Entries.resize(NumIndexedStrings);
118 for (const auto &Entry : Pool) {
119 if (Entry.getValue().isIndexed())
120 Entries[Entry.getValue().Index] = &Entry;
121 }
122
95123 Asm.OutStreamer->SwitchSection(OffsetSection);
96124 unsigned size = 4; // FIXME: DWARF64 is 8.
97125 for (const auto &Entry : Entries)
2929 StringMap Pool;
3030 StringRef Prefix;
3131 unsigned NumBytes = 0;
32 unsigned NumIndexedStrings = 0;
3233 bool ShouldCreateSymbols;
34
35 StringMapEntry &getEntryImpl(AsmPrinter &Asm, StringRef Str);
3336
3437 public:
3538 using EntryRef = DwarfStringPoolEntryRef;
4750
4851 unsigned size() const { return Pool.size(); }
4952
53 unsigned getNumIndexedStrings() const { return NumIndexedStrings; }
54
5055 /// Get a reference to an entry in the string pool.
5156 EntryRef getEntry(AsmPrinter &Asm, StringRef Str);
57
58 /// Same as getEntry, except that you can use EntryRef::getIndex to obtain a
59 /// unique ID of this entry (e.g., for use in indexed forms like
60 /// DW_FORM_strx).
61 EntryRef getIndexedEntry(AsmPrinter &Asm, StringRef Str);
5262 };
5363
5464 } // end namespace llvm
242242 DIEInlineString(String, DIEValueAllocator));
243243 return;
244244 }
245 auto StringPoolEntry = DU->getStringPool().getEntry(*Asm, String);
246245 dwarf::Form IxForm =
247246 isDwoUnit() ? dwarf::DW_FORM_GNU_str_index : dwarf::DW_FORM_strp;
247
248 auto StringPoolEntry =
249 useSegmentedStringOffsetsTable() || IxForm == dwarf::DW_FORM_GNU_str_index
250 ? DU->getStringPool().getIndexedEntry(*Asm, String)
251 : DU->getStringPool().getEntry(*Asm, String);
252
248253 // For DWARF v5 and beyond, use the smallest strx? form possible.
249254 if (useSegmentedStringOffsetsTable()) {
250255 IxForm = dwarf::DW_FORM_strx1;
0 ; REQUIRES: object-emission
1 ; RUN: llc -mtriple=x86_64-unknown-linux-gnu -split-dwarf-file=foo.dwo -filetype=obj < %s \
2 ; RUN: | llvm-dwarfdump -v - | FileCheck %s
3
4 ; This triggers a situation where the order of entries in the .debug_str and
5 ; .debug_str_offsets sections does not match and makes sure that all entries are
6 ; still wired up correctly.
7
8 ; Produced with "clang -S -emit-llvm -gdwarf-5" from source "int X;", copied
9 ; three times and modified by hand.
10
11 ; CHECK: .debug_info contents:
12 ; CHECK: DW_TAG_compile_unit
13 ; CHECK: DW_AT_comp_dir [DW_FORM_strx1] ( indexed (00000001) string = "X3")
14 ; CHECK: DW_TAG_compile_unit
15 ; CHECK: DW_AT_comp_dir [DW_FORM_strx1] ( indexed (00000002) string = "X2")
16 ; CHECK: DW_TAG_compile_unit
17 ; CHECK: DW_AT_comp_dir [DW_FORM_strx1] ( indexed (00000003) string = "X1")
18 ; CHECK: .debug_info.dwo contents:
19
20 ; CHECK: .debug_str contents:
21 ; CHECK: 0x[[X3:[0-9a-f]*]]: "X3"
22 ; CHECK: 0x[[X1:[0-9a-f]*]]: "X1"
23 ; CHECK: 0x[[X2:[0-9a-f]*]]: "X2"
24
25 ; CHECK: .debug_str_offsets contents:
26 ; CHECK: Format = DWARF32, Version = 5
27 ; CHECK-NEXT: 00000000 "foo.dwo"
28 ; CHECK-NEXT: [[X3]] "X3"
29 ; CHECK-NEXT: [[X2]] "X2"
30 ; CHECK-NEXT: [[X1]] "X1"
31 ; CHECK-EMPTY:
32
33
34
35 !llvm.dbg.cu = !{!10, !20, !30}
36 !llvm.module.flags = !{!0, !1, !2}
37 !llvm.ident = !{!3}
38
39 !0 = !{i32 2, !"Dwarf Version", i32 5}
40 !1 = !{i32 2, !"Debug Info Version", i32 3}
41 !2 = !{i32 1, !"wchar_size", i32 4}
42 !3 = !{!"clang version 7.0.0 (trunk 337353) (llvm/trunk 337361)"}
43
44
45 @X1 = dso_local global i32 0, align 4, !dbg !11
46
47 !10 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !13, producer: "clang version 7.0.0 (trunk 337353) (llvm/trunk 337361)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !14, globals: !15)
48 !11 = !DIGlobalVariableExpression(var: !12, expr: !DIExpression())
49 !12 = distinct !DIGlobalVariable(name: "X1", scope: !10, file: !16, line: 1, type: !17, isLocal: false, isDefinition: true)
50 !13 = !DIFile(filename: "-", directory: "X3", checksumkind: CSK_MD5, checksum: "f2e6e10e303927a308f1645fbf6f710e")
51 !14 = !{}
52 !15 = !{!11}
53 !16 = !DIFile(filename: "", directory: "X3", checksumkind: CSK_MD5, checksum: "f2e6e10e303927a308f1645fbf6f710e")
54 !17 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
55
56
57 @X2 = dso_local global i32 0, align 4, !dbg !21
58
59 !20 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !23, producer: "clang version 7.0.0 (trunk 337353) (llvm/trunk 337361)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !24, globals: !25)
60 !21 = !DIGlobalVariableExpression(var: !22, expr: !DIExpression())
61 !22 = distinct !DIGlobalVariable(name: "X2", scope: !20, file: !26, line: 1, type: !27, isLocal: false, isDefinition: true)
62 !23 = !DIFile(filename: "-", directory: "X2", checksumkind: CSK_MD5, checksum: "f2e6e10e303927a308f1645fbf6f710e")
63 !24 = !{}
64 !25 = !{!21}
65 !26 = !DIFile(filename: "", directory: "X2", checksumkind: CSK_MD5, checksum: "f2e6e10e303927a308f1645fbf6f710e")
66 !27 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
67
68
69 @X3 = dso_local global i32 0, align 4, !dbg !31
70
71 !30 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !33, producer: "clang version 7.0.0 (trunk 337353) (llvm/trunk 337361)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !34, globals: !35)
72 !31 = !DIGlobalVariableExpression(var: !32, expr: !DIExpression())
73 !32 = distinct !DIGlobalVariable(name: "X3", scope: !30, file: !36, line: 1, type: !37, isLocal: false, isDefinition: true)
74 !33 = !DIFile(filename: "-", directory: "X1", checksumkind: CSK_MD5, checksum: "f2e6e10e303927a308f1645fbf6f710e")
75 !34 = !{}
76 !35 = !{!31}
77 !36 = !DIFile(filename: "", directory: "X1", checksumkind: CSK_MD5, checksum: "f2e6e10e303927a308f1645fbf6f710e")
78 !37 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
0 ; REQUIRES: object-emission
11 ; RUN: llc -mtriple=x86_64-unknown-linux-gnu -filetype=obj < %s | llvm-dwarfdump -v - \
22 ; RUN: | FileCheck --check-prefix=MONOLITHIC %s
3 ; RUN: llc -mtriple=x86_64-unknown-linux-gnu -split-dwarf-file=%t.dwo -filetype=obj < %s \
3 ; RUN: llc -mtriple=x86_64-unknown-linux-gnu -split-dwarf-file=foo.dwo -filetype=obj < %s \
44 ; RUN: | llvm-dwarfdump -v - | FileCheck --check-prefix=SPLIT %s
55
66 ; This basic test checks the emission of a DWARF v5 string offsets table in
5858 ; SPLIT: DW_TAG_compile_unit
5959 ; SPLIT-NOT: {{DW_TAG|contents:}}
6060 ; SPLIT: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008)
61 ; SPLIT: DW_AT_GNU_dwo_name [DW_FORM_strx1] ( indexed (00000000) string = "foo.dwo")
62 ; SPLIT: DW_AT_comp_dir [DW_FORM_strx1] ( indexed (00000001) string = "/home/test")
6163
6264 ; Check for the split CU in .debug_info.dwo.
6365 ; SPLIT: .debug_info.dwo contents:
7880 ;
7981 ; Extract the string offsets referenced in the main file by the skeleton unit.
8082 ; SPLIT: .debug_str contents:
81 ; SPLIT-NEXT: 0x00000000:{{.*}}
82 ; SPLIT-NEXT: 0x[[STRING2SPLIT:[0-9a-f]*]]{{.*}}
83 ; SPLIT-NEXT: 0x[[STRING3SPLIT:[0-9a-f]*]]{{.*}}
84 ; SPLIT-NEXT: 0x[[STRING4SPLIT:[0-9a-f]*]]{{.*}}
83 ; SPLIT-NEXT: 0x00000000: "foo.dwo"
84 ; SPLIT-NEXT: 0x[[STRING2SPLIT:[0-9a-f]*]]: "/home/test"
85 ; SPLIT-NEXT: 0x[[STRING3SPLIT:[0-9a-f]*]]: "E"
86 ; SPLIT-NEXT: 0x[[STRING4SPLIT:[0-9a-f]*]]: "glob"
8587 ;
8688 ; Extract the string offsets referenced in the .dwo file by the split unit.
8789 ; SPLIT: .debug_str.dwo contents:
9092 ; SPLIT-NEXT: 0x[[STRING3DWO:[0-9a-f]*]]{{.*}}
9193 ;
9294 ; Check the string offsets sections in both the main and the .dwo files and
93 ; verify that the extracted string offsets are referenced correctly.
95 ; verify that the extracted string offsets are referenced correctly. The
96 ; sections should contain only the offsets of strings that are actually
97 ; referenced by the debug info.
9498 ; SPLIT: .debug_str_offsets contents:
95 ; SPLIT-NEXT: 0x00000000: Contribution size = 20, Format = DWARF32, Version = 5
96 ; SPLIT-NEXT: 0x00000008: 00000000{{.*}}
97 ; SPLIT-NEXT: 0x0000000c: [[STRING2SPLIT]]
98 ; SPLIT-NEXT: 0x00000010: [[STRING3SPLIT]]
99 ; SPLIT-NEXT: 0x00000014: [[STRING4SPLIT]]
99 ; SPLIT-NEXT: 0x00000000: Contribution size = 12, Format = DWARF32, Version = 5
100 ; SPLIT-NEXT: 0x00000008: 00000000 "foo.dwo"
101 ; SPLIT-NEXT: 0x0000000c: [[STRING2SPLIT]] "/home/test"
102 ; SPLIT-EMPTY:
103
100104 ; SPLIT: .debug_str_offsets.dwo contents:
101105 ; SPLIT-NEXT: 0x00000000: Contribution size = 36, Format = DWARF32, Version = 5
102106 ; SPLIT-NEXT: 0x00000008: 00000000{{.*}}
189189 /// Emit the debug_str section stored in \p Pool.
190190 void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) {
191191 Asm->OutStreamer->SwitchSection(MOFI->getDwarfStrSection());
192 std::vector Entries = Pool.getEntries();
192 std::vector Entries = Pool.getEntriesForEmission();
193193 for (auto Entry : Entries) {
194 if (Entry.getIndex() == -1U)
195 break;
196194 // Emit the string itself.
197195 Asm->OutStreamer->EmitBytes(Entry.getString());
198196 // Emit a null terminator.
513513 // Reproduce that behavior for now (there is corresponding code in
514514 // transferSymbol).
515515 OutFile << '\0';
516 std::vector Strings = NewStrings.getEntries();
516 std::vector Strings =
517 NewStrings.getEntriesForEmission();
517518 for (auto EntryRef : Strings) {
518 if (EntryRef.getIndex() == -1U)
519 break;
520519 OutFile.write(EntryRef.getString().data(),
521520 EntryRef.getString().size() + 1);
522521 }
1717
1818 auto I = Strings.insert({S, DwarfStringPoolEntry()});
1919 auto &Entry = I.first->second;
20 if (I.second || Entry.Index == -1U) {
20 if (I.second || !Entry.isIndexed()) {
2121 Entry.Index = NumEntries++;
2222 Entry.Offset = CurrentEndOffset;
2323 Entry.Symbol = nullptr;
2424 CurrentEndOffset += S.size() + 1;
2525 }
26 return DwarfStringPoolEntryRef(*I.first);
26 return DwarfStringPoolEntryRef(*I.first, true);
2727 }
2828
2929 StringRef NonRelocatableStringpool::internString(StringRef S) {
30 DwarfStringPoolEntry Entry{nullptr, 0, -1U};
30 DwarfStringPoolEntry Entry{nullptr, 0, DwarfStringPoolEntry::NotIndexed};
3131 auto InsertResult = Strings.insert({S, Entry});
3232 return InsertResult.first->getKey();
3333 }
3434
3535 std::vector
36 NonRelocatableStringpool::getEntries() const {
36 NonRelocatableStringpool::getEntriesForEmission() const {
3737 std::vector Result;
3838 Result.reserve(Strings.size());
3939 for (const auto &E : Strings)
40 Result.emplace_back(E);
40 if (E.getValue().isIndexed())
41 Result.emplace_back(E, true);
4142 llvm::sort(
4243 Result.begin(), Result.end(),
4344 [](const DwarfStringPoolEntryRef A, const DwarfStringPoolEntryRef B) {
5252
5353 uint64_t getSize() { return CurrentEndOffset; }
5454
55 std::vector getEntries() const;
55 /// Return the list of strings to be emitted. This does not contain the
56 /// strings which were added via internString only.
57 std::vector getEntriesForEmission() const;
5658
5759 private:
5860 MapTy Strings;
3030 public:
3131 DIEString getString(StringRef S) {
3232 DwarfStringPoolEntry Entry = {nullptr, 1, 1};
33 return DIEString(
34 DwarfStringPoolEntryRef(*Pool.insert(std::make_pair(S, Entry)).first));
33 return DIEString(DwarfStringPoolEntryRef(
34 *Pool.insert(std::make_pair(S, Entry)).first, Entry.isIndexed()));
3535 }
3636 };
3737
10041004 // addresses.
10051005 typedef uint64_t AddrType;
10061006 TestAddresses<4, AddrType>();
1007 }
1008
1009 TEST(DWARFDebugInfo, TestStringOffsets) {
1010 Triple Triple = getHostTripleForAddrSize(sizeof(void *));
1011 if (!isConfigurationSupported(Triple))
1012 return;
1013
1014 const char *String1 = "Hello";
1015 const char *String2 = "World";
1016
1017 auto ExpectedDG = dwarfgen::Generator::create(Triple, 5);
1018 ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
1019 dwarfgen::Generator *DG = ExpectedDG.get().get();
1020 dwarfgen::CompileUnit &CU = DG->addCompileUnit();
1021 dwarfgen::DIE CUDie = CU.getUnitDIE();
1022
1023 CUDie.addStrOffsetsBaseAttribute();
1024
1025 uint16_t Attr = DW_AT_lo_user;
1026
1027 // Create our strings. First we create a non-indexed reference to String1,
1028 // followed by an indexed String2. Finally, we add an indexed reference to
1029 // String1.
1030 const auto Attr1 = static_cast(Attr++);
1031 CUDie.addAttribute(Attr1, DW_FORM_strp, String1);
1032
1033 const auto Attr2 = static_cast(Attr++);
1034 CUDie.addAttribute(Attr2, DW_FORM_strx, String2);
1035
1036 const auto Attr3 = static_cast(Attr++);
1037 CUDie.addAttribute(Attr3, DW_FORM_strx, String1);
1038
1039 // Generate the DWARF
1040 StringRef FileBytes = DG->generate();
1041 MemoryBufferRef FileBuffer(FileBytes, "dwarf");
1042 auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
1043 ASSERT_TRUE((bool)Obj);
1044 std::unique_ptr DwarfContext = DWARFContext::create(**Obj);
1045 uint32_t NumCUs = DwarfContext->getNumCompileUnits();
1046 ASSERT_EQ(NumCUs, 1u);
1047 DWARFUnit *U = DwarfContext->getUnitAtIndex(0);
1048 auto DieDG = U->getUnitDIE(false);
1049 ASSERT_TRUE(DieDG.isValid());
1050
1051 // Now make sure the string offsets came out properly. Attr2 should have index
1052 // 0 (because it was the first indexed string) even though the string itself
1053 // was added eariler.
1054 auto Extracted1 = toString(DieDG.find(Attr1));
1055 ASSERT_TRUE((bool)Extracted1);
1056 EXPECT_STREQ(String1, *Extracted1);
1057
1058 Optional Form2 = DieDG.find(Attr2);
1059 ASSERT_TRUE((bool)Form2);
1060 EXPECT_EQ(0u, Form2->getRawUValue());
1061 auto Extracted2 = toString(Form2);
1062 ASSERT_TRUE((bool)Extracted2);
1063 EXPECT_STREQ(String2, *Extracted2);
1064
1065 Optional Form3 = DieDG.find(Attr3);
1066 ASSERT_TRUE((bool)Form3);
1067 EXPECT_EQ(1u, Form3->getRawUValue());
1068 auto Extracted3 = toString(Form3);
1069 ASSERT_TRUE((bool)Extracted3);
1070 EXPECT_STREQ(String1, *Extracted3);
1071 }
1072
1073 TEST(DWARFDebugInfo, TestEmptyStringOffsets) {
1074 Triple Triple = getHostTripleForAddrSize(sizeof(void *));
1075 if (!isConfigurationSupported(Triple))
1076 return;
1077
1078 const char *String1 = "Hello";
1079
1080 auto ExpectedDG = dwarfgen::Generator::create(Triple, 5);
1081 ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded());
1082 dwarfgen::Generator *DG = ExpectedDG.get().get();
1083 dwarfgen::CompileUnit &CU = DG->addCompileUnit();
1084 dwarfgen::DIE CUDie = CU.getUnitDIE();
1085
1086 uint16_t Attr = DW_AT_lo_user;
1087
1088 // We shall insert only one string. It will be referenced directly.
1089 const auto Attr1 = static_cast(Attr++);
1090 CUDie.addAttribute(Attr1, DW_FORM_strp, String1);
1091
1092 // Generate the DWARF
1093 StringRef FileBytes = DG->generate();
1094 MemoryBufferRef FileBuffer(FileBytes, "dwarf");
1095 auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
1096 ASSERT_TRUE((bool)Obj);
1097 std::unique_ptr DwarfContext = DWARFContext::create(**Obj);
1098 EXPECT_TRUE(
1099 DwarfContext->getDWARFObj().getStringOffsetSection().Data.empty());
10071100 }
10081101
10091102 TEST(DWARFDebugInfo, TestRelations) {
7070 break;
7171
7272 case DW_FORM_strp:
73 Die->addValue(
74 DG.getAllocator(), static_cast(A), Form,
75 DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String)));
76 break;
77
7378 case DW_FORM_GNU_str_index:
7479 case DW_FORM_strx:
7580 case DW_FORM_strx1:
7681 case DW_FORM_strx2:
7782 case DW_FORM_strx3:
7883 case DW_FORM_strx4:
79 Die->addValue(
80 DG.getAllocator(), static_cast(A), Form,
81 DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String)));
84 Die->addValue(DG.getAllocator(), static_cast(A), Form,
85 DIEString(DG.getStringPool().getIndexedEntry(
86 *DG.getAsmPrinter(), String)));
8287 break;
8388
8489 default: