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