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