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