1 //===--- lib/CodeGen/DebugLocStream.h - DWARF debug_loc stream --*- C++ -*-===// 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 #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCSTREAM_H 10 #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCSTREAM_H 11 12 #include "ByteStreamer.h" 13 #include "llvm/ADT/ArrayRef.h" 14 #include "llvm/ADT/SmallVector.h" 15 16 namespace llvm { 17 18 class AsmPrinter; 19 class DbgVariable; 20 class DwarfCompileUnit; 21 class MachineInstr; 22 class MCSymbol; 23 24 /// Byte stream of .debug_loc entries. 25 /// 26 /// Stores a unified stream of .debug_loc entries. There's \a List for each 27 /// variable/inlined-at pair, and an \a Entry for each \a DebugLocEntry. 28 /// 29 /// FIXME: Do we need all these temp symbols? 30 /// FIXME: Why not output directly to the output stream? 31 class DebugLocStream { 32 public: 33 struct List { 34 DwarfCompileUnit *CU; 35 MCSymbol *Label = nullptr; 36 size_t EntryOffset; ListList37 List(DwarfCompileUnit *CU, size_t EntryOffset) 38 : CU(CU), EntryOffset(EntryOffset) {} 39 }; 40 struct Entry { 41 const MCSymbol *Begin; 42 const MCSymbol *End; 43 size_t ByteOffset; 44 size_t CommentOffset; 45 }; 46 47 private: 48 SmallVector<List, 4> Lists; 49 SmallVector<Entry, 32> Entries; 50 SmallString<256> DWARFBytes; 51 std::vector<std::string> Comments; 52 MCSymbol *Sym; 53 54 /// Only verbose textual output needs comments. This will be set to 55 /// true for that case, and false otherwise. 56 bool GenerateComments; 57 58 public: DebugLocStream(bool GenerateComments)59 DebugLocStream(bool GenerateComments) : GenerateComments(GenerateComments) { } getNumLists()60 size_t getNumLists() const { return Lists.size(); } getList(size_t LI)61 const List &getList(size_t LI) const { return Lists[LI]; } getLists()62 ArrayRef<List> getLists() const { return Lists; } getSym()63 MCSymbol *getSym() const { 64 return Sym; 65 } setSym(MCSymbol * Sym)66 void setSym(MCSymbol *Sym) { 67 this->Sym = Sym; 68 } 69 70 class ListBuilder; 71 class EntryBuilder; 72 73 private: 74 /// Start a new .debug_loc entry list. 75 /// 76 /// Start a new .debug_loc entry list. Return the new list's index so it can 77 /// be retrieved later via \a getList(). 78 /// 79 /// Until the next call, \a startEntry() will add entries to this list. startList(DwarfCompileUnit * CU)80 size_t startList(DwarfCompileUnit *CU) { 81 size_t LI = Lists.size(); 82 Lists.emplace_back(CU, Entries.size()); 83 return LI; 84 } 85 86 /// Finalize a .debug_loc entry list. 87 /// 88 /// If there are no entries in this list, delete it outright. Otherwise, 89 /// create a label with \a Asm. 90 /// 91 /// \return false iff the list is deleted. 92 bool finalizeList(AsmPrinter &Asm); 93 94 /// Start a new .debug_loc entry. 95 /// 96 /// Until the next call, bytes added to the stream will be added to this 97 /// entry. startEntry(const MCSymbol * BeginSym,const MCSymbol * EndSym)98 void startEntry(const MCSymbol *BeginSym, const MCSymbol *EndSym) { 99 Entries.push_back({BeginSym, EndSym, DWARFBytes.size(), Comments.size()}); 100 } 101 102 /// Finalize a .debug_loc entry, deleting if it's empty. 103 void finalizeEntry(); 104 105 public: getStreamer()106 BufferByteStreamer getStreamer() { 107 return BufferByteStreamer(DWARFBytes, Comments, GenerateComments); 108 } 109 getEntries(const List & L)110 ArrayRef<Entry> getEntries(const List &L) const { 111 size_t LI = getIndex(L); 112 return ArrayRef(Entries).slice(Lists[LI].EntryOffset, getNumEntries(LI)); 113 } 114 getBytes(const Entry & E)115 ArrayRef<char> getBytes(const Entry &E) const { 116 size_t EI = getIndex(E); 117 return ArrayRef(DWARFBytes.begin(), DWARFBytes.end()) 118 .slice(Entries[EI].ByteOffset, getNumBytes(EI)); 119 } getComments(const Entry & E)120 ArrayRef<std::string> getComments(const Entry &E) const { 121 size_t EI = getIndex(E); 122 return ArrayRef(Comments).slice(Entries[EI].CommentOffset, 123 getNumComments(EI)); 124 } 125 126 private: getIndex(const List & L)127 size_t getIndex(const List &L) const { 128 assert(&Lists.front() <= &L && &L <= &Lists.back() && 129 "Expected valid list"); 130 return &L - &Lists.front(); 131 } getIndex(const Entry & E)132 size_t getIndex(const Entry &E) const { 133 assert(&Entries.front() <= &E && &E <= &Entries.back() && 134 "Expected valid entry"); 135 return &E - &Entries.front(); 136 } getNumEntries(size_t LI)137 size_t getNumEntries(size_t LI) const { 138 if (LI + 1 == Lists.size()) 139 return Entries.size() - Lists[LI].EntryOffset; 140 return Lists[LI + 1].EntryOffset - Lists[LI].EntryOffset; 141 } getNumBytes(size_t EI)142 size_t getNumBytes(size_t EI) const { 143 if (EI + 1 == Entries.size()) 144 return DWARFBytes.size() - Entries[EI].ByteOffset; 145 return Entries[EI + 1].ByteOffset - Entries[EI].ByteOffset; 146 } getNumComments(size_t EI)147 size_t getNumComments(size_t EI) const { 148 if (EI + 1 == Entries.size()) 149 return Comments.size() - Entries[EI].CommentOffset; 150 return Entries[EI + 1].CommentOffset - Entries[EI].CommentOffset; 151 } 152 }; 153 154 /// Builder for DebugLocStream lists. 155 class DebugLocStream::ListBuilder { 156 DebugLocStream &Locs; 157 AsmPrinter &Asm; 158 DbgVariable &V; 159 const MachineInstr &MI; 160 size_t ListIndex; 161 std::optional<uint8_t> TagOffset; 162 163 public: ListBuilder(DebugLocStream & Locs,DwarfCompileUnit & CU,AsmPrinter & Asm,DbgVariable & V,const MachineInstr & MI)164 ListBuilder(DebugLocStream &Locs, DwarfCompileUnit &CU, AsmPrinter &Asm, 165 DbgVariable &V, const MachineInstr &MI) 166 : Locs(Locs), Asm(Asm), V(V), MI(MI), ListIndex(Locs.startList(&CU)), 167 TagOffset(std::nullopt) {} 168 setTagOffset(uint8_t TO)169 void setTagOffset(uint8_t TO) { 170 TagOffset = TO; 171 } 172 173 /// Finalize the list. 174 /// 175 /// If the list is empty, delete it. Otherwise, finalize it by creating a 176 /// temp symbol in \a Asm and setting up the \a DbgVariable. 177 ~ListBuilder(); 178 getLocs()179 DebugLocStream &getLocs() { return Locs; } 180 }; 181 182 /// Builder for DebugLocStream entries. 183 class DebugLocStream::EntryBuilder { 184 DebugLocStream &Locs; 185 186 public: EntryBuilder(ListBuilder & List,const MCSymbol * Begin,const MCSymbol * End)187 EntryBuilder(ListBuilder &List, const MCSymbol *Begin, const MCSymbol *End) 188 : Locs(List.getLocs()) { 189 Locs.startEntry(Begin, End); 190 } 191 192 /// Finalize the entry, deleting it if it's empty. ~EntryBuilder()193 ~EntryBuilder() { Locs.finalizeEntry(); } 194 getStreamer()195 BufferByteStreamer getStreamer() { return Locs.getStreamer(); } 196 }; 197 198 } // namespace llvm 199 200 #endif 201