1 //===- MCDwarf.h - Machine Code Dwarf support -------------------*- 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 // This file contains the declaration of the MCDwarfFile to support the dwarf
10 // .file directive and the .loc directive.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_MC_MCDWARF_H
15 #define LLVM_MC_MCDWARF_H
16 
17 #include "llvm/ADT/MapVector.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringMap.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/MC/StringTableBuilder.h"
22 #include "llvm/Support/Error.h"
23 #include "llvm/Support/MD5.h"
24 #include "llvm/Support/StringSaver.h"
25 #include <cassert>
26 #include <cstdint>
27 #include <optional>
28 #include <string>
29 #include <utility>
30 #include <vector>
31 
32 namespace llvm {
33 
34 template <typename T> class ArrayRef;
35 class MCAsmBackend;
36 class MCContext;
37 class MCObjectStreamer;
38 class MCSection;
39 class MCStreamer;
40 class MCSymbol;
41 class raw_ostream;
42 class SMLoc;
43 class SourceMgr;
44 
45 namespace mcdwarf {
46 // Emit the common part of the DWARF 5 range/locations list tables header.
47 MCSymbol *emitListsTableHeaderStart(MCStreamer &S);
48 } // namespace mcdwarf
49 
50 /// Manage the .debug_line_str section contents, if we use it.
51 class MCDwarfLineStr {
52   BumpPtrAllocator Alloc;
53   StringSaver Saver{Alloc};
54   MCSymbol *LineStrLabel = nullptr;
55   StringTableBuilder LineStrings{StringTableBuilder::DWARF};
56   bool UseRelocs = false;
57 
58 public:
59   /// Construct an instance that can emit .debug_line_str (for use in a normal
60   /// v5 line table).
61   explicit MCDwarfLineStr(MCContext &Ctx);
62 
63   StringSaver &getSaver() { return Saver; }
64 
65   /// Emit a reference to the string.
66   void emitRef(MCStreamer *MCOS, StringRef Path);
67 
68   /// Emit the .debug_line_str section if appropriate.
69   void emitSection(MCStreamer *MCOS);
70 
71   /// Returns finalized section.
72   SmallString<0> getFinalizedData();
73 };
74 
75 /// Instances of this class represent the name of the dwarf .file directive and
76 /// its associated dwarf file number in the MC file. MCDwarfFile's are created
77 /// and uniqued by the MCContext class. In Dwarf 4 file numbers start from 1;
78 /// i.e. the entry with file number 1 is the first element in the vector of
79 /// DwarfFiles and there is no MCDwarfFile with file number 0. In Dwarf 5 file
80 /// numbers start from 0, with the MCDwarfFile with file number 0 being the
81 /// primary source file, and file numbers correspond to their index in the
82 /// vector.
83 struct MCDwarfFile {
84   // The base name of the file without its directory path.
85   std::string Name;
86 
87   // The index into the list of directory names for this file name.
88   unsigned DirIndex = 0;
89 
90   /// The MD5 checksum, if there is one. Non-owning pointer to data allocated
91   /// in MCContext.
92   std::optional<MD5::MD5Result> Checksum;
93 
94   /// The source code of the file. Non-owning reference to data allocated in
95   /// MCContext.
96   std::optional<StringRef> Source;
97 };
98 
99 /// Instances of this class represent the information from a
100 /// dwarf .loc directive.
101 class MCDwarfLoc {
102   uint32_t FileNum;
103   uint32_t Line;
104   uint16_t Column;
105   // Flags (see #define's below)
106   uint8_t Flags;
107   uint8_t Isa;
108   uint32_t Discriminator;
109 
110 // Flag that indicates the initial value of the is_stmt_start flag.
111 #define DWARF2_LINE_DEFAULT_IS_STMT 1
112 
113 #define DWARF2_FLAG_IS_STMT (1 << 0)
114 #define DWARF2_FLAG_BASIC_BLOCK (1 << 1)
115 #define DWARF2_FLAG_PROLOGUE_END (1 << 2)
116 #define DWARF2_FLAG_EPILOGUE_BEGIN (1 << 3)
117 
118 private: // MCContext manages these
119   friend class MCContext;
120   friend class MCDwarfLineEntry;
121 
122   MCDwarfLoc(unsigned fileNum, unsigned line, unsigned column, unsigned flags,
123              unsigned isa, unsigned discriminator)
124       : FileNum(fileNum), Line(line), Column(column), Flags(flags), Isa(isa),
125         Discriminator(discriminator) {}
126 
127   // Allow the default copy constructor and assignment operator to be used
128   // for an MCDwarfLoc object.
129 
130 public:
131   /// Get the FileNum of this MCDwarfLoc.
132   unsigned getFileNum() const { return FileNum; }
133 
134   /// Get the Line of this MCDwarfLoc.
135   unsigned getLine() const { return Line; }
136 
137   /// Get the Column of this MCDwarfLoc.
138   unsigned getColumn() const { return Column; }
139 
140   /// Get the Flags of this MCDwarfLoc.
141   unsigned getFlags() const { return Flags; }
142 
143   /// Get the Isa of this MCDwarfLoc.
144   unsigned getIsa() const { return Isa; }
145 
146   /// Get the Discriminator of this MCDwarfLoc.
147   unsigned getDiscriminator() const { return Discriminator; }
148 
149   /// Set the FileNum of this MCDwarfLoc.
150   void setFileNum(unsigned fileNum) { FileNum = fileNum; }
151 
152   /// Set the Line of this MCDwarfLoc.
153   void setLine(unsigned line) { Line = line; }
154 
155   /// Set the Column of this MCDwarfLoc.
156   void setColumn(unsigned column) {
157     assert(column <= UINT16_MAX);
158     Column = column;
159   }
160 
161   /// Set the Flags of this MCDwarfLoc.
162   void setFlags(unsigned flags) {
163     assert(flags <= UINT8_MAX);
164     Flags = flags;
165   }
166 
167   /// Set the Isa of this MCDwarfLoc.
168   void setIsa(unsigned isa) {
169     assert(isa <= UINT8_MAX);
170     Isa = isa;
171   }
172 
173   /// Set the Discriminator of this MCDwarfLoc.
174   void setDiscriminator(unsigned discriminator) {
175     Discriminator = discriminator;
176   }
177 };
178 
179 /// Instances of this class represent the line information for
180 /// the dwarf line table entries.  Which is created after a machine
181 /// instruction is assembled and uses an address from a temporary label
182 /// created at the current address in the current section and the info from
183 /// the last .loc directive seen as stored in the context.
184 class MCDwarfLineEntry : public MCDwarfLoc {
185   MCSymbol *Label;
186 
187 private:
188   // Allow the default copy constructor and assignment operator to be used
189   // for an MCDwarfLineEntry object.
190 
191 public:
192   // Constructor to create an MCDwarfLineEntry given a symbol and the dwarf loc.
193   MCDwarfLineEntry(MCSymbol *label, const MCDwarfLoc loc)
194       : MCDwarfLoc(loc), Label(label) {}
195 
196   MCSymbol *getLabel() const { return Label; }
197 
198   // This indicates the line entry is synthesized for an end entry.
199   bool IsEndEntry = false;
200 
201   // Override the label with the given EndLabel.
202   void setEndLabel(MCSymbol *EndLabel) {
203     Label = EndLabel;
204     IsEndEntry = true;
205   }
206 
207   // This is called when an instruction is assembled into the specified
208   // section and if there is information from the last .loc directive that
209   // has yet to have a line entry made for it is made.
210   static void make(MCStreamer *MCOS, MCSection *Section);
211 };
212 
213 /// Instances of this class represent the line information for a compile
214 /// unit where machine instructions have been assembled after seeing .loc
215 /// directives.  This is the information used to build the dwarf line
216 /// table for a section.
217 class MCLineSection {
218 public:
219   // Add an entry to this MCLineSection's line entries.
220   void addLineEntry(const MCDwarfLineEntry &LineEntry, MCSection *Sec) {
221     MCLineDivisions[Sec].push_back(LineEntry);
222   }
223 
224   // Add an end entry by cloning the last entry, if exists, for the section
225   // the given EndLabel belongs to. The label is replaced by the given EndLabel.
226   void addEndEntry(MCSymbol *EndLabel);
227 
228   using MCDwarfLineEntryCollection = std::vector<MCDwarfLineEntry>;
229   using iterator = MCDwarfLineEntryCollection::iterator;
230   using const_iterator = MCDwarfLineEntryCollection::const_iterator;
231   using MCLineDivisionMap = MapVector<MCSection *, MCDwarfLineEntryCollection>;
232 
233 private:
234   // A collection of MCDwarfLineEntry for each section.
235   MCLineDivisionMap MCLineDivisions;
236 
237 public:
238   // Returns the collection of MCDwarfLineEntry for a given Compile Unit ID.
239   const MCLineDivisionMap &getMCLineEntries() const {
240     return MCLineDivisions;
241   }
242 };
243 
244 struct MCDwarfLineTableParams {
245   /// First special line opcode - leave room for the standard opcodes.
246   /// Note: If you want to change this, you'll have to update the
247   /// "StandardOpcodeLengths" table that is emitted in
248   /// \c Emit().
249   uint8_t DWARF2LineOpcodeBase = 13;
250   /// Minimum line offset in a special line info. opcode.  The value
251   /// -5 was chosen to give a reasonable range of values.
252   int8_t DWARF2LineBase = -5;
253   /// Range of line offsets in a special line info. opcode.
254   uint8_t DWARF2LineRange = 14;
255 };
256 
257 struct MCDwarfLineTableHeader {
258   MCSymbol *Label = nullptr;
259   SmallVector<std::string, 3> MCDwarfDirs;
260   SmallVector<MCDwarfFile, 3> MCDwarfFiles;
261   StringMap<unsigned> SourceIdMap;
262   std::string CompilationDir;
263   MCDwarfFile RootFile;
264   bool HasSource = false;
265 private:
266   bool HasAllMD5 = true;
267   bool HasAnyMD5 = false;
268 
269 public:
270   MCDwarfLineTableHeader() = default;
271 
272   Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
273                                 std::optional<MD5::MD5Result> Checksum,
274                                 std::optional<StringRef> Source,
275                                 uint16_t DwarfVersion, unsigned FileNumber = 0);
276   std::pair<MCSymbol *, MCSymbol *>
277   Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
278        std::optional<MCDwarfLineStr> &LineStr) const;
279   std::pair<MCSymbol *, MCSymbol *>
280   Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
281        ArrayRef<char> SpecialOpcodeLengths,
282        std::optional<MCDwarfLineStr> &LineStr) const;
283   void resetMD5Usage() {
284     HasAllMD5 = true;
285     HasAnyMD5 = false;
286   }
287   void trackMD5Usage(bool MD5Used) {
288     HasAllMD5 &= MD5Used;
289     HasAnyMD5 |= MD5Used;
290   }
291   bool isMD5UsageConsistent() const {
292     return MCDwarfFiles.empty() || (HasAllMD5 == HasAnyMD5);
293   }
294 
295   void setRootFile(StringRef Directory, StringRef FileName,
296                    std::optional<MD5::MD5Result> Checksum,
297                    std::optional<StringRef> Source) {
298     CompilationDir = std::string(Directory);
299     RootFile.Name = std::string(FileName);
300     RootFile.DirIndex = 0;
301     RootFile.Checksum = Checksum;
302     RootFile.Source = Source;
303     trackMD5Usage(Checksum.has_value());
304     HasSource = Source.has_value();
305   }
306 
307   void resetFileTable() {
308     MCDwarfDirs.clear();
309     MCDwarfFiles.clear();
310     RootFile.Name.clear();
311     resetMD5Usage();
312     HasSource = false;
313   }
314 
315 private:
316   void emitV2FileDirTables(MCStreamer *MCOS) const;
317   void emitV5FileDirTables(MCStreamer *MCOS,
318                            std::optional<MCDwarfLineStr> &LineStr) const;
319 };
320 
321 class MCDwarfDwoLineTable {
322   MCDwarfLineTableHeader Header;
323   bool HasSplitLineTable = false;
324 
325 public:
326   void maybeSetRootFile(StringRef Directory, StringRef FileName,
327                         std::optional<MD5::MD5Result> Checksum,
328                         std::optional<StringRef> Source) {
329     if (!Header.RootFile.Name.empty())
330       return;
331     Header.setRootFile(Directory, FileName, Checksum, Source);
332   }
333 
334   unsigned getFile(StringRef Directory, StringRef FileName,
335                    std::optional<MD5::MD5Result> Checksum,
336                    uint16_t DwarfVersion, std::optional<StringRef> Source) {
337     HasSplitLineTable = true;
338     return cantFail(Header.tryGetFile(Directory, FileName, Checksum, Source,
339                                       DwarfVersion));
340   }
341 
342   void Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params,
343             MCSection *Section) const;
344 };
345 
346 class MCDwarfLineTable {
347   MCDwarfLineTableHeader Header;
348   MCLineSection MCLineSections;
349 
350 public:
351   // This emits the Dwarf file and the line tables for all Compile Units.
352   static void emit(MCStreamer *MCOS, MCDwarfLineTableParams Params);
353 
354   // This emits the Dwarf file and the line tables for a given Compile Unit.
355   void emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
356               std::optional<MCDwarfLineStr> &LineStr) const;
357 
358   // This emits a single line table associated with a given Section.
359   static void
360   emitOne(MCStreamer *MCOS, MCSection *Section,
361           const MCLineSection::MCDwarfLineEntryCollection &LineEntries);
362 
363   Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
364                                 std::optional<MD5::MD5Result> Checksum,
365                                 std::optional<StringRef> Source,
366                                 uint16_t DwarfVersion, unsigned FileNumber = 0);
367   unsigned getFile(StringRef &Directory, StringRef &FileName,
368                    std::optional<MD5::MD5Result> Checksum,
369                    std::optional<StringRef> Source, uint16_t DwarfVersion,
370                    unsigned FileNumber = 0) {
371     return cantFail(tryGetFile(Directory, FileName, Checksum, Source,
372                                DwarfVersion, FileNumber));
373   }
374 
375   void setRootFile(StringRef Directory, StringRef FileName,
376                    std::optional<MD5::MD5Result> Checksum,
377                    std::optional<StringRef> Source) {
378     Header.CompilationDir = std::string(Directory);
379     Header.RootFile.Name = std::string(FileName);
380     Header.RootFile.DirIndex = 0;
381     Header.RootFile.Checksum = Checksum;
382     Header.RootFile.Source = Source;
383     Header.trackMD5Usage(Checksum.has_value());
384     Header.HasSource = Source.has_value();
385   }
386 
387   void resetFileTable() { Header.resetFileTable(); }
388 
389   bool hasRootFile() const { return !Header.RootFile.Name.empty(); }
390 
391   MCDwarfFile &getRootFile() { return Header.RootFile; }
392   const MCDwarfFile &getRootFile() const { return Header.RootFile; }
393 
394   // Report whether MD5 usage has been consistent (all-or-none).
395   bool isMD5UsageConsistent() const { return Header.isMD5UsageConsistent(); }
396 
397   MCSymbol *getLabel() const {
398     return Header.Label;
399   }
400 
401   void setLabel(MCSymbol *Label) {
402     Header.Label = Label;
403   }
404 
405   const SmallVectorImpl<std::string> &getMCDwarfDirs() const {
406     return Header.MCDwarfDirs;
407   }
408 
409   SmallVectorImpl<std::string> &getMCDwarfDirs() {
410     return Header.MCDwarfDirs;
411   }
412 
413   const SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() const {
414     return Header.MCDwarfFiles;
415   }
416 
417   SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() {
418     return Header.MCDwarfFiles;
419   }
420 
421   const MCLineSection &getMCLineSections() const {
422     return MCLineSections;
423   }
424   MCLineSection &getMCLineSections() {
425     return MCLineSections;
426   }
427 };
428 
429 class MCDwarfLineAddr {
430 public:
431   /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas.
432   static void Encode(MCContext &Context, MCDwarfLineTableParams Params,
433                      int64_t LineDelta, uint64_t AddrDelta, raw_ostream &OS);
434 
435   /// Utility function to emit the encoding to a streamer.
436   static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
437                    int64_t LineDelta, uint64_t AddrDelta);
438 };
439 
440 class MCGenDwarfInfo {
441 public:
442   //
443   // When generating dwarf for assembly source files this emits the Dwarf
444   // sections.
445   //
446   static void Emit(MCStreamer *MCOS);
447 };
448 
449 // When generating dwarf for assembly source files this is the info that is
450 // needed to be gathered for each symbol that will have a dwarf label.
451 class MCGenDwarfLabelEntry {
452 private:
453   // Name of the symbol without a leading underbar, if any.
454   StringRef Name;
455   // The dwarf file number this symbol is in.
456   unsigned FileNumber;
457   // The line number this symbol is at.
458   unsigned LineNumber;
459   // The low_pc for the dwarf label is taken from this symbol.
460   MCSymbol *Label;
461 
462 public:
463   MCGenDwarfLabelEntry(StringRef name, unsigned fileNumber, unsigned lineNumber,
464                        MCSymbol *label)
465       : Name(name), FileNumber(fileNumber), LineNumber(lineNumber),
466         Label(label) {}
467 
468   StringRef getName() const { return Name; }
469   unsigned getFileNumber() const { return FileNumber; }
470   unsigned getLineNumber() const { return LineNumber; }
471   MCSymbol *getLabel() const { return Label; }
472 
473   // This is called when label is created when we are generating dwarf for
474   // assembly source files.
475   static void Make(MCSymbol *Symbol, MCStreamer *MCOS, SourceMgr &SrcMgr,
476                    SMLoc &Loc);
477 };
478 
479 class MCCFIInstruction {
480 public:
481   enum OpType {
482     OpSameValue,
483     OpRememberState,
484     OpRestoreState,
485     OpOffset,
486     OpLLVMDefAspaceCfa,
487     OpDefCfaRegister,
488     OpDefCfaOffset,
489     OpDefCfa,
490     OpRelOffset,
491     OpAdjustCfaOffset,
492     OpEscape,
493     OpRestore,
494     OpUndefined,
495     OpRegister,
496     OpWindowSave,
497     OpNegateRAState,
498     OpGnuArgsSize
499   };
500 
501 private:
502   OpType Operation;
503   MCSymbol *Label;
504   unsigned Register;
505   union {
506     int Offset;
507     unsigned Register2;
508   };
509   unsigned AddressSpace;
510   std::vector<char> Values;
511   std::string Comment;
512 
513   MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, StringRef V,
514                    StringRef Comment = "")
515       : Operation(Op), Label(L), Register(R), Offset(O),
516         Values(V.begin(), V.end()), Comment(Comment) {
517     assert(Op != OpRegister && Op != OpLLVMDefAspaceCfa);
518   }
519 
520   MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2)
521       : Operation(Op), Label(L), Register(R1), Register2(R2) {
522     assert(Op == OpRegister);
523   }
524 
525   MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, unsigned AS)
526       : Operation(Op), Label(L), Register(R), Offset(O), AddressSpace(AS) {
527     assert(Op == OpLLVMDefAspaceCfa);
528   }
529 
530 public:
531   /// .cfi_def_cfa defines a rule for computing CFA as: take address from
532   /// Register and add Offset to it.
533   static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register,
534                                     int Offset) {
535     return MCCFIInstruction(OpDefCfa, L, Register, Offset, "");
536   }
537 
538   /// .cfi_def_cfa_register modifies a rule for computing CFA. From now
539   /// on Register will be used instead of the old one. Offset remains the same.
540   static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register) {
541     return MCCFIInstruction(OpDefCfaRegister, L, Register, 0, "");
542   }
543 
544   /// .cfi_def_cfa_offset modifies a rule for computing CFA. Register
545   /// remains the same, but offset is new. Note that it is the absolute offset
546   /// that will be added to a defined register to the compute CFA address.
547   static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int Offset) {
548     return MCCFIInstruction(OpDefCfaOffset, L, 0, Offset, "");
549   }
550 
551   /// .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but
552   /// Offset is a relative value that is added/subtracted from the previous
553   /// offset.
554   static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int Adjustment) {
555     return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, "");
556   }
557 
558   // FIXME: Update the remaining docs to use the new proposal wording.
559   /// .cfi_llvm_def_aspace_cfa defines the rule for computing the CFA to
560   /// be the result of evaluating the DWARF operation expression
561   /// `DW_OP_constu AS; DW_OP_aspace_bregx R, B` as a location description.
562   static MCCFIInstruction createLLVMDefAspaceCfa(MCSymbol *L, unsigned Register,
563                                                  int Offset,
564                                                  unsigned AddressSpace) {
565     return MCCFIInstruction(OpLLVMDefAspaceCfa, L, Register, Offset,
566                             AddressSpace);
567   }
568 
569   /// .cfi_offset Previous value of Register is saved at offset Offset
570   /// from CFA.
571   static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register,
572                                        int Offset) {
573     return MCCFIInstruction(OpOffset, L, Register, Offset, "");
574   }
575 
576   /// .cfi_rel_offset Previous value of Register is saved at offset
577   /// Offset from the current CFA register. This is transformed to .cfi_offset
578   /// using the known displacement of the CFA register from the CFA.
579   static MCCFIInstruction createRelOffset(MCSymbol *L, unsigned Register,
580                                           int Offset) {
581     return MCCFIInstruction(OpRelOffset, L, Register, Offset, "");
582   }
583 
584   /// .cfi_register Previous value of Register1 is saved in
585   /// register Register2.
586   static MCCFIInstruction createRegister(MCSymbol *L, unsigned Register1,
587                                          unsigned Register2) {
588     return MCCFIInstruction(OpRegister, L, Register1, Register2);
589   }
590 
591   /// .cfi_window_save SPARC register window is saved.
592   static MCCFIInstruction createWindowSave(MCSymbol *L) {
593     return MCCFIInstruction(OpWindowSave, L, 0, 0, "");
594   }
595 
596   /// .cfi_negate_ra_state AArch64 negate RA state.
597   static MCCFIInstruction createNegateRAState(MCSymbol *L) {
598     return MCCFIInstruction(OpNegateRAState, L, 0, 0, "");
599   }
600 
601   /// .cfi_restore says that the rule for Register is now the same as it
602   /// was at the beginning of the function, after all initial instructions added
603   /// by .cfi_startproc were executed.
604   static MCCFIInstruction createRestore(MCSymbol *L, unsigned Register) {
605     return MCCFIInstruction(OpRestore, L, Register, 0, "");
606   }
607 
608   /// .cfi_undefined From now on the previous value of Register can't be
609   /// restored anymore.
610   static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register) {
611     return MCCFIInstruction(OpUndefined, L, Register, 0, "");
612   }
613 
614   /// .cfi_same_value Current value of Register is the same as in the
615   /// previous frame. I.e., no restoration is needed.
616   static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register) {
617     return MCCFIInstruction(OpSameValue, L, Register, 0, "");
618   }
619 
620   /// .cfi_remember_state Save all current rules for all registers.
621   static MCCFIInstruction createRememberState(MCSymbol *L) {
622     return MCCFIInstruction(OpRememberState, L, 0, 0, "");
623   }
624 
625   /// .cfi_restore_state Restore the previously saved state.
626   static MCCFIInstruction createRestoreState(MCSymbol *L) {
627     return MCCFIInstruction(OpRestoreState, L, 0, 0, "");
628   }
629 
630   /// .cfi_escape Allows the user to add arbitrary bytes to the unwind
631   /// info.
632   static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals,
633                                        StringRef Comment = "") {
634     return MCCFIInstruction(OpEscape, L, 0, 0, Vals, Comment);
635   }
636 
637   /// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE
638   static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int Size) {
639     return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, "");
640   }
641 
642   OpType getOperation() const { return Operation; }
643   MCSymbol *getLabel() const { return Label; }
644 
645   unsigned getRegister() const {
646     assert(Operation == OpDefCfa || Operation == OpOffset ||
647            Operation == OpRestore || Operation == OpUndefined ||
648            Operation == OpSameValue || Operation == OpDefCfaRegister ||
649            Operation == OpRelOffset || Operation == OpRegister ||
650            Operation == OpLLVMDefAspaceCfa);
651     return Register;
652   }
653 
654   unsigned getRegister2() const {
655     assert(Operation == OpRegister);
656     return Register2;
657   }
658 
659   unsigned getAddressSpace() const {
660     assert(Operation == OpLLVMDefAspaceCfa);
661     return AddressSpace;
662   }
663 
664   int getOffset() const {
665     assert(Operation == OpDefCfa || Operation == OpOffset ||
666            Operation == OpRelOffset || Operation == OpDefCfaOffset ||
667            Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize ||
668            Operation == OpLLVMDefAspaceCfa);
669     return Offset;
670   }
671 
672   StringRef getValues() const {
673     assert(Operation == OpEscape);
674     return StringRef(&Values[0], Values.size());
675   }
676 
677   StringRef getComment() const {
678     return Comment;
679   }
680 };
681 
682 struct MCDwarfFrameInfo {
683   MCDwarfFrameInfo() = default;
684 
685   MCSymbol *Begin = nullptr;
686   MCSymbol *End = nullptr;
687   const MCSymbol *Personality = nullptr;
688   const MCSymbol *Lsda = nullptr;
689   std::vector<MCCFIInstruction> Instructions;
690   unsigned CurrentCfaRegister = 0;
691   unsigned PersonalityEncoding = 0;
692   unsigned LsdaEncoding = 0;
693   uint32_t CompactUnwindEncoding = 0;
694   bool IsSignalFrame = false;
695   bool IsSimple = false;
696   unsigned RAReg = static_cast<unsigned>(INT_MAX);
697   bool IsBKeyFrame = false;
698   bool IsMTETaggedFrame = false;
699 };
700 
701 class MCDwarfFrameEmitter {
702 public:
703   //
704   // This emits the frame info section.
705   //
706   static void Emit(MCObjectStreamer &streamer, MCAsmBackend *MAB, bool isEH);
707   static void EmitAdvanceLoc(MCObjectStreamer &Streamer, uint64_t AddrDelta);
708   static void EncodeAdvanceLoc(MCContext &Context, uint64_t AddrDelta,
709                                raw_ostream &OS);
710 };
711 
712 } // end namespace llvm
713 
714 #endif // LLVM_MC_MCDWARF_H
715