10b57cec5SDimitry Andric //===--- lib/CodeGen/DebugLocStream.h - DWARF debug_loc stream --*- C++ -*-===// 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 #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCSTREAM_H 100b57cec5SDimitry Andric #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCSTREAM_H 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include "ByteStreamer.h" 130b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 140b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric namespace llvm { 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric class AsmPrinter; 190b57cec5SDimitry Andric class DbgVariable; 200b57cec5SDimitry Andric class DwarfCompileUnit; 210b57cec5SDimitry Andric class MCSymbol; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric /// Byte stream of .debug_loc entries. 240b57cec5SDimitry Andric /// 250b57cec5SDimitry Andric /// Stores a unified stream of .debug_loc entries. There's \a List for each 260b57cec5SDimitry Andric /// variable/inlined-at pair, and an \a Entry for each \a DebugLocEntry. 270b57cec5SDimitry Andric /// 280b57cec5SDimitry Andric /// FIXME: Do we need all these temp symbols? 290b57cec5SDimitry Andric /// FIXME: Why not output directly to the output stream? 300b57cec5SDimitry Andric class DebugLocStream { 310b57cec5SDimitry Andric public: 320b57cec5SDimitry Andric struct List { 330b57cec5SDimitry Andric DwarfCompileUnit *CU; 340b57cec5SDimitry Andric MCSymbol *Label = nullptr; 350b57cec5SDimitry Andric size_t EntryOffset; ListList360b57cec5SDimitry Andric List(DwarfCompileUnit *CU, size_t EntryOffset) 370b57cec5SDimitry Andric : CU(CU), EntryOffset(EntryOffset) {} 380b57cec5SDimitry Andric }; 390b57cec5SDimitry Andric struct Entry { 408bcb0991SDimitry Andric const MCSymbol *Begin; 418bcb0991SDimitry Andric const MCSymbol *End; 420b57cec5SDimitry Andric size_t ByteOffset; 430b57cec5SDimitry Andric size_t CommentOffset; 440b57cec5SDimitry Andric }; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric private: 470b57cec5SDimitry Andric SmallVector<List, 4> Lists; 480b57cec5SDimitry Andric SmallVector<Entry, 32> Entries; 490b57cec5SDimitry Andric SmallString<256> DWARFBytes; 508bcb0991SDimitry Andric std::vector<std::string> Comments; 5106c3fb27SDimitry Andric MCSymbol *Sym = nullptr; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric /// Only verbose textual output needs comments. This will be set to 540b57cec5SDimitry Andric /// true for that case, and false otherwise. 550b57cec5SDimitry Andric bool GenerateComments; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric public: DebugLocStream(bool GenerateComments)580b57cec5SDimitry Andric DebugLocStream(bool GenerateComments) : GenerateComments(GenerateComments) { } getNumLists()590b57cec5SDimitry Andric size_t getNumLists() const { return Lists.size(); } getList(size_t LI)600b57cec5SDimitry Andric const List &getList(size_t LI) const { return Lists[LI]; } getLists()610b57cec5SDimitry Andric ArrayRef<List> getLists() const { return Lists; } getSym()628bcb0991SDimitry Andric MCSymbol *getSym() const { 638bcb0991SDimitry Andric return Sym; 648bcb0991SDimitry Andric } setSym(MCSymbol * Sym)658bcb0991SDimitry Andric void setSym(MCSymbol *Sym) { 668bcb0991SDimitry Andric this->Sym = Sym; 678bcb0991SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric class ListBuilder; 700b57cec5SDimitry Andric class EntryBuilder; 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric private: 730b57cec5SDimitry Andric /// Start a new .debug_loc entry list. 740b57cec5SDimitry Andric /// 750b57cec5SDimitry Andric /// Start a new .debug_loc entry list. Return the new list's index so it can 760b57cec5SDimitry Andric /// be retrieved later via \a getList(). 770b57cec5SDimitry Andric /// 780b57cec5SDimitry Andric /// Until the next call, \a startEntry() will add entries to this list. startList(DwarfCompileUnit * CU)790b57cec5SDimitry Andric size_t startList(DwarfCompileUnit *CU) { 800b57cec5SDimitry Andric size_t LI = Lists.size(); 810b57cec5SDimitry Andric Lists.emplace_back(CU, Entries.size()); 820b57cec5SDimitry Andric return LI; 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric /// Finalize a .debug_loc entry list. 860b57cec5SDimitry Andric /// 870b57cec5SDimitry Andric /// If there are no entries in this list, delete it outright. Otherwise, 880b57cec5SDimitry Andric /// create a label with \a Asm. 890b57cec5SDimitry Andric /// 900b57cec5SDimitry Andric /// \return false iff the list is deleted. 910b57cec5SDimitry Andric bool finalizeList(AsmPrinter &Asm); 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric /// Start a new .debug_loc entry. 940b57cec5SDimitry Andric /// 950b57cec5SDimitry Andric /// Until the next call, bytes added to the stream will be added to this 960b57cec5SDimitry Andric /// entry. startEntry(const MCSymbol * BeginSym,const MCSymbol * EndSym)970b57cec5SDimitry Andric void startEntry(const MCSymbol *BeginSym, const MCSymbol *EndSym) { 988bcb0991SDimitry Andric Entries.push_back({BeginSym, EndSym, DWARFBytes.size(), Comments.size()}); 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric /// Finalize a .debug_loc entry, deleting if it's empty. 1020b57cec5SDimitry Andric void finalizeEntry(); 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric public: getStreamer()1050b57cec5SDimitry Andric BufferByteStreamer getStreamer() { 1060b57cec5SDimitry Andric return BufferByteStreamer(DWARFBytes, Comments, GenerateComments); 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric getEntries(const List & L)1090b57cec5SDimitry Andric ArrayRef<Entry> getEntries(const List &L) const { 1100b57cec5SDimitry Andric size_t LI = getIndex(L); 111bdd1243dSDimitry Andric return ArrayRef(Entries).slice(Lists[LI].EntryOffset, getNumEntries(LI)); 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric getBytes(const Entry & E)1140b57cec5SDimitry Andric ArrayRef<char> getBytes(const Entry &E) const { 1150b57cec5SDimitry Andric size_t EI = getIndex(E); 116bdd1243dSDimitry Andric return ArrayRef(DWARFBytes.begin(), DWARFBytes.end()) 1170b57cec5SDimitry Andric .slice(Entries[EI].ByteOffset, getNumBytes(EI)); 1180b57cec5SDimitry Andric } getComments(const Entry & E)1190b57cec5SDimitry Andric ArrayRef<std::string> getComments(const Entry &E) const { 1200b57cec5SDimitry Andric size_t EI = getIndex(E); 121bdd1243dSDimitry Andric return ArrayRef(Comments).slice(Entries[EI].CommentOffset, 122bdd1243dSDimitry Andric getNumComments(EI)); 1230b57cec5SDimitry Andric } 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric private: getIndex(const List & L)1260b57cec5SDimitry Andric size_t getIndex(const List &L) const { 1270b57cec5SDimitry Andric assert(&Lists.front() <= &L && &L <= &Lists.back() && 1280b57cec5SDimitry Andric "Expected valid list"); 1290b57cec5SDimitry Andric return &L - &Lists.front(); 1300b57cec5SDimitry Andric } getIndex(const Entry & E)1310b57cec5SDimitry Andric size_t getIndex(const Entry &E) const { 1320b57cec5SDimitry Andric assert(&Entries.front() <= &E && &E <= &Entries.back() && 1330b57cec5SDimitry Andric "Expected valid entry"); 1340b57cec5SDimitry Andric return &E - &Entries.front(); 1350b57cec5SDimitry Andric } getNumEntries(size_t LI)1360b57cec5SDimitry Andric size_t getNumEntries(size_t LI) const { 1370b57cec5SDimitry Andric if (LI + 1 == Lists.size()) 1380b57cec5SDimitry Andric return Entries.size() - Lists[LI].EntryOffset; 1390b57cec5SDimitry Andric return Lists[LI + 1].EntryOffset - Lists[LI].EntryOffset; 1400b57cec5SDimitry Andric } getNumBytes(size_t EI)1410b57cec5SDimitry Andric size_t getNumBytes(size_t EI) const { 1420b57cec5SDimitry Andric if (EI + 1 == Entries.size()) 1430b57cec5SDimitry Andric return DWARFBytes.size() - Entries[EI].ByteOffset; 1440b57cec5SDimitry Andric return Entries[EI + 1].ByteOffset - Entries[EI].ByteOffset; 1450b57cec5SDimitry Andric } getNumComments(size_t EI)1460b57cec5SDimitry Andric size_t getNumComments(size_t EI) const { 1470b57cec5SDimitry Andric if (EI + 1 == Entries.size()) 1480b57cec5SDimitry Andric return Comments.size() - Entries[EI].CommentOffset; 1490b57cec5SDimitry Andric return Entries[EI + 1].CommentOffset - Entries[EI].CommentOffset; 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric }; 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric /// Builder for DebugLocStream lists. 1540b57cec5SDimitry Andric class DebugLocStream::ListBuilder { 1550b57cec5SDimitry Andric DebugLocStream &Locs; 1560b57cec5SDimitry Andric AsmPrinter &Asm; 1570b57cec5SDimitry Andric DbgVariable &V; 1580b57cec5SDimitry Andric size_t ListIndex; 159bdd1243dSDimitry Andric std::optional<uint8_t> TagOffset; 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric public: ListBuilder(DebugLocStream & Locs,DwarfCompileUnit & CU,AsmPrinter & Asm,DbgVariable & V)1620b57cec5SDimitry Andric ListBuilder(DebugLocStream &Locs, DwarfCompileUnit &CU, AsmPrinter &Asm, 163*5f757f3fSDimitry Andric DbgVariable &V) 164*5f757f3fSDimitry Andric : Locs(Locs), Asm(Asm), V(V), ListIndex(Locs.startList(&CU)), 165bdd1243dSDimitry Andric TagOffset(std::nullopt) {} 166480093f4SDimitry Andric setTagOffset(uint8_t TO)167480093f4SDimitry Andric void setTagOffset(uint8_t TO) { 168480093f4SDimitry Andric TagOffset = TO; 169480093f4SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric /// Finalize the list. 1720b57cec5SDimitry Andric /// 1730b57cec5SDimitry Andric /// If the list is empty, delete it. Otherwise, finalize it by creating a 1740b57cec5SDimitry Andric /// temp symbol in \a Asm and setting up the \a DbgVariable. 1750b57cec5SDimitry Andric ~ListBuilder(); 1760b57cec5SDimitry Andric getLocs()1770b57cec5SDimitry Andric DebugLocStream &getLocs() { return Locs; } 1780b57cec5SDimitry Andric }; 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric /// Builder for DebugLocStream entries. 1810b57cec5SDimitry Andric class DebugLocStream::EntryBuilder { 1820b57cec5SDimitry Andric DebugLocStream &Locs; 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric public: EntryBuilder(ListBuilder & List,const MCSymbol * Begin,const MCSymbol * End)1850b57cec5SDimitry Andric EntryBuilder(ListBuilder &List, const MCSymbol *Begin, const MCSymbol *End) 1860b57cec5SDimitry Andric : Locs(List.getLocs()) { 1870b57cec5SDimitry Andric Locs.startEntry(Begin, End); 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric /// Finalize the entry, deleting it if it's empty. ~EntryBuilder()1910b57cec5SDimitry Andric ~EntryBuilder() { Locs.finalizeEntry(); } 1920b57cec5SDimitry Andric getStreamer()1930b57cec5SDimitry Andric BufferByteStreamer getStreamer() { return Locs.getStreamer(); } 1940b57cec5SDimitry Andric }; 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric } // namespace llvm 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric #endif 199