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
17namespace llvm {
18
19class AsmPrinter;
20class DbgVariable;
21class DwarfCompileUnit;
22class MachineInstr;
23class 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?
32class DebugLocStream {
33public:
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
52private:
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
62public:
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
71private:
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
103public:
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
125private:
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.
154class DebugLocStream::ListBuilder {
155  DebugLocStream &Locs;
156  AsmPrinter &Asm;
157  DbgVariable &V;
158  const MachineInstr &MI;
159  size_t ListIndex;
160
161public:
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.
176class DebugLocStream::EntryBuilder {
177  DebugLocStream &Locs;
178
179public:
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