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 } 37 return *I.first; 38 } 39 40 DwarfStringPool::EntryRef DwarfStringPool::getEntry(AsmPrinter &Asm, 41 StringRef Str) { 42 auto &MapEntry = getEntryImpl(Asm, Str); 43 return EntryRef(MapEntry, false); 44 } 45 46 DwarfStringPool::EntryRef DwarfStringPool::getIndexedEntry(AsmPrinter &Asm, 47 StringRef Str) { 48 auto &MapEntry = getEntryImpl(Asm, Str); 49 if (!MapEntry.getValue().isIndexed()) 50 MapEntry.getValue().Index = NumIndexedStrings++; 51 return EntryRef(MapEntry, true); 52 } 53 54 void DwarfStringPool::emitStringOffsetsTableHeader(AsmPrinter &Asm, 55 MCSection *Section, 56 MCSymbol *StartSym) { 57 if (getNumIndexedStrings() == 0) 58 return; 59 Asm.OutStreamer->SwitchSection(Section); 60 unsigned EntrySize = Asm.getDwarfOffsetByteSize(); 61 // We are emitting the header for a contribution to the string offsets 62 // table. The header consists of an entry with the contribution's 63 // size (not including the size of the length field), the DWARF version and 64 // 2 bytes of padding. 65 Asm.emitDwarfUnitLength(getNumIndexedStrings() * EntrySize + 4, 66 "Length of String Offsets Set"); 67 Asm.emitInt16(Asm.getDwarfVersion()); 68 Asm.emitInt16(0); 69 // Define the symbol that marks the start of the contribution. It is 70 // referenced by most unit headers via DW_AT_str_offsets_base. 71 // Split units do not use the attribute. 72 if (StartSym) 73 Asm.OutStreamer->emitLabel(StartSym); 74 } 75 76 void DwarfStringPool::emit(AsmPrinter &Asm, MCSection *StrSection, 77 MCSection *OffsetSection, bool UseRelativeOffsets) { 78 if (Pool.empty()) 79 return; 80 81 // Start the dwarf str section. 82 Asm.OutStreamer->SwitchSection(StrSection); 83 84 // Get all of the string pool entries and sort them by their offset. 85 SmallVector<const StringMapEntry<EntryTy> *, 64> Entries; 86 Entries.reserve(Pool.size()); 87 88 for (const auto &E : Pool) 89 Entries.push_back(&E); 90 91 llvm::sort(Entries, [](const StringMapEntry<EntryTy> *A, 92 const StringMapEntry<EntryTy> *B) { 93 return A->getValue().Offset < B->getValue().Offset; 94 }); 95 96 for (const auto &Entry : Entries) { 97 assert(ShouldCreateSymbols == static_cast<bool>(Entry->getValue().Symbol) && 98 "Mismatch between setting and entry"); 99 100 // Emit a label for reference from debug information entries. 101 if (ShouldCreateSymbols) 102 Asm.OutStreamer->emitLabel(Entry->getValue().Symbol); 103 104 // Emit the string itself with a terminating null byte. 105 Asm.OutStreamer->AddComment("string offset=" + 106 Twine(Entry->getValue().Offset)); 107 Asm.OutStreamer->emitBytes( 108 StringRef(Entry->getKeyData(), Entry->getKeyLength() + 1)); 109 } 110 111 // If we've got an offset section go ahead and emit that now as well. 112 if (OffsetSection) { 113 // Now only take the indexed entries and put them in an array by their ID so 114 // we can emit them in order. 115 Entries.resize(NumIndexedStrings); 116 for (const auto &Entry : Pool) { 117 if (Entry.getValue().isIndexed()) 118 Entries[Entry.getValue().Index] = &Entry; 119 } 120 121 Asm.OutStreamer->SwitchSection(OffsetSection); 122 unsigned size = Asm.getDwarfOffsetByteSize(); 123 for (const auto &Entry : Entries) 124 if (UseRelativeOffsets) 125 Asm.emitDwarfStringOffset(Entry->getValue()); 126 else 127 Asm.OutStreamer->emitIntValue(Entry->getValue().Offset, size); 128 } 129 } 130