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; 37 List(DwarfCompileUnit *CU, size_t EntryOffset) 38 : CU(CU), EntryOffset(EntryOffset) {} 39 }; 40 struct Entry { 41 const MCSymbol *BeginSym; 42 const MCSymbol *EndSym; 43 size_t ByteOffset; 44 size_t CommentOffset; 45 Entry(const MCSymbol *BeginSym, const MCSymbol *EndSym, size_t ByteOffset, 46 size_t CommentOffset) 47 : BeginSym(BeginSym), EndSym(EndSym), ByteOffset(ByteOffset), 48 CommentOffset(CommentOffset) {} 49 }; 50 51 private: 52 SmallVector<List, 4> Lists; 53 SmallVector<Entry, 32> Entries; 54 SmallString<256> DWARFBytes; 55 SmallVector<std::string, 32> Comments; 56 57 /// Only verbose textual output needs comments. This will be set to 58 /// true for that case, and false otherwise. 59 bool GenerateComments; 60 61 public: 62 DebugLocStream(bool GenerateComments) : GenerateComments(GenerateComments) { } 63 size_t getNumLists() const { return Lists.size(); } 64 const List &getList(size_t LI) const { return Lists[LI]; } 65 ArrayRef<List> getLists() const { return Lists; } 66 67 class ListBuilder; 68 class EntryBuilder; 69 70 private: 71 /// Start a new .debug_loc entry list. 72 /// 73 /// Start a new .debug_loc entry list. Return the new list's index so it can 74 /// be retrieved later via \a getList(). 75 /// 76 /// Until the next call, \a startEntry() will add entries to this list. 77 size_t startList(DwarfCompileUnit *CU) { 78 size_t LI = Lists.size(); 79 Lists.emplace_back(CU, Entries.size()); 80 return LI; 81 } 82 83 /// Finalize a .debug_loc entry list. 84 /// 85 /// If there are no entries in this list, delete it outright. Otherwise, 86 /// create a label with \a Asm. 87 /// 88 /// \return false iff the list is deleted. 89 bool finalizeList(AsmPrinter &Asm); 90 91 /// Start a new .debug_loc entry. 92 /// 93 /// Until the next call, bytes added to the stream will be added to this 94 /// entry. 95 void startEntry(const MCSymbol *BeginSym, const MCSymbol *EndSym) { 96 Entries.emplace_back(BeginSym, EndSym, DWARFBytes.size(), Comments.size()); 97 } 98 99 /// Finalize a .debug_loc entry, deleting if it's empty. 100 void finalizeEntry(); 101 102 public: 103 BufferByteStreamer getStreamer() { 104 return BufferByteStreamer(DWARFBytes, Comments, GenerateComments); 105 } 106 107 ArrayRef<Entry> getEntries(const List &L) const { 108 size_t LI = getIndex(L); 109 return makeArrayRef(Entries) 110 .slice(Lists[LI].EntryOffset, getNumEntries(LI)); 111 } 112 113 ArrayRef<char> getBytes(const Entry &E) const { 114 size_t EI = getIndex(E); 115 return makeArrayRef(DWARFBytes.begin(), DWARFBytes.end()) 116 .slice(Entries[EI].ByteOffset, getNumBytes(EI)); 117 } 118 ArrayRef<std::string> getComments(const Entry &E) const { 119 size_t EI = getIndex(E); 120 return makeArrayRef(Comments) 121 .slice(Entries[EI].CommentOffset, getNumComments(EI)); 122 } 123 124 private: 125 size_t getIndex(const List &L) const { 126 assert(&Lists.front() <= &L && &L <= &Lists.back() && 127 "Expected valid list"); 128 return &L - &Lists.front(); 129 } 130 size_t getIndex(const Entry &E) const { 131 assert(&Entries.front() <= &E && &E <= &Entries.back() && 132 "Expected valid entry"); 133 return &E - &Entries.front(); 134 } 135 size_t getNumEntries(size_t LI) const { 136 if (LI + 1 == Lists.size()) 137 return Entries.size() - Lists[LI].EntryOffset; 138 return Lists[LI + 1].EntryOffset - Lists[LI].EntryOffset; 139 } 140 size_t getNumBytes(size_t EI) const { 141 if (EI + 1 == Entries.size()) 142 return DWARFBytes.size() - Entries[EI].ByteOffset; 143 return Entries[EI + 1].ByteOffset - Entries[EI].ByteOffset; 144 } 145 size_t getNumComments(size_t EI) const { 146 if (EI + 1 == Entries.size()) 147 return Comments.size() - Entries[EI].CommentOffset; 148 return Entries[EI + 1].CommentOffset - Entries[EI].CommentOffset; 149 } 150 }; 151 152 /// Builder for DebugLocStream lists. 153 class DebugLocStream::ListBuilder { 154 DebugLocStream &Locs; 155 AsmPrinter &Asm; 156 DbgVariable &V; 157 const MachineInstr &MI; 158 size_t ListIndex; 159 160 public: 161 ListBuilder(DebugLocStream &Locs, DwarfCompileUnit &CU, AsmPrinter &Asm, 162 DbgVariable &V, const MachineInstr &MI) 163 : Locs(Locs), Asm(Asm), V(V), MI(MI), ListIndex(Locs.startList(&CU)) {} 164 165 /// Finalize the list. 166 /// 167 /// If the list is empty, delete it. Otherwise, finalize it by creating a 168 /// temp symbol in \a Asm and setting up the \a DbgVariable. 169 ~ListBuilder(); 170 171 DebugLocStream &getLocs() { return Locs; } 172 }; 173 174 /// Builder for DebugLocStream entries. 175 class DebugLocStream::EntryBuilder { 176 DebugLocStream &Locs; 177 178 public: 179 EntryBuilder(ListBuilder &List, const MCSymbol *Begin, const MCSymbol *End) 180 : Locs(List.getLocs()) { 181 Locs.startEntry(Begin, End); 182 } 183 184 /// Finalize the entry, deleting it if it's empty. 185 ~EntryBuilder() { Locs.finalizeEntry(); } 186 187 BufferByteStreamer getStreamer() { return Locs.getStreamer(); } 188 }; 189 190 } // namespace llvm 191 192 #endif 193