| //===- MCDwarf.h - Machine Code Dwarf support -------------------*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains the declaration of the MCDwarfFile to support the dwarf |
| // .file directive and the .loc directive. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_MC_MCDWARF_H |
| #define LLVM_MC_MCDWARF_H |
| |
| #include "llvm/ADT/MapVector.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/MC/StringTableBuilder.h" |
| #include "llvm/Support/Error.h" |
| #include "llvm/Support/MD5.h" |
| #include "llvm/Support/SMLoc.h" |
| #include "llvm/Support/StringSaver.h" |
| #include <cassert> |
| #include <cstdint> |
| #include <optional> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| namespace llvm { |
| |
| template <typename T> class ArrayRef; |
| class MCAsmBackend; |
| class MCContext; |
| class MCObjectStreamer; |
| class MCSection; |
| class MCStreamer; |
| class MCSymbol; |
| class raw_ostream; |
| class SourceMgr; |
| |
| namespace mcdwarf { |
| // Emit the common part of the DWARF 5 range/locations list tables header. |
| MCSymbol *emitListsTableHeaderStart(MCStreamer &S); |
| } // namespace mcdwarf |
| |
| /// Manage the .debug_line_str section contents, if we use it. |
| class MCDwarfLineStr { |
| BumpPtrAllocator Alloc; |
| StringSaver Saver{Alloc}; |
| MCSymbol *LineStrLabel = nullptr; |
| StringTableBuilder LineStrings{StringTableBuilder::DWARF}; |
| bool UseRelocs = false; |
| |
| public: |
| /// Construct an instance that can emit .debug_line_str (for use in a normal |
| /// v5 line table). |
| explicit MCDwarfLineStr(MCContext &Ctx); |
| |
| StringSaver &getSaver() { return Saver; } |
| |
| /// Emit a reference to the string. |
| void emitRef(MCStreamer *MCOS, StringRef Path); |
| |
| /// Emit the .debug_line_str section if appropriate. |
| void emitSection(MCStreamer *MCOS); |
| |
| /// Returns finalized section. |
| SmallString<0> getFinalizedData(); |
| |
| /// Adds path \p Path to the line string. Returns offset in the |
| /// .debug_line_str section. |
| size_t addString(StringRef Path); |
| }; |
| |
| /// Instances of this class represent the name of the dwarf .file directive and |
| /// its associated dwarf file number in the MC file. MCDwarfFile's are created |
| /// and uniqued by the MCContext class. In Dwarf 4 file numbers start from 1; |
| /// i.e. the entry with file number 1 is the first element in the vector of |
| /// DwarfFiles and there is no MCDwarfFile with file number 0. In Dwarf 5 file |
| /// numbers start from 0, with the MCDwarfFile with file number 0 being the |
| /// primary source file, and file numbers correspond to their index in the |
| /// vector. |
| struct MCDwarfFile { |
| // The base name of the file without its directory path. |
| std::string Name; |
| |
| // The index into the list of directory names for this file name. |
| unsigned DirIndex = 0; |
| |
| /// The MD5 checksum, if there is one. Non-owning pointer to data allocated |
| /// in MCContext. |
| std::optional<MD5::MD5Result> Checksum; |
| |
| /// The source code of the file. Non-owning reference to data allocated in |
| /// MCContext. |
| std::optional<StringRef> Source; |
| }; |
| |
| /// Instances of this class represent the information from a |
| /// dwarf .loc directive. |
| class MCDwarfLoc { |
| uint32_t FileNum; |
| uint32_t Line; |
| uint16_t Column; |
| // Flags (see #define's below) |
| uint8_t Flags; |
| uint8_t Isa; |
| uint32_t Discriminator; |
| |
| // Flag that indicates the initial value of the is_stmt_start flag. |
| #define DWARF2_LINE_DEFAULT_IS_STMT 1 |
| |
| #define DWARF2_FLAG_IS_STMT (1 << 0) |
| #define DWARF2_FLAG_BASIC_BLOCK (1 << 1) |
| #define DWARF2_FLAG_PROLOGUE_END (1 << 2) |
| #define DWARF2_FLAG_EPILOGUE_BEGIN (1 << 3) |
| |
| private: // MCContext manages these |
| friend class MCContext; |
| friend class MCDwarfLineEntry; |
| |
| MCDwarfLoc(unsigned fileNum, unsigned line, unsigned column, unsigned flags, |
| unsigned isa, unsigned discriminator) |
| : FileNum(fileNum), Line(line), Column(column), Flags(flags), Isa(isa), |
| Discriminator(discriminator) {} |
| |
| // Allow the default copy constructor and assignment operator to be used |
| // for an MCDwarfLoc object. |
| |
| public: |
| /// Get the FileNum of this MCDwarfLoc. |
| unsigned getFileNum() const { return FileNum; } |
| |
| /// Get the Line of this MCDwarfLoc. |
| unsigned getLine() const { return Line; } |
| |
| /// Get the Column of this MCDwarfLoc. |
| unsigned getColumn() const { return Column; } |
| |
| /// Get the Flags of this MCDwarfLoc. |
| unsigned getFlags() const { return Flags; } |
| |
| /// Get the Isa of this MCDwarfLoc. |
| unsigned getIsa() const { return Isa; } |
| |
| /// Get the Discriminator of this MCDwarfLoc. |
| unsigned getDiscriminator() const { return Discriminator; } |
| |
| /// Set the FileNum of this MCDwarfLoc. |
| void setFileNum(unsigned fileNum) { FileNum = fileNum; } |
| |
| /// Set the Line of this MCDwarfLoc. |
| void setLine(unsigned line) { Line = line; } |
| |
| /// Set the Column of this MCDwarfLoc. |
| void setColumn(unsigned column) { |
| assert(column <= UINT16_MAX); |
| Column = column; |
| } |
| |
| /// Set the Flags of this MCDwarfLoc. |
| void setFlags(unsigned flags) { |
| assert(flags <= UINT8_MAX); |
| Flags = flags; |
| } |
| |
| /// Set the Isa of this MCDwarfLoc. |
| void setIsa(unsigned isa) { |
| assert(isa <= UINT8_MAX); |
| Isa = isa; |
| } |
| |
| /// Set the Discriminator of this MCDwarfLoc. |
| void setDiscriminator(unsigned discriminator) { |
| Discriminator = discriminator; |
| } |
| }; |
| |
| /// Instances of this class represent the line information for |
| /// the dwarf line table entries. Which is created after a machine |
| /// instruction is assembled and uses an address from a temporary label |
| /// created at the current address in the current section and the info from |
| /// the last .loc directive seen as stored in the context. |
| class MCDwarfLineEntry : public MCDwarfLoc { |
| MCSymbol *Label; |
| |
| private: |
| // Allow the default copy constructor and assignment operator to be used |
| // for an MCDwarfLineEntry object. |
| |
| public: |
| // Constructor to create an MCDwarfLineEntry given a symbol and the dwarf loc. |
| MCDwarfLineEntry(MCSymbol *label, const MCDwarfLoc loc) |
| : MCDwarfLoc(loc), Label(label) {} |
| |
| MCSymbol *getLabel() const { return Label; } |
| |
| // This indicates the line entry is synthesized for an end entry. |
| bool IsEndEntry = false; |
| |
| // Override the label with the given EndLabel. |
| void setEndLabel(MCSymbol *EndLabel) { |
| Label = EndLabel; |
| IsEndEntry = true; |
| } |
| |
| // This is called when an instruction is assembled into the specified |
| // section and if there is information from the last .loc directive that |
| // has yet to have a line entry made for it is made. |
| static void make(MCStreamer *MCOS, MCSection *Section); |
| }; |
| |
| /// Instances of this class represent the line information for a compile |
| /// unit where machine instructions have been assembled after seeing .loc |
| /// directives. This is the information used to build the dwarf line |
| /// table for a section. |
| class MCLineSection { |
| public: |
| // Add an entry to this MCLineSection's line entries. |
| void addLineEntry(const MCDwarfLineEntry &LineEntry, MCSection *Sec) { |
| MCLineDivisions[Sec].push_back(LineEntry); |
| } |
| |
| // Add an end entry by cloning the last entry, if exists, for the section |
| // the given EndLabel belongs to. The label is replaced by the given EndLabel. |
| void addEndEntry(MCSymbol *EndLabel); |
| |
| using MCDwarfLineEntryCollection = std::vector<MCDwarfLineEntry>; |
| using iterator = MCDwarfLineEntryCollection::iterator; |
| using const_iterator = MCDwarfLineEntryCollection::const_iterator; |
| using MCLineDivisionMap = MapVector<MCSection *, MCDwarfLineEntryCollection>; |
| |
| private: |
| // A collection of MCDwarfLineEntry for each section. |
| MCLineDivisionMap MCLineDivisions; |
| |
| public: |
| // Returns the collection of MCDwarfLineEntry for a given Compile Unit ID. |
| const MCLineDivisionMap &getMCLineEntries() const { |
| return MCLineDivisions; |
| } |
| }; |
| |
| struct MCDwarfLineTableParams { |
| /// First special line opcode - leave room for the standard opcodes. |
| /// Note: If you want to change this, you'll have to update the |
| /// "StandardOpcodeLengths" table that is emitted in |
| /// \c Emit(). |
| uint8_t DWARF2LineOpcodeBase = 13; |
| /// Minimum line offset in a special line info. opcode. The value |
| /// -5 was chosen to give a reasonable range of values. |
| int8_t DWARF2LineBase = -5; |
| /// Range of line offsets in a special line info. opcode. |
| uint8_t DWARF2LineRange = 14; |
| }; |
| |
| struct MCDwarfLineTableHeader { |
| MCSymbol *Label = nullptr; |
| SmallVector<std::string, 3> MCDwarfDirs; |
| SmallVector<MCDwarfFile, 3> MCDwarfFiles; |
| StringMap<unsigned> SourceIdMap; |
| std::string CompilationDir; |
| MCDwarfFile RootFile; |
| bool HasAnySource = false; |
| |
| private: |
| bool HasAllMD5 = true; |
| bool HasAnyMD5 = false; |
| |
| public: |
| MCDwarfLineTableHeader() = default; |
| |
| Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName, |
| std::optional<MD5::MD5Result> Checksum, |
| std::optional<StringRef> Source, |
| uint16_t DwarfVersion, unsigned FileNumber = 0); |
| std::pair<MCSymbol *, MCSymbol *> |
| Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, |
| std::optional<MCDwarfLineStr> &LineStr) const; |
| std::pair<MCSymbol *, MCSymbol *> |
| Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, |
| ArrayRef<char> SpecialOpcodeLengths, |
| std::optional<MCDwarfLineStr> &LineStr) const; |
| void resetMD5Usage() { |
| HasAllMD5 = true; |
| HasAnyMD5 = false; |
| } |
| void trackMD5Usage(bool MD5Used) { |
| HasAllMD5 &= MD5Used; |
| HasAnyMD5 |= MD5Used; |
| } |
| bool isMD5UsageConsistent() const { |
| return MCDwarfFiles.empty() || (HasAllMD5 == HasAnyMD5); |
| } |
| |
| void setRootFile(StringRef Directory, StringRef FileName, |
| std::optional<MD5::MD5Result> Checksum, |
| std::optional<StringRef> Source) { |
| CompilationDir = std::string(Directory); |
| RootFile.Name = std::string(FileName); |
| RootFile.DirIndex = 0; |
| RootFile.Checksum = Checksum; |
| RootFile.Source = Source; |
| trackMD5Usage(Checksum.has_value()); |
| HasAnySource |= Source.has_value(); |
| } |
| |
| void resetFileTable() { |
| MCDwarfDirs.clear(); |
| MCDwarfFiles.clear(); |
| RootFile.Name.clear(); |
| resetMD5Usage(); |
| HasAnySource = false; |
| } |
| |
| private: |
| void emitV2FileDirTables(MCStreamer *MCOS) const; |
| void emitV5FileDirTables(MCStreamer *MCOS, |
| std::optional<MCDwarfLineStr> &LineStr) const; |
| }; |
| |
| class MCDwarfDwoLineTable { |
| MCDwarfLineTableHeader Header; |
| bool HasSplitLineTable = false; |
| |
| public: |
| void maybeSetRootFile(StringRef Directory, StringRef FileName, |
| std::optional<MD5::MD5Result> Checksum, |
| std::optional<StringRef> Source) { |
| if (!Header.RootFile.Name.empty()) |
| return; |
| Header.setRootFile(Directory, FileName, Checksum, Source); |
| } |
| |
| unsigned getFile(StringRef Directory, StringRef FileName, |
| std::optional<MD5::MD5Result> Checksum, |
| uint16_t DwarfVersion, std::optional<StringRef> Source) { |
| HasSplitLineTable = true; |
| return cantFail(Header.tryGetFile(Directory, FileName, Checksum, Source, |
| DwarfVersion)); |
| } |
| |
| void Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params, |
| MCSection *Section) const; |
| }; |
| |
| class MCDwarfLineTable { |
| MCDwarfLineTableHeader Header; |
| MCLineSection MCLineSections; |
| |
| public: |
| // This emits the Dwarf file and the line tables for all Compile Units. |
| static void emit(MCStreamer *MCOS, MCDwarfLineTableParams Params); |
| |
| // This emits the Dwarf file and the line tables for a given Compile Unit. |
| void emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params, |
| std::optional<MCDwarfLineStr> &LineStr) const; |
| |
| // This emits a single line table associated with a given Section. |
| static void |
| emitOne(MCStreamer *MCOS, MCSection *Section, |
| const MCLineSection::MCDwarfLineEntryCollection &LineEntries); |
| |
| Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName, |
| std::optional<MD5::MD5Result> Checksum, |
| std::optional<StringRef> Source, |
| uint16_t DwarfVersion, unsigned FileNumber = 0); |
| unsigned getFile(StringRef &Directory, StringRef &FileName, |
| std::optional<MD5::MD5Result> Checksum, |
| std::optional<StringRef> Source, uint16_t DwarfVersion, |
| unsigned FileNumber = 0) { |
| return cantFail(tryGetFile(Directory, FileName, Checksum, Source, |
| DwarfVersion, FileNumber)); |
| } |
| |
| void setRootFile(StringRef Directory, StringRef FileName, |
| std::optional<MD5::MD5Result> Checksum, |
| std::optional<StringRef> Source) { |
| Header.CompilationDir = std::string(Directory); |
| Header.RootFile.Name = std::string(FileName); |
| Header.RootFile.DirIndex = 0; |
| Header.RootFile.Checksum = Checksum; |
| Header.RootFile.Source = Source; |
| Header.trackMD5Usage(Checksum.has_value()); |
| Header.HasAnySource |= Source.has_value(); |
| } |
| |
| void resetFileTable() { Header.resetFileTable(); } |
| |
| bool hasRootFile() const { return !Header.RootFile.Name.empty(); } |
| |
| MCDwarfFile &getRootFile() { return Header.RootFile; } |
| const MCDwarfFile &getRootFile() const { return Header.RootFile; } |
| |
| // Report whether MD5 usage has been consistent (all-or-none). |
| bool isMD5UsageConsistent() const { return Header.isMD5UsageConsistent(); } |
| |
| MCSymbol *getLabel() const { |
| return Header.Label; |
| } |
| |
| void setLabel(MCSymbol *Label) { |
| Header.Label = Label; |
| } |
| |
| const SmallVectorImpl<std::string> &getMCDwarfDirs() const { |
| return Header.MCDwarfDirs; |
| } |
| |
| SmallVectorImpl<std::string> &getMCDwarfDirs() { |
| return Header.MCDwarfDirs; |
| } |
| |
| const SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() const { |
| return Header.MCDwarfFiles; |
| } |
| |
| SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() { |
| return Header.MCDwarfFiles; |
| } |
| |
| const MCLineSection &getMCLineSections() const { |
| return MCLineSections; |
| } |
| MCLineSection &getMCLineSections() { |
| return MCLineSections; |
| } |
| }; |
| |
| class MCDwarfLineAddr { |
| public: |
| /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas. |
| static void encode(MCContext &Context, MCDwarfLineTableParams Params, |
| int64_t LineDelta, uint64_t AddrDelta, SmallVectorImpl<char> &OS); |
| |
| /// Utility function to emit the encoding to a streamer. |
| static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, |
| int64_t LineDelta, uint64_t AddrDelta); |
| }; |
| |
| class MCGenDwarfInfo { |
| public: |
| // |
| // When generating dwarf for assembly source files this emits the Dwarf |
| // sections. |
| // |
| static void Emit(MCStreamer *MCOS); |
| }; |
| |
| // When generating dwarf for assembly source files this is the info that is |
| // needed to be gathered for each symbol that will have a dwarf label. |
| class MCGenDwarfLabelEntry { |
| private: |
| // Name of the symbol without a leading underbar, if any. |
| StringRef Name; |
| // The dwarf file number this symbol is in. |
| unsigned FileNumber; |
| // The line number this symbol is at. |
| unsigned LineNumber; |
| // The low_pc for the dwarf label is taken from this symbol. |
| MCSymbol *Label; |
| |
| public: |
| MCGenDwarfLabelEntry(StringRef name, unsigned fileNumber, unsigned lineNumber, |
| MCSymbol *label) |
| : Name(name), FileNumber(fileNumber), LineNumber(lineNumber), |
| Label(label) {} |
| |
| StringRef getName() const { return Name; } |
| unsigned getFileNumber() const { return FileNumber; } |
| unsigned getLineNumber() const { return LineNumber; } |
| MCSymbol *getLabel() const { return Label; } |
| |
| // This is called when label is created when we are generating dwarf for |
| // assembly source files. |
| static void Make(MCSymbol *Symbol, MCStreamer *MCOS, SourceMgr &SrcMgr, |
| SMLoc &Loc); |
| }; |
| |
| class MCCFIInstruction { |
| public: |
| enum OpType { |
| OpSameValue, |
| OpRememberState, |
| OpRestoreState, |
| OpOffset, |
| OpLLVMDefAspaceCfa, |
| OpDefCfaRegister, |
| OpDefCfaOffset, |
| OpDefCfa, |
| OpRelOffset, |
| OpAdjustCfaOffset, |
| OpEscape, |
| OpRestore, |
| OpUndefined, |
| OpRegister, |
| OpWindowSave, |
| OpNegateRAState, |
| OpGnuArgsSize |
| }; |
| |
| private: |
| OpType Operation; |
| MCSymbol *Label; |
| unsigned Register; |
| union { |
| int Offset; |
| unsigned Register2; |
| }; |
| unsigned AddressSpace = ~0u; |
| SMLoc Loc; |
| std::vector<char> Values; |
| std::string Comment; |
| |
| MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, SMLoc Loc, |
| StringRef V = "", StringRef Comment = "") |
| : Operation(Op), Label(L), Register(R), Offset(O), Loc(Loc), |
| Values(V.begin(), V.end()), Comment(Comment) { |
| assert(Op != OpRegister && Op != OpLLVMDefAspaceCfa); |
| } |
| |
| MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2, SMLoc Loc) |
| : Operation(Op), Label(L), Register(R1), Register2(R2), Loc(Loc) { |
| assert(Op == OpRegister); |
| } |
| |
| MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, unsigned AS, |
| SMLoc Loc) |
| : Operation(Op), Label(L), Register(R), Offset(O), AddressSpace(AS), |
| Loc(Loc) { |
| assert(Op == OpLLVMDefAspaceCfa); |
| } |
| |
| public: |
| /// .cfi_def_cfa defines a rule for computing CFA as: take address from |
| /// Register and add Offset to it. |
| static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register, int Offset, |
| SMLoc Loc = {}) { |
| return MCCFIInstruction(OpDefCfa, L, Register, Offset, Loc); |
| } |
| |
| /// .cfi_def_cfa_register modifies a rule for computing CFA. From now |
| /// on Register will be used instead of the old one. Offset remains the same. |
| static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register, |
| SMLoc Loc = {}) { |
| return MCCFIInstruction(OpDefCfaRegister, L, Register, 0, Loc); |
| } |
| |
| /// .cfi_def_cfa_offset modifies a rule for computing CFA. Register |
| /// remains the same, but offset is new. Note that it is the absolute offset |
| /// that will be added to a defined register to the compute CFA address. |
| static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int Offset, |
| SMLoc Loc = {}) { |
| return MCCFIInstruction(OpDefCfaOffset, L, 0, Offset, Loc); |
| } |
| |
| /// .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but |
| /// Offset is a relative value that is added/subtracted from the previous |
| /// offset. |
| static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int Adjustment, |
| SMLoc Loc = {}) { |
| return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, Loc); |
| } |
| |
| // FIXME: Update the remaining docs to use the new proposal wording. |
| /// .cfi_llvm_def_aspace_cfa defines the rule for computing the CFA to |
| /// be the result of evaluating the DWARF operation expression |
| /// `DW_OP_constu AS; DW_OP_aspace_bregx R, B` as a location description. |
| static MCCFIInstruction createLLVMDefAspaceCfa(MCSymbol *L, unsigned Register, |
| int Offset, |
| unsigned AddressSpace, |
| SMLoc Loc) { |
| return MCCFIInstruction(OpLLVMDefAspaceCfa, L, Register, Offset, |
| AddressSpace, Loc); |
| } |
| |
| /// .cfi_offset Previous value of Register is saved at offset Offset |
| /// from CFA. |
| static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register, |
| int Offset, SMLoc Loc = {}) { |
| return MCCFIInstruction(OpOffset, L, Register, Offset, Loc); |
| } |
| |
| /// .cfi_rel_offset Previous value of Register is saved at offset |
| /// Offset from the current CFA register. This is transformed to .cfi_offset |
| /// using the known displacement of the CFA register from the CFA. |
| static MCCFIInstruction createRelOffset(MCSymbol *L, unsigned Register, |
| int Offset, SMLoc Loc = {}) { |
| return MCCFIInstruction(OpRelOffset, L, Register, Offset, Loc); |
| } |
| |
| /// .cfi_register Previous value of Register1 is saved in |
| /// register Register2. |
| static MCCFIInstruction createRegister(MCSymbol *L, unsigned Register1, |
| unsigned Register2, SMLoc Loc = {}) { |
| return MCCFIInstruction(OpRegister, L, Register1, Register2, Loc); |
| } |
| |
| /// .cfi_window_save SPARC register window is saved. |
| static MCCFIInstruction createWindowSave(MCSymbol *L, SMLoc Loc = {}) { |
| return MCCFIInstruction(OpWindowSave, L, 0, 0, Loc); |
| } |
| |
| /// .cfi_negate_ra_state AArch64 negate RA state. |
| static MCCFIInstruction createNegateRAState(MCSymbol *L, SMLoc Loc = {}) { |
| return MCCFIInstruction(OpNegateRAState, L, 0, 0, Loc); |
| } |
| |
| /// .cfi_restore says that the rule for Register is now the same as it |
| /// was at the beginning of the function, after all initial instructions added |
| /// by .cfi_startproc were executed. |
| static MCCFIInstruction createRestore(MCSymbol *L, unsigned Register, |
| SMLoc Loc = {}) { |
| return MCCFIInstruction(OpRestore, L, Register, 0, Loc); |
| } |
| |
| /// .cfi_undefined From now on the previous value of Register can't be |
| /// restored anymore. |
| static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register, |
| SMLoc Loc = {}) { |
| return MCCFIInstruction(OpUndefined, L, Register, 0, Loc); |
| } |
| |
| /// .cfi_same_value Current value of Register is the same as in the |
| /// previous frame. I.e., no restoration is needed. |
| static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register, |
| SMLoc Loc = {}) { |
| return MCCFIInstruction(OpSameValue, L, Register, 0, Loc); |
| } |
| |
| /// .cfi_remember_state Save all current rules for all registers. |
| static MCCFIInstruction createRememberState(MCSymbol *L, SMLoc Loc = {}) { |
| return MCCFIInstruction(OpRememberState, L, 0, 0, Loc); |
| } |
| |
| /// .cfi_restore_state Restore the previously saved state. |
| static MCCFIInstruction createRestoreState(MCSymbol *L, SMLoc Loc = {}) { |
| return MCCFIInstruction(OpRestoreState, L, 0, 0, Loc); |
| } |
| |
| /// .cfi_escape Allows the user to add arbitrary bytes to the unwind |
| /// info. |
| static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals, |
| SMLoc Loc = {}, StringRef Comment = "") { |
| return MCCFIInstruction(OpEscape, L, 0, 0, Loc, Vals, Comment); |
| } |
| |
| /// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE |
| static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int Size, |
| SMLoc Loc = {}) { |
| return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, Loc); |
| } |
| |
| OpType getOperation() const { return Operation; } |
| MCSymbol *getLabel() const { return Label; } |
| |
| unsigned getRegister() const { |
| assert(Operation == OpDefCfa || Operation == OpOffset || |
| Operation == OpRestore || Operation == OpUndefined || |
| Operation == OpSameValue || Operation == OpDefCfaRegister || |
| Operation == OpRelOffset || Operation == OpRegister || |
| Operation == OpLLVMDefAspaceCfa); |
| return Register; |
| } |
| |
| unsigned getRegister2() const { |
| assert(Operation == OpRegister); |
| return Register2; |
| } |
| |
| unsigned getAddressSpace() const { |
| assert(Operation == OpLLVMDefAspaceCfa); |
| return AddressSpace; |
| } |
| |
| int getOffset() const { |
| assert(Operation == OpDefCfa || Operation == OpOffset || |
| Operation == OpRelOffset || Operation == OpDefCfaOffset || |
| Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize || |
| Operation == OpLLVMDefAspaceCfa); |
| return Offset; |
| } |
| |
| StringRef getValues() const { |
| assert(Operation == OpEscape); |
| return StringRef(&Values[0], Values.size()); |
| } |
| |
| StringRef getComment() const { return Comment; } |
| SMLoc getLoc() const { return Loc; } |
| }; |
| |
| struct MCDwarfFrameInfo { |
| MCDwarfFrameInfo() = default; |
| |
| MCSymbol *Begin = nullptr; |
| MCSymbol *End = nullptr; |
| const MCSymbol *Personality = nullptr; |
| const MCSymbol *Lsda = nullptr; |
| std::vector<MCCFIInstruction> Instructions; |
| unsigned CurrentCfaRegister = 0; |
| unsigned PersonalityEncoding = 0; |
| unsigned LsdaEncoding = 0; |
| uint32_t CompactUnwindEncoding = 0; |
| bool IsSignalFrame = false; |
| bool IsSimple = false; |
| unsigned RAReg = static_cast<unsigned>(INT_MAX); |
| bool IsBKeyFrame = false; |
| bool IsMTETaggedFrame = false; |
| }; |
| |
| class MCDwarfFrameEmitter { |
| public: |
| // |
| // This emits the frame info section. |
| // |
| static void Emit(MCObjectStreamer &streamer, MCAsmBackend *MAB, bool isEH); |
| static void encodeAdvanceLoc(MCContext &Context, uint64_t AddrDelta, |
| SmallVectorImpl<char> &OS); |
| }; |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_MC_MCDWARF_H |