xref: /llvm-project/llvm/include/llvm/MC/MCDwarf.h (revision 74003f11b3e4dd90665f8f8d911f40a22dd940d4)
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                    MCSymbol *lineStreamLabel = nullptr,
199                    SMLoc streamLabelDefLoc = {})
200       : MCDwarfLoc(loc), Label(label), LineStreamLabel(lineStreamLabel),
201         StreamLabelDefLoc(streamLabelDefLoc) {}
202 
203   MCSymbol *getLabel() const { return Label; }
204 
205   // This is the label that is to be emitted into the line stream. If this is
206   // non-null and we need to emit a label, also make sure to restart the current
207   // line sequence.
208   MCSymbol *LineStreamLabel;
209 
210   // Location where LineStreamLabel was defined. If there is an error emitting
211   // LineStreamLabel, we can use the SMLoc to report an error.
212   SMLoc StreamLabelDefLoc;
213 
214   // This indicates the line entry is synthesized for an end entry.
215   bool IsEndEntry = false;
216 
217   // Override the label with the given EndLabel.
218   void setEndLabel(MCSymbol *EndLabel) {
219     Label = EndLabel;
220     IsEndEntry = true;
221   }
222 
223   // This is called when an instruction is assembled into the specified
224   // section and if there is information from the last .loc directive that
225   // has yet to have a line entry made for it is made.
226   static void make(MCStreamer *MCOS, MCSection *Section);
227 };
228 
229 /// Instances of this class represent the line information for a compile
230 /// unit where machine instructions have been assembled after seeing .loc
231 /// directives.  This is the information used to build the dwarf line
232 /// table for a section.
233 class MCLineSection {
234 public:
235   // Add an entry to this MCLineSection's line entries.
236   void addLineEntry(const MCDwarfLineEntry &LineEntry, MCSection *Sec) {
237     MCLineDivisions[Sec].push_back(LineEntry);
238   }
239 
240   // Add an end entry by cloning the last entry, if exists, for the section
241   // the given EndLabel belongs to. The label is replaced by the given EndLabel.
242   void addEndEntry(MCSymbol *EndLabel);
243 
244   using MCDwarfLineEntryCollection = std::vector<MCDwarfLineEntry>;
245   using iterator = MCDwarfLineEntryCollection::iterator;
246   using const_iterator = MCDwarfLineEntryCollection::const_iterator;
247   using MCLineDivisionMap = MapVector<MCSection *, MCDwarfLineEntryCollection>;
248 
249 private:
250   // A collection of MCDwarfLineEntry for each section.
251   MCLineDivisionMap MCLineDivisions;
252 
253 public:
254   // Returns the collection of MCDwarfLineEntry for a given Compile Unit ID.
255   const MCLineDivisionMap &getMCLineEntries() const {
256     return MCLineDivisions;
257   }
258 };
259 
260 struct MCDwarfLineTableParams {
261   /// First special line opcode - leave room for the standard opcodes.
262   /// Note: If you want to change this, you'll have to update the
263   /// "StandardOpcodeLengths" table that is emitted in
264   /// \c Emit().
265   uint8_t DWARF2LineOpcodeBase = 13;
266   /// Minimum line offset in a special line info. opcode.  The value
267   /// -5 was chosen to give a reasonable range of values.
268   int8_t DWARF2LineBase = -5;
269   /// Range of line offsets in a special line info. opcode.
270   uint8_t DWARF2LineRange = 14;
271 };
272 
273 struct MCDwarfLineTableHeader {
274   MCSymbol *Label = nullptr;
275   SmallVector<std::string, 3> MCDwarfDirs;
276   SmallVector<MCDwarfFile, 3> MCDwarfFiles;
277   StringMap<unsigned> SourceIdMap;
278   std::string CompilationDir;
279   MCDwarfFile RootFile;
280   bool HasAnySource = false;
281 
282 private:
283   bool HasAllMD5 = true;
284   bool HasAnyMD5 = false;
285 
286 public:
287   MCDwarfLineTableHeader() = default;
288 
289   Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
290                                 std::optional<MD5::MD5Result> Checksum,
291                                 std::optional<StringRef> Source,
292                                 uint16_t DwarfVersion, unsigned FileNumber = 0);
293   std::pair<MCSymbol *, MCSymbol *>
294   Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
295        std::optional<MCDwarfLineStr> &LineStr) const;
296   std::pair<MCSymbol *, MCSymbol *>
297   Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
298        ArrayRef<char> SpecialOpcodeLengths,
299        std::optional<MCDwarfLineStr> &LineStr) const;
300   void resetMD5Usage() {
301     HasAllMD5 = true;
302     HasAnyMD5 = false;
303   }
304   void trackMD5Usage(bool MD5Used) {
305     HasAllMD5 &= MD5Used;
306     HasAnyMD5 |= MD5Used;
307   }
308   bool isMD5UsageConsistent() const {
309     return MCDwarfFiles.empty() || (HasAllMD5 == HasAnyMD5);
310   }
311 
312   void setRootFile(StringRef Directory, StringRef FileName,
313                    std::optional<MD5::MD5Result> Checksum,
314                    std::optional<StringRef> Source) {
315     CompilationDir = std::string(Directory);
316     RootFile.Name = std::string(FileName);
317     RootFile.DirIndex = 0;
318     RootFile.Checksum = Checksum;
319     RootFile.Source = Source;
320     trackMD5Usage(Checksum.has_value());
321     HasAnySource |= Source.has_value();
322   }
323 
324   void resetFileTable() {
325     MCDwarfDirs.clear();
326     MCDwarfFiles.clear();
327     RootFile.Name.clear();
328     resetMD5Usage();
329     HasAnySource = false;
330   }
331 
332 private:
333   void emitV2FileDirTables(MCStreamer *MCOS) const;
334   void emitV5FileDirTables(MCStreamer *MCOS,
335                            std::optional<MCDwarfLineStr> &LineStr) const;
336 };
337 
338 class MCDwarfDwoLineTable {
339   MCDwarfLineTableHeader Header;
340   bool HasSplitLineTable = false;
341 
342 public:
343   void maybeSetRootFile(StringRef Directory, StringRef FileName,
344                         std::optional<MD5::MD5Result> Checksum,
345                         std::optional<StringRef> Source) {
346     if (!Header.RootFile.Name.empty())
347       return;
348     Header.setRootFile(Directory, FileName, Checksum, Source);
349   }
350 
351   unsigned getFile(StringRef Directory, StringRef FileName,
352                    std::optional<MD5::MD5Result> Checksum,
353                    uint16_t DwarfVersion, std::optional<StringRef> Source) {
354     HasSplitLineTable = true;
355     return cantFail(Header.tryGetFile(Directory, FileName, Checksum, Source,
356                                       DwarfVersion));
357   }
358 
359   void Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params,
360             MCSection *Section) const;
361 };
362 
363 class MCDwarfLineTable {
364   MCDwarfLineTableHeader Header;
365   MCLineSection MCLineSections;
366 
367 public:
368   // This emits the Dwarf file and the line tables for all Compile Units.
369   static void emit(MCStreamer *MCOS, MCDwarfLineTableParams Params);
370 
371   // This emits the Dwarf file and the line tables for a given Compile Unit.
372   void emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
373               std::optional<MCDwarfLineStr> &LineStr) const;
374 
375   // This emits a single line table associated with a given Section.
376   static void
377   emitOne(MCStreamer *MCOS, MCSection *Section,
378           const MCLineSection::MCDwarfLineEntryCollection &LineEntries);
379 
380   void endCurrentSeqAndEmitLineStreamLabel(MCStreamer *MCOS, SMLoc DefLoc,
381                                            StringRef Name);
382 
383   Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
384                                 std::optional<MD5::MD5Result> Checksum,
385                                 std::optional<StringRef> Source,
386                                 uint16_t DwarfVersion, unsigned FileNumber = 0);
387   unsigned getFile(StringRef &Directory, StringRef &FileName,
388                    std::optional<MD5::MD5Result> Checksum,
389                    std::optional<StringRef> Source, uint16_t DwarfVersion,
390                    unsigned FileNumber = 0) {
391     return cantFail(tryGetFile(Directory, FileName, Checksum, Source,
392                                DwarfVersion, FileNumber));
393   }
394 
395   void setRootFile(StringRef Directory, StringRef FileName,
396                    std::optional<MD5::MD5Result> Checksum,
397                    std::optional<StringRef> Source) {
398     Header.CompilationDir = std::string(Directory);
399     Header.RootFile.Name = std::string(FileName);
400     Header.RootFile.DirIndex = 0;
401     Header.RootFile.Checksum = Checksum;
402     Header.RootFile.Source = Source;
403     Header.trackMD5Usage(Checksum.has_value());
404     Header.HasAnySource |= Source.has_value();
405   }
406 
407   void resetFileTable() { Header.resetFileTable(); }
408 
409   bool hasRootFile() const { return !Header.RootFile.Name.empty(); }
410 
411   MCDwarfFile &getRootFile() { return Header.RootFile; }
412   const MCDwarfFile &getRootFile() const { return Header.RootFile; }
413 
414   // Report whether MD5 usage has been consistent (all-or-none).
415   bool isMD5UsageConsistent() const { return Header.isMD5UsageConsistent(); }
416 
417   MCSymbol *getLabel() const {
418     return Header.Label;
419   }
420 
421   void setLabel(MCSymbol *Label) {
422     Header.Label = Label;
423   }
424 
425   const SmallVectorImpl<std::string> &getMCDwarfDirs() const {
426     return Header.MCDwarfDirs;
427   }
428 
429   SmallVectorImpl<std::string> &getMCDwarfDirs() {
430     return Header.MCDwarfDirs;
431   }
432 
433   const SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() const {
434     return Header.MCDwarfFiles;
435   }
436 
437   SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() {
438     return Header.MCDwarfFiles;
439   }
440 
441   const MCLineSection &getMCLineSections() const {
442     return MCLineSections;
443   }
444   MCLineSection &getMCLineSections() {
445     return MCLineSections;
446   }
447 };
448 
449 class MCDwarfLineAddr {
450 public:
451   /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas.
452   static void encode(MCContext &Context, MCDwarfLineTableParams Params,
453                      int64_t LineDelta, uint64_t AddrDelta, SmallVectorImpl<char> &OS);
454 
455   /// Utility function to emit the encoding to a streamer.
456   static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
457                    int64_t LineDelta, uint64_t AddrDelta);
458 };
459 
460 class MCGenDwarfInfo {
461 public:
462   //
463   // When generating dwarf for assembly source files this emits the Dwarf
464   // sections.
465   //
466   static void Emit(MCStreamer *MCOS);
467 };
468 
469 // When generating dwarf for assembly source files this is the info that is
470 // needed to be gathered for each symbol that will have a dwarf label.
471 class MCGenDwarfLabelEntry {
472 private:
473   // Name of the symbol without a leading underbar, if any.
474   StringRef Name;
475   // The dwarf file number this symbol is in.
476   unsigned FileNumber;
477   // The line number this symbol is at.
478   unsigned LineNumber;
479   // The low_pc for the dwarf label is taken from this symbol.
480   MCSymbol *Label;
481 
482 public:
483   MCGenDwarfLabelEntry(StringRef name, unsigned fileNumber, unsigned lineNumber,
484                        MCSymbol *label)
485       : Name(name), FileNumber(fileNumber), LineNumber(lineNumber),
486         Label(label) {}
487 
488   StringRef getName() const { return Name; }
489   unsigned getFileNumber() const { return FileNumber; }
490   unsigned getLineNumber() const { return LineNumber; }
491   MCSymbol *getLabel() const { return Label; }
492 
493   // This is called when label is created when we are generating dwarf for
494   // assembly source files.
495   static void Make(MCSymbol *Symbol, MCStreamer *MCOS, SourceMgr &SrcMgr,
496                    SMLoc &Loc);
497 };
498 
499 class MCCFIInstruction {
500 public:
501   enum OpType : uint8_t {
502     OpSameValue,
503     OpRememberState,
504     OpRestoreState,
505     OpOffset,
506     OpLLVMDefAspaceCfa,
507     OpDefCfaRegister,
508     OpDefCfaOffset,
509     OpDefCfa,
510     OpRelOffset,
511     OpAdjustCfaOffset,
512     OpEscape,
513     OpRestore,
514     OpUndefined,
515     OpRegister,
516     OpWindowSave,
517     OpNegateRAState,
518     OpNegateRAStateWithPC,
519     OpGnuArgsSize,
520     OpLabel,
521     OpValOffset,
522   };
523 
524 private:
525   MCSymbol *Label;
526   union {
527     struct {
528       unsigned Register;
529       int64_t Offset;
530     } RI;
531     struct {
532       unsigned Register;
533       int64_t Offset;
534       unsigned AddressSpace;
535     } RIA;
536     struct {
537       unsigned Register;
538       unsigned Register2;
539     } RR;
540     MCSymbol *CfiLabel;
541   } U;
542   OpType Operation;
543   SMLoc Loc;
544   std::vector<char> Values;
545   std::string Comment;
546 
547   MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int64_t O, SMLoc Loc,
548                    StringRef V = "", StringRef Comment = "")
549       : Label(L), Operation(Op), Loc(Loc), Values(V.begin(), V.end()),
550         Comment(Comment) {
551     assert(Op != OpRegister && Op != OpLLVMDefAspaceCfa);
552     U.RI = {R, O};
553   }
554   MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2, SMLoc Loc)
555       : Label(L), Operation(Op), Loc(Loc) {
556     assert(Op == OpRegister);
557     U.RR = {R1, R2};
558   }
559   MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int64_t O, unsigned AS,
560                    SMLoc Loc)
561       : Label(L), Operation(Op), Loc(Loc) {
562     assert(Op == OpLLVMDefAspaceCfa);
563     U.RIA = {R, O, AS};
564   }
565 
566   MCCFIInstruction(OpType Op, MCSymbol *L, MCSymbol *CfiLabel, SMLoc Loc)
567       : Label(L), Operation(Op), Loc(Loc) {
568     assert(Op == OpLabel);
569     U.CfiLabel = CfiLabel;
570   }
571 
572 public:
573   /// .cfi_def_cfa defines a rule for computing CFA as: take address from
574   /// Register and add Offset to it.
575   static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register,
576                                     int64_t Offset, SMLoc Loc = {}) {
577     return MCCFIInstruction(OpDefCfa, L, Register, Offset, Loc);
578   }
579 
580   /// .cfi_def_cfa_register modifies a rule for computing CFA. From now
581   /// on Register will be used instead of the old one. Offset remains the same.
582   static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register,
583                                                SMLoc Loc = {}) {
584     return MCCFIInstruction(OpDefCfaRegister, L, Register, INT64_C(0), Loc);
585   }
586 
587   /// .cfi_def_cfa_offset modifies a rule for computing CFA. Register
588   /// remains the same, but offset is new. Note that it is the absolute offset
589   /// that will be added to a defined register to the compute CFA address.
590   static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int64_t Offset,
591                                           SMLoc Loc = {}) {
592     return MCCFIInstruction(OpDefCfaOffset, L, 0, Offset, Loc);
593   }
594 
595   /// .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but
596   /// Offset is a relative value that is added/subtracted from the previous
597   /// offset.
598   static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int64_t Adjustment,
599                                                 SMLoc Loc = {}) {
600     return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, Loc);
601   }
602 
603   // FIXME: Update the remaining docs to use the new proposal wording.
604   /// .cfi_llvm_def_aspace_cfa defines the rule for computing the CFA to
605   /// be the result of evaluating the DWARF operation expression
606   /// `DW_OP_constu AS; DW_OP_aspace_bregx R, B` as a location description.
607   static MCCFIInstruction createLLVMDefAspaceCfa(MCSymbol *L, unsigned Register,
608                                                  int64_t Offset,
609                                                  unsigned AddressSpace,
610                                                  SMLoc Loc) {
611     return MCCFIInstruction(OpLLVMDefAspaceCfa, L, Register, Offset,
612                             AddressSpace, Loc);
613   }
614 
615   /// .cfi_offset Previous value of Register is saved at offset Offset
616   /// from CFA.
617   static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register,
618                                        int64_t Offset, SMLoc Loc = {}) {
619     return MCCFIInstruction(OpOffset, L, Register, Offset, Loc);
620   }
621 
622   /// .cfi_rel_offset Previous value of Register is saved at offset
623   /// Offset from the current CFA register. This is transformed to .cfi_offset
624   /// using the known displacement of the CFA register from the CFA.
625   static MCCFIInstruction createRelOffset(MCSymbol *L, unsigned Register,
626                                           int64_t Offset, SMLoc Loc = {}) {
627     return MCCFIInstruction(OpRelOffset, L, Register, Offset, Loc);
628   }
629 
630   /// .cfi_register Previous value of Register1 is saved in
631   /// register Register2.
632   static MCCFIInstruction createRegister(MCSymbol *L, unsigned Register1,
633                                          unsigned Register2, SMLoc Loc = {}) {
634     return MCCFIInstruction(OpRegister, L, Register1, Register2, Loc);
635   }
636 
637   /// .cfi_window_save SPARC register window is saved.
638   static MCCFIInstruction createWindowSave(MCSymbol *L, SMLoc Loc = {}) {
639     return MCCFIInstruction(OpWindowSave, L, 0, INT64_C(0), Loc);
640   }
641 
642   /// .cfi_negate_ra_state AArch64 negate RA state.
643   static MCCFIInstruction createNegateRAState(MCSymbol *L, SMLoc Loc = {}) {
644     return MCCFIInstruction(OpNegateRAState, L, 0, INT64_C(0), Loc);
645   }
646 
647   /// .cfi_negate_ra_state_with_pc AArch64 negate RA state with PC.
648   static MCCFIInstruction createNegateRAStateWithPC(MCSymbol *L,
649                                                     SMLoc Loc = {}) {
650     return MCCFIInstruction(OpNegateRAStateWithPC, L, 0, INT64_C(0), Loc);
651   }
652 
653   /// .cfi_restore says that the rule for Register is now the same as it
654   /// was at the beginning of the function, after all initial instructions added
655   /// by .cfi_startproc were executed.
656   static MCCFIInstruction createRestore(MCSymbol *L, unsigned Register,
657                                         SMLoc Loc = {}) {
658     return MCCFIInstruction(OpRestore, L, Register, INT64_C(0), Loc);
659   }
660 
661   /// .cfi_undefined From now on the previous value of Register can't be
662   /// restored anymore.
663   static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register,
664                                           SMLoc Loc = {}) {
665     return MCCFIInstruction(OpUndefined, L, Register, INT64_C(0), Loc);
666   }
667 
668   /// .cfi_same_value Current value of Register is the same as in the
669   /// previous frame. I.e., no restoration is needed.
670   static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register,
671                                           SMLoc Loc = {}) {
672     return MCCFIInstruction(OpSameValue, L, Register, INT64_C(0), Loc);
673   }
674 
675   /// .cfi_remember_state Save all current rules for all registers.
676   static MCCFIInstruction createRememberState(MCSymbol *L, SMLoc Loc = {}) {
677     return MCCFIInstruction(OpRememberState, L, 0, INT64_C(0), Loc);
678   }
679 
680   /// .cfi_restore_state Restore the previously saved state.
681   static MCCFIInstruction createRestoreState(MCSymbol *L, SMLoc Loc = {}) {
682     return MCCFIInstruction(OpRestoreState, L, 0, INT64_C(0), Loc);
683   }
684 
685   /// .cfi_escape Allows the user to add arbitrary bytes to the unwind
686   /// info.
687   static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals,
688                                        SMLoc Loc = {}, StringRef Comment = "") {
689     return MCCFIInstruction(OpEscape, L, 0, 0, Loc, Vals, Comment);
690   }
691 
692   /// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE
693   static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int64_t Size,
694                                             SMLoc Loc = {}) {
695     return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, Loc);
696   }
697 
698   static MCCFIInstruction createLabel(MCSymbol *L, MCSymbol *CfiLabel,
699                                       SMLoc Loc) {
700     return MCCFIInstruction(OpLabel, L, CfiLabel, Loc);
701   }
702 
703   /// .cfi_val_offset Previous value of Register is offset Offset from the
704   /// current CFA register.
705   static MCCFIInstruction createValOffset(MCSymbol *L, unsigned Register,
706                                           int64_t Offset, SMLoc Loc = {}) {
707     return MCCFIInstruction(OpValOffset, L, Register, Offset, Loc);
708   }
709 
710   OpType getOperation() const { return Operation; }
711   MCSymbol *getLabel() const { return Label; }
712 
713   unsigned getRegister() const {
714     if (Operation == OpRegister)
715       return U.RR.Register;
716     if (Operation == OpLLVMDefAspaceCfa)
717       return U.RIA.Register;
718     assert(Operation == OpDefCfa || Operation == OpOffset ||
719            Operation == OpRestore || Operation == OpUndefined ||
720            Operation == OpSameValue || Operation == OpDefCfaRegister ||
721            Operation == OpRelOffset || Operation == OpValOffset);
722     return U.RI.Register;
723   }
724 
725   unsigned getRegister2() const {
726     assert(Operation == OpRegister);
727     return U.RR.Register2;
728   }
729 
730   unsigned getAddressSpace() const {
731     assert(Operation == OpLLVMDefAspaceCfa);
732     return U.RIA.AddressSpace;
733   }
734 
735   int64_t getOffset() const {
736     if (Operation == OpLLVMDefAspaceCfa)
737       return U.RIA.Offset;
738     assert(Operation == OpDefCfa || Operation == OpOffset ||
739            Operation == OpRelOffset || Operation == OpDefCfaOffset ||
740            Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize ||
741            Operation == OpValOffset);
742     return U.RI.Offset;
743   }
744 
745   MCSymbol *getCfiLabel() const {
746     assert(Operation == OpLabel);
747     return U.CfiLabel;
748   }
749 
750   StringRef getValues() const {
751     assert(Operation == OpEscape);
752     return StringRef(&Values[0], Values.size());
753   }
754 
755   StringRef getComment() const { return Comment; }
756   SMLoc getLoc() const { return Loc; }
757 };
758 
759 struct MCDwarfFrameInfo {
760   MCDwarfFrameInfo() = default;
761 
762   MCSymbol *Begin = nullptr;
763   MCSymbol *End = nullptr;
764   const MCSymbol *Personality = nullptr;
765   const MCSymbol *Lsda = nullptr;
766   std::vector<MCCFIInstruction> Instructions;
767   unsigned CurrentCfaRegister = 0;
768   unsigned PersonalityEncoding = 0;
769   unsigned LsdaEncoding = 0;
770   uint64_t CompactUnwindEncoding = 0;
771   bool IsSignalFrame = false;
772   bool IsSimple = false;
773   unsigned RAReg = static_cast<unsigned>(INT_MAX);
774   bool IsBKeyFrame = false;
775   bool IsMTETaggedFrame = false;
776 };
777 
778 class MCDwarfFrameEmitter {
779 public:
780   //
781   // This emits the frame info section.
782   //
783   static void Emit(MCObjectStreamer &streamer, MCAsmBackend *MAB, bool isEH);
784   static void encodeAdvanceLoc(MCContext &Context, uint64_t AddrDelta,
785                                SmallVectorImpl<char> &OS);
786 };
787 
788 } // end namespace llvm
789 
790 #endif // LLVM_MC_MCDWARF_H
791