| //===--- lib/CodeGen/DebugLocStream.h - DWARF debug_loc stream --*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCSTREAM_H |
| #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCSTREAM_H |
| |
| #include "ByteStreamer.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/SmallVector.h" |
| |
| namespace llvm { |
| |
| class AsmPrinter; |
| class DbgVariable; |
| class DwarfCompileUnit; |
| class MachineInstr; |
| class MCSymbol; |
| |
| /// Byte stream of .debug_loc entries. |
| /// |
| /// Stores a unified stream of .debug_loc entries. There's \a List for each |
| /// variable/inlined-at pair, and an \a Entry for each \a DebugLocEntry. |
| /// |
| /// FIXME: Do we need all these temp symbols? |
| /// FIXME: Why not output directly to the output stream? |
| class DebugLocStream { |
| public: |
| struct List { |
| DwarfCompileUnit *CU; |
| MCSymbol *Label = nullptr; |
| size_t EntryOffset; |
| List(DwarfCompileUnit *CU, size_t EntryOffset) |
| : CU(CU), EntryOffset(EntryOffset) {} |
| }; |
| struct Entry { |
| const MCSymbol *Begin; |
| const MCSymbol *End; |
| size_t ByteOffset; |
| size_t CommentOffset; |
| }; |
| |
| private: |
| SmallVector<List, 4> Lists; |
| SmallVector<Entry, 32> Entries; |
| SmallString<256> DWARFBytes; |
| std::vector<std::string> Comments; |
| MCSymbol *Sym; |
| |
| /// Only verbose textual output needs comments. This will be set to |
| /// true for that case, and false otherwise. |
| bool GenerateComments; |
| |
| public: |
| DebugLocStream(bool GenerateComments) : GenerateComments(GenerateComments) { } |
| size_t getNumLists() const { return Lists.size(); } |
| const List &getList(size_t LI) const { return Lists[LI]; } |
| ArrayRef<List> getLists() const { return Lists; } |
| MCSymbol *getSym() const { |
| return Sym; |
| } |
| void setSym(MCSymbol *Sym) { |
| this->Sym = Sym; |
| } |
| |
| class ListBuilder; |
| class EntryBuilder; |
| |
| private: |
| /// Start a new .debug_loc entry list. |
| /// |
| /// Start a new .debug_loc entry list. Return the new list's index so it can |
| /// be retrieved later via \a getList(). |
| /// |
| /// Until the next call, \a startEntry() will add entries to this list. |
| size_t startList(DwarfCompileUnit *CU) { |
| size_t LI = Lists.size(); |
| Lists.emplace_back(CU, Entries.size()); |
| return LI; |
| } |
| |
| /// Finalize a .debug_loc entry list. |
| /// |
| /// If there are no entries in this list, delete it outright. Otherwise, |
| /// create a label with \a Asm. |
| /// |
| /// \return false iff the list is deleted. |
| bool finalizeList(AsmPrinter &Asm); |
| |
| /// Start a new .debug_loc entry. |
| /// |
| /// Until the next call, bytes added to the stream will be added to this |
| /// entry. |
| void startEntry(const MCSymbol *BeginSym, const MCSymbol *EndSym) { |
| Entries.push_back({BeginSym, EndSym, DWARFBytes.size(), Comments.size()}); |
| } |
| |
| /// Finalize a .debug_loc entry, deleting if it's empty. |
| void finalizeEntry(); |
| |
| public: |
| BufferByteStreamer getStreamer() { |
| return BufferByteStreamer(DWARFBytes, Comments, GenerateComments); |
| } |
| |
| ArrayRef<Entry> getEntries(const List &L) const { |
| size_t LI = getIndex(L); |
| return makeArrayRef(Entries) |
| .slice(Lists[LI].EntryOffset, getNumEntries(LI)); |
| } |
| |
| ArrayRef<char> getBytes(const Entry &E) const { |
| size_t EI = getIndex(E); |
| return makeArrayRef(DWARFBytes.begin(), DWARFBytes.end()) |
| .slice(Entries[EI].ByteOffset, getNumBytes(EI)); |
| } |
| ArrayRef<std::string> getComments(const Entry &E) const { |
| size_t EI = getIndex(E); |
| return makeArrayRef(Comments) |
| .slice(Entries[EI].CommentOffset, getNumComments(EI)); |
| } |
| |
| private: |
| size_t getIndex(const List &L) const { |
| assert(&Lists.front() <= &L && &L <= &Lists.back() && |
| "Expected valid list"); |
| return &L - &Lists.front(); |
| } |
| size_t getIndex(const Entry &E) const { |
| assert(&Entries.front() <= &E && &E <= &Entries.back() && |
| "Expected valid entry"); |
| return &E - &Entries.front(); |
| } |
| size_t getNumEntries(size_t LI) const { |
| if (LI + 1 == Lists.size()) |
| return Entries.size() - Lists[LI].EntryOffset; |
| return Lists[LI + 1].EntryOffset - Lists[LI].EntryOffset; |
| } |
| size_t getNumBytes(size_t EI) const { |
| if (EI + 1 == Entries.size()) |
| return DWARFBytes.size() - Entries[EI].ByteOffset; |
| return Entries[EI + 1].ByteOffset - Entries[EI].ByteOffset; |
| } |
| size_t getNumComments(size_t EI) const { |
| if (EI + 1 == Entries.size()) |
| return Comments.size() - Entries[EI].CommentOffset; |
| return Entries[EI + 1].CommentOffset - Entries[EI].CommentOffset; |
| } |
| }; |
| |
| /// Builder for DebugLocStream lists. |
| class DebugLocStream::ListBuilder { |
| DebugLocStream &Locs; |
| AsmPrinter &Asm; |
| DbgVariable &V; |
| const MachineInstr &MI; |
| size_t ListIndex; |
| Optional<uint8_t> TagOffset; |
| |
| public: |
| ListBuilder(DebugLocStream &Locs, DwarfCompileUnit &CU, AsmPrinter &Asm, |
| DbgVariable &V, const MachineInstr &MI) |
| : Locs(Locs), Asm(Asm), V(V), MI(MI), ListIndex(Locs.startList(&CU)), |
| TagOffset(None) {} |
| |
| void setTagOffset(uint8_t TO) { |
| TagOffset = TO; |
| } |
| |
| /// Finalize the list. |
| /// |
| /// If the list is empty, delete it. Otherwise, finalize it by creating a |
| /// temp symbol in \a Asm and setting up the \a DbgVariable. |
| ~ListBuilder(); |
| |
| DebugLocStream &getLocs() { return Locs; } |
| }; |
| |
| /// Builder for DebugLocStream entries. |
| class DebugLocStream::EntryBuilder { |
| DebugLocStream &Locs; |
| |
| public: |
| EntryBuilder(ListBuilder &List, const MCSymbol *Begin, const MCSymbol *End) |
| : Locs(List.getLocs()) { |
| Locs.startEntry(Begin, End); |
| } |
| |
| /// Finalize the entry, deleting it if it's empty. |
| ~EntryBuilder() { Locs.finalizeEntry(); } |
| |
| BufferByteStreamer getStreamer() { return Locs.getStreamer(); } |
| }; |
| |
| } // namespace llvm |
| |
| #endif |