1 //===- llvm/CodeGen/DwarfStringPool.cpp - Dwarf Debug Framework -----------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "DwarfStringPool.h" 10 #include "llvm/ADT/SmallVector.h" 11 #include "llvm/ADT/StringRef.h" 12 #include "llvm/ADT/Twine.h" 13 #include "llvm/CodeGen/AsmPrinter.h" 14 #include "llvm/MC/MCAsmInfo.h" 15 #include "llvm/MC/MCStreamer.h" 16 #include <cassert> 17 #include <utility> 18 19 using namespace llvm; 20 21 DwarfStringPool::DwarfStringPool(BumpPtrAllocator &A, AsmPrinter &Asm, 22 StringRef Prefix) 23 : Pool(A), Prefix(Prefix), 24 ShouldCreateSymbols(Asm.MAI->doesDwarfUseRelocationsAcrossSections()) {} 25 26 StringMapEntry<DwarfStringPool::EntryTy> & 27 DwarfStringPool::getEntryImpl(AsmPrinter &Asm, StringRef Str) { 28 auto I = Pool.insert(std::make_pair(Str, EntryTy())); 29 auto &Entry = I.first->second; 30 if (I.second) { 31 Entry.Index = EntryTy::NotIndexed; 32 Entry.Offset = NumBytes; 33 Entry.Symbol = ShouldCreateSymbols ? Asm.createTempSymbol(Prefix) : nullptr; 34 35 NumBytes += Str.size() + 1; 36 assert(NumBytes > Entry.Offset && "Unexpected overflow"); 37 } 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); 53 } 54 55 void DwarfStringPool::emitStringOffsetsTableHeader(AsmPrinter &Asm, 56 MCSection *Section, 57 MCSymbol *StartSym) { 58 if (getNumIndexedStrings() == 0) 59 return; 60 Asm.OutStreamer->SwitchSection(Section); 61 unsigned EntrySize = 4; 62 // FIXME: DWARF64 63 // We are emitting the header for a contribution to the string offsets 64 // table. The header consists of an entry with the contribution's 65 // size (not including the size of the length field), the DWARF version and 66 // 2 bytes of padding. 67 Asm.emitInt32(getNumIndexedStrings() * EntrySize + 4); 68 Asm.emitInt16(Asm.getDwarfVersion()); 69 Asm.emitInt16(0); 70 // Define the symbol that marks the start of the contribution. It is 71 // referenced by most unit headers via DW_AT_str_offsets_base. 72 // Split units do not use the attribute. 73 if (StartSym) 74 Asm.OutStreamer->EmitLabel(StartSym); 75 } 76 77 void DwarfStringPool::emit(AsmPrinter &Asm, MCSection *StrSection, 78 MCSection *OffsetSection, bool UseRelativeOffsets) { 79 if (Pool.empty()) 80 return; 81 82 // Start the dwarf str section. 83 Asm.OutStreamer->SwitchSection(StrSection); 84 85 // Get all of the string pool entries and sort them by their offset. 86 SmallVector<const StringMapEntry<EntryTy> *, 64> Entries; 87 Entries.reserve(Pool.size()); 88 89 for (const auto &E : Pool) 90 Entries.push_back(&E); 91 92 llvm::sort(Entries, [](const StringMapEntry<EntryTy> *A, 93 const StringMapEntry<EntryTy> *B) { 94 return A->getValue().Offset < B->getValue().Offset; 95 }); 96 97 for (const auto &Entry : Entries) { 98 assert(ShouldCreateSymbols == static_cast<bool>(Entry->getValue().Symbol) && 99 "Mismatch between setting and entry"); 100 101 // Emit a label for reference from debug information entries. 102 if (ShouldCreateSymbols) 103 Asm.OutStreamer->EmitLabel(Entry->getValue().Symbol); 104 105 // Emit the string itself with a terminating null byte. 106 Asm.OutStreamer->AddComment("string offset=" + 107 Twine(Entry->getValue().Offset)); 108 Asm.OutStreamer->EmitBytes( 109 StringRef(Entry->getKeyData(), Entry->getKeyLength() + 1)); 110 } 111 112 // If we've got an offset section go ahead and emit that now as well. 113 if (OffsetSection) { 114 // Now only take the indexed entries and put them in an array by their ID so 115 // we can emit them in order. 116 Entries.resize(NumIndexedStrings); 117 for (const auto &Entry : Pool) { 118 if (Entry.getValue().isIndexed()) 119 Entries[Entry.getValue().Index] = &Entry; 120 } 121 122 Asm.OutStreamer->SwitchSection(OffsetSection); 123 unsigned size = 4; // FIXME: DWARF64 is 8. 124 for (const auto &Entry : Entries) 125 if (UseRelativeOffsets) 126 Asm.emitDwarfStringOffset(Entry->getValue()); 127 else 128 Asm.OutStreamer->EmitIntValue(Entry->getValue().Offset, size); 129 } 130 } 131