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