10b57cec5SDimitry Andric //===- llvm/CodeGen/DwarfStringPool.cpp - Dwarf Debug Framework -----------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "DwarfStringPool.h" 100b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 110b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 120b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h" 130b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 140b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 150b57cec5SDimitry Andric #include <cassert> 160b57cec5SDimitry Andric #include <utility> 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric using namespace llvm; 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric DwarfStringPool::DwarfStringPool(BumpPtrAllocator &A, AsmPrinter &Asm, 210b57cec5SDimitry Andric StringRef Prefix) 220b57cec5SDimitry Andric : Pool(A), Prefix(Prefix), 230b57cec5SDimitry Andric ShouldCreateSymbols(Asm.MAI->doesDwarfUseRelocationsAcrossSections()) {} 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric StringMapEntry<DwarfStringPool::EntryTy> & 260b57cec5SDimitry Andric DwarfStringPool::getEntryImpl(AsmPrinter &Asm, StringRef Str) { 270b57cec5SDimitry Andric auto I = Pool.insert(std::make_pair(Str, EntryTy())); 280b57cec5SDimitry Andric auto &Entry = I.first->second; 290b57cec5SDimitry Andric if (I.second) { 300b57cec5SDimitry Andric Entry.Index = EntryTy::NotIndexed; 310b57cec5SDimitry Andric Entry.Offset = NumBytes; 320b57cec5SDimitry Andric Entry.Symbol = ShouldCreateSymbols ? Asm.createTempSymbol(Prefix) : nullptr; 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric NumBytes += Str.size() + 1; 350b57cec5SDimitry Andric } 360b57cec5SDimitry Andric return *I.first; 370b57cec5SDimitry Andric } 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric DwarfStringPool::EntryRef DwarfStringPool::getEntry(AsmPrinter &Asm, 400b57cec5SDimitry Andric StringRef Str) { 410b57cec5SDimitry Andric auto &MapEntry = getEntryImpl(Asm, Str); 420b57cec5SDimitry Andric return EntryRef(MapEntry, false); 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric DwarfStringPool::EntryRef DwarfStringPool::getIndexedEntry(AsmPrinter &Asm, 460b57cec5SDimitry Andric StringRef Str) { 470b57cec5SDimitry Andric auto &MapEntry = getEntryImpl(Asm, Str); 480b57cec5SDimitry Andric if (!MapEntry.getValue().isIndexed()) 490b57cec5SDimitry Andric MapEntry.getValue().Index = NumIndexedStrings++; 500b57cec5SDimitry Andric return EntryRef(MapEntry, true); 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric void DwarfStringPool::emitStringOffsetsTableHeader(AsmPrinter &Asm, 540b57cec5SDimitry Andric MCSection *Section, 550b57cec5SDimitry Andric MCSymbol *StartSym) { 560b57cec5SDimitry Andric if (getNumIndexedStrings() == 0) 570b57cec5SDimitry Andric return; 580b57cec5SDimitry Andric Asm.OutStreamer->SwitchSection(Section); 59*e8d8bef9SDimitry Andric unsigned EntrySize = Asm.getDwarfOffsetByteSize(); 600b57cec5SDimitry Andric // We are emitting the header for a contribution to the string offsets 610b57cec5SDimitry Andric // table. The header consists of an entry with the contribution's 620b57cec5SDimitry Andric // size (not including the size of the length field), the DWARF version and 630b57cec5SDimitry Andric // 2 bytes of padding. 64*e8d8bef9SDimitry Andric Asm.emitDwarfUnitLength(getNumIndexedStrings() * EntrySize + 4, 65*e8d8bef9SDimitry Andric "Length of String Offsets Set"); 660b57cec5SDimitry Andric Asm.emitInt16(Asm.getDwarfVersion()); 670b57cec5SDimitry Andric Asm.emitInt16(0); 680b57cec5SDimitry Andric // Define the symbol that marks the start of the contribution. It is 690b57cec5SDimitry Andric // referenced by most unit headers via DW_AT_str_offsets_base. 700b57cec5SDimitry Andric // Split units do not use the attribute. 710b57cec5SDimitry Andric if (StartSym) 725ffd83dbSDimitry Andric Asm.OutStreamer->emitLabel(StartSym); 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric void DwarfStringPool::emit(AsmPrinter &Asm, MCSection *StrSection, 760b57cec5SDimitry Andric MCSection *OffsetSection, bool UseRelativeOffsets) { 770b57cec5SDimitry Andric if (Pool.empty()) 780b57cec5SDimitry Andric return; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric // Start the dwarf str section. 810b57cec5SDimitry Andric Asm.OutStreamer->SwitchSection(StrSection); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric // Get all of the string pool entries and sort them by their offset. 840b57cec5SDimitry Andric SmallVector<const StringMapEntry<EntryTy> *, 64> Entries; 850b57cec5SDimitry Andric Entries.reserve(Pool.size()); 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric for (const auto &E : Pool) 880b57cec5SDimitry Andric Entries.push_back(&E); 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric llvm::sort(Entries, [](const StringMapEntry<EntryTy> *A, 910b57cec5SDimitry Andric const StringMapEntry<EntryTy> *B) { 920b57cec5SDimitry Andric return A->getValue().Offset < B->getValue().Offset; 930b57cec5SDimitry Andric }); 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric for (const auto &Entry : Entries) { 960b57cec5SDimitry Andric assert(ShouldCreateSymbols == static_cast<bool>(Entry->getValue().Symbol) && 970b57cec5SDimitry Andric "Mismatch between setting and entry"); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric // Emit a label for reference from debug information entries. 1000b57cec5SDimitry Andric if (ShouldCreateSymbols) 1015ffd83dbSDimitry Andric Asm.OutStreamer->emitLabel(Entry->getValue().Symbol); 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric // Emit the string itself with a terminating null byte. 1040b57cec5SDimitry Andric Asm.OutStreamer->AddComment("string offset=" + 1050b57cec5SDimitry Andric Twine(Entry->getValue().Offset)); 1065ffd83dbSDimitry Andric Asm.OutStreamer->emitBytes( 1070b57cec5SDimitry Andric StringRef(Entry->getKeyData(), Entry->getKeyLength() + 1)); 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric // If we've got an offset section go ahead and emit that now as well. 1110b57cec5SDimitry Andric if (OffsetSection) { 1120b57cec5SDimitry Andric // Now only take the indexed entries and put them in an array by their ID so 1130b57cec5SDimitry Andric // we can emit them in order. 1140b57cec5SDimitry Andric Entries.resize(NumIndexedStrings); 1150b57cec5SDimitry Andric for (const auto &Entry : Pool) { 1160b57cec5SDimitry Andric if (Entry.getValue().isIndexed()) 1170b57cec5SDimitry Andric Entries[Entry.getValue().Index] = &Entry; 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric Asm.OutStreamer->SwitchSection(OffsetSection); 121*e8d8bef9SDimitry Andric unsigned size = Asm.getDwarfOffsetByteSize(); 1220b57cec5SDimitry Andric for (const auto &Entry : Entries) 1230b57cec5SDimitry Andric if (UseRelativeOffsets) 1240b57cec5SDimitry Andric Asm.emitDwarfStringOffset(Entry->getValue()); 1250b57cec5SDimitry Andric else 1265ffd83dbSDimitry Andric Asm.OutStreamer->emitIntValue(Entry->getValue().Offset, size); 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric } 129