1044eb2f6SDimitry Andric //===- llvm/CodeGen/DwarfStringPool.cpp - Dwarf Debug Framework -----------===//
25ca98fd9SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ca98fd9SDimitry Andric //
75ca98fd9SDimitry Andric //===----------------------------------------------------------------------===//
85ca98fd9SDimitry Andric
95ca98fd9SDimitry Andric #include "DwarfStringPool.h"
10044eb2f6SDimitry Andric #include "llvm/ADT/SmallVector.h"
11044eb2f6SDimitry Andric #include "llvm/ADT/Twine.h"
125a5ac124SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
135a5ac124SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
145ca98fd9SDimitry Andric #include "llvm/MC/MCStreamer.h"
15044eb2f6SDimitry Andric #include <cassert>
16044eb2f6SDimitry Andric #include <utility>
175ca98fd9SDimitry Andric
185ca98fd9SDimitry Andric using namespace llvm;
195ca98fd9SDimitry Andric
DwarfStringPool(BumpPtrAllocator & A,AsmPrinter & Asm,StringRef Prefix)205a5ac124SDimitry Andric DwarfStringPool::DwarfStringPool(BumpPtrAllocator &A, AsmPrinter &Asm,
215a5ac124SDimitry Andric StringRef Prefix)
225a5ac124SDimitry Andric : Pool(A), Prefix(Prefix),
23e3b55780SDimitry Andric ShouldCreateSymbols(Asm.doesDwarfUseRelocationsAcrossSections()) {}
245a5ac124SDimitry Andric
25d8e91e46SDimitry Andric StringMapEntry<DwarfStringPool::EntryTy> &
getEntryImpl(AsmPrinter & Asm,StringRef Str)26d8e91e46SDimitry Andric DwarfStringPool::getEntryImpl(AsmPrinter &Asm, StringRef Str) {
275a5ac124SDimitry Andric auto I = Pool.insert(std::make_pair(Str, EntryTy()));
285a5ac124SDimitry Andric auto &Entry = I.first->second;
29d8e91e46SDimitry Andric if (I.second) {
30d8e91e46SDimitry Andric Entry.Index = EntryTy::NotIndexed;
315a5ac124SDimitry Andric Entry.Offset = NumBytes;
325a5ac124SDimitry Andric Entry.Symbol = ShouldCreateSymbols ? Asm.createTempSymbol(Prefix) : nullptr;
335a5ac124SDimitry Andric
345a5ac124SDimitry Andric NumBytes += Str.size() + 1;
355ca98fd9SDimitry Andric }
36d8e91e46SDimitry Andric return *I.first;
37d8e91e46SDimitry Andric }
38d8e91e46SDimitry Andric
getEntry(AsmPrinter & Asm,StringRef Str)39d8e91e46SDimitry Andric DwarfStringPool::EntryRef DwarfStringPool::getEntry(AsmPrinter &Asm,
40d8e91e46SDimitry Andric StringRef Str) {
41d8e91e46SDimitry Andric auto &MapEntry = getEntryImpl(Asm, Str);
42145449b1SDimitry Andric return EntryRef(MapEntry);
43d8e91e46SDimitry Andric }
44d8e91e46SDimitry Andric
getIndexedEntry(AsmPrinter & Asm,StringRef Str)45d8e91e46SDimitry Andric DwarfStringPool::EntryRef DwarfStringPool::getIndexedEntry(AsmPrinter &Asm,
46d8e91e46SDimitry Andric StringRef Str) {
47d8e91e46SDimitry Andric auto &MapEntry = getEntryImpl(Asm, Str);
48d8e91e46SDimitry Andric if (!MapEntry.getValue().isIndexed())
49d8e91e46SDimitry Andric MapEntry.getValue().Index = NumIndexedStrings++;
50145449b1SDimitry Andric return EntryRef(MapEntry);
515ca98fd9SDimitry Andric }
525ca98fd9SDimitry Andric
emitStringOffsetsTableHeader(AsmPrinter & Asm,MCSection * Section,MCSymbol * StartSym)53eb11fae6SDimitry Andric void DwarfStringPool::emitStringOffsetsTableHeader(AsmPrinter &Asm,
54eb11fae6SDimitry Andric MCSection *Section,
55eb11fae6SDimitry Andric MCSymbol *StartSym) {
56d8e91e46SDimitry Andric if (getNumIndexedStrings() == 0)
57eb11fae6SDimitry Andric return;
58145449b1SDimitry Andric Asm.OutStreamer->switchSection(Section);
59b60736ecSDimitry Andric unsigned EntrySize = Asm.getDwarfOffsetByteSize();
60eb11fae6SDimitry Andric // We are emitting the header for a contribution to the string offsets
61eb11fae6SDimitry Andric // table. The header consists of an entry with the contribution's
62eb11fae6SDimitry Andric // size (not including the size of the length field), the DWARF version and
63eb11fae6SDimitry Andric // 2 bytes of padding.
64b60736ecSDimitry Andric Asm.emitDwarfUnitLength(getNumIndexedStrings() * EntrySize + 4,
65b60736ecSDimitry Andric "Length of String Offsets Set");
66eb11fae6SDimitry Andric Asm.emitInt16(Asm.getDwarfVersion());
67eb11fae6SDimitry Andric Asm.emitInt16(0);
68eb11fae6SDimitry Andric // Define the symbol that marks the start of the contribution. It is
69eb11fae6SDimitry Andric // referenced by most unit headers via DW_AT_str_offsets_base.
70eb11fae6SDimitry Andric // Split units do not use the attribute.
71eb11fae6SDimitry Andric if (StartSym)
72cfca06d7SDimitry Andric Asm.OutStreamer->emitLabel(StartSym);
73eb11fae6SDimitry Andric }
74eb11fae6SDimitry Andric
emit(AsmPrinter & Asm,MCSection * StrSection,MCSection * OffsetSection,bool UseRelativeOffsets)755a5ac124SDimitry Andric void DwarfStringPool::emit(AsmPrinter &Asm, MCSection *StrSection,
76eb11fae6SDimitry Andric MCSection *OffsetSection, bool UseRelativeOffsets) {
775ca98fd9SDimitry Andric if (Pool.empty())
785ca98fd9SDimitry Andric return;
795ca98fd9SDimitry Andric
805ca98fd9SDimitry Andric // Start the dwarf str section.
81145449b1SDimitry Andric Asm.OutStreamer->switchSection(StrSection);
825ca98fd9SDimitry Andric
83d8e91e46SDimitry Andric // Get all of the string pool entries and sort them by their offset.
84d8e91e46SDimitry Andric SmallVector<const StringMapEntry<EntryTy> *, 64> Entries;
85d8e91e46SDimitry Andric Entries.reserve(Pool.size());
865ca98fd9SDimitry Andric
875ca98fd9SDimitry Andric for (const auto &E : Pool)
88d8e91e46SDimitry Andric Entries.push_back(&E);
89d8e91e46SDimitry Andric
90d8e91e46SDimitry Andric llvm::sort(Entries, [](const StringMapEntry<EntryTy> *A,
91d8e91e46SDimitry Andric const StringMapEntry<EntryTy> *B) {
92d8e91e46SDimitry Andric return A->getValue().Offset < B->getValue().Offset;
93d8e91e46SDimitry Andric });
945ca98fd9SDimitry Andric
955ca98fd9SDimitry Andric for (const auto &Entry : Entries) {
965a5ac124SDimitry Andric assert(ShouldCreateSymbols == static_cast<bool>(Entry->getValue().Symbol) &&
975a5ac124SDimitry Andric "Mismatch between setting and entry");
985a5ac124SDimitry Andric
995ca98fd9SDimitry Andric // Emit a label for reference from debug information entries.
1005a5ac124SDimitry Andric if (ShouldCreateSymbols)
101cfca06d7SDimitry Andric Asm.OutStreamer->emitLabel(Entry->getValue().Symbol);
1025ca98fd9SDimitry Andric
1035ca98fd9SDimitry Andric // Emit the string itself with a terminating null byte.
1045a5ac124SDimitry Andric Asm.OutStreamer->AddComment("string offset=" +
1055a5ac124SDimitry Andric Twine(Entry->getValue().Offset));
106cfca06d7SDimitry Andric Asm.OutStreamer->emitBytes(
1075ca98fd9SDimitry Andric StringRef(Entry->getKeyData(), Entry->getKeyLength() + 1));
1085ca98fd9SDimitry Andric }
1095ca98fd9SDimitry Andric
1105ca98fd9SDimitry Andric // If we've got an offset section go ahead and emit that now as well.
1115ca98fd9SDimitry Andric if (OffsetSection) {
112d8e91e46SDimitry Andric // Now only take the indexed entries and put them in an array by their ID so
113d8e91e46SDimitry Andric // we can emit them in order.
114d8e91e46SDimitry Andric Entries.resize(NumIndexedStrings);
115d8e91e46SDimitry Andric for (const auto &Entry : Pool) {
116d8e91e46SDimitry Andric if (Entry.getValue().isIndexed())
117d8e91e46SDimitry Andric Entries[Entry.getValue().Index] = &Entry;
118d8e91e46SDimitry Andric }
119d8e91e46SDimitry Andric
120145449b1SDimitry Andric Asm.OutStreamer->switchSection(OffsetSection);
121b60736ecSDimitry Andric unsigned size = Asm.getDwarfOffsetByteSize();
1225a5ac124SDimitry Andric for (const auto &Entry : Entries)
123eb11fae6SDimitry Andric if (UseRelativeOffsets)
124eb11fae6SDimitry Andric Asm.emitDwarfStringOffset(Entry->getValue());
125eb11fae6SDimitry Andric else
126cfca06d7SDimitry Andric Asm.OutStreamer->emitIntValue(Entry->getValue().Offset, size);
1275ca98fd9SDimitry Andric }
1285ca98fd9SDimitry Andric }
129