xref: /freebsd/contrib/llvm-project/llvm/include/llvm/MC/MCDwarf.h (revision 36b606ae6aa4b24061096ba18582e0a08ccd5dba)
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 
getSaver()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 
MCDwarfLoc(unsigned fileNum,unsigned line,unsigned column,unsigned flags,unsigned isa,unsigned discriminator)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.
getFileNum()136   unsigned getFileNum() const { return FileNum; }
137 
138   /// Get the Line of this MCDwarfLoc.
getLine()139   unsigned getLine() const { return Line; }
140 
141   /// Get the Column of this MCDwarfLoc.
getColumn()142   unsigned getColumn() const { return Column; }
143 
144   /// Get the Flags of this MCDwarfLoc.
getFlags()145   unsigned getFlags() const { return Flags; }
146 
147   /// Get the Isa of this MCDwarfLoc.
getIsa()148   unsigned getIsa() const { return Isa; }
149 
150   /// Get the Discriminator of this MCDwarfLoc.
getDiscriminator()151   unsigned getDiscriminator() const { return Discriminator; }
152 
153   /// Set the FileNum of this MCDwarfLoc.
setFileNum(unsigned fileNum)154   void setFileNum(unsigned fileNum) { FileNum = fileNum; }
155 
156   /// Set the Line of this MCDwarfLoc.
setLine(unsigned line)157   void setLine(unsigned line) { Line = line; }
158 
159   /// Set the Column of this MCDwarfLoc.
setColumn(unsigned column)160   void setColumn(unsigned column) {
161     assert(column <= UINT16_MAX);
162     Column = column;
163   }
164 
165   /// Set the Flags of this MCDwarfLoc.
setFlags(unsigned flags)166   void setFlags(unsigned flags) {
167     assert(flags <= UINT8_MAX);
168     Flags = flags;
169   }
170 
171   /// Set the Isa of this MCDwarfLoc.
setIsa(unsigned isa)172   void setIsa(unsigned isa) {
173     assert(isa <= UINT8_MAX);
174     Isa = isa;
175   }
176 
177   /// Set the Discriminator of this MCDwarfLoc.
setDiscriminator(unsigned discriminator)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.
MCDwarfLineEntry(MCSymbol * label,const MCDwarfLoc loc)197   MCDwarfLineEntry(MCSymbol *label, const MCDwarfLoc loc)
198       : MCDwarfLoc(loc), Label(label) {}
199 
getLabel()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.
setEndLabel(MCSymbol * 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.
addLineEntry(const MCDwarfLineEntry & LineEntry,MCSection * Sec)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.
getMCLineEntries()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 HasAnySource = false;
269 
270 private:
271   bool HasAllMD5 = true;
272   bool HasAnyMD5 = false;
273 
274 public:
275   MCDwarfLineTableHeader() = default;
276 
277   Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
278                                 std::optional<MD5::MD5Result> Checksum,
279                                 std::optional<StringRef> Source,
280                                 uint16_t DwarfVersion, unsigned FileNumber = 0);
281   std::pair<MCSymbol *, MCSymbol *>
282   Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
283        std::optional<MCDwarfLineStr> &LineStr) const;
284   std::pair<MCSymbol *, MCSymbol *>
285   Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
286        ArrayRef<char> SpecialOpcodeLengths,
287        std::optional<MCDwarfLineStr> &LineStr) const;
resetMD5UsageMCDwarfLineTableHeader288   void resetMD5Usage() {
289     HasAllMD5 = true;
290     HasAnyMD5 = false;
291   }
trackMD5UsageMCDwarfLineTableHeader292   void trackMD5Usage(bool MD5Used) {
293     HasAllMD5 &= MD5Used;
294     HasAnyMD5 |= MD5Used;
295   }
isMD5UsageConsistentMCDwarfLineTableHeader296   bool isMD5UsageConsistent() const {
297     return MCDwarfFiles.empty() || (HasAllMD5 == HasAnyMD5);
298   }
299 
setRootFileMCDwarfLineTableHeader300   void setRootFile(StringRef Directory, StringRef FileName,
301                    std::optional<MD5::MD5Result> Checksum,
302                    std::optional<StringRef> Source) {
303     CompilationDir = std::string(Directory);
304     RootFile.Name = std::string(FileName);
305     RootFile.DirIndex = 0;
306     RootFile.Checksum = Checksum;
307     RootFile.Source = Source;
308     trackMD5Usage(Checksum.has_value());
309     HasAnySource |= Source.has_value();
310   }
311 
resetFileTableMCDwarfLineTableHeader312   void resetFileTable() {
313     MCDwarfDirs.clear();
314     MCDwarfFiles.clear();
315     RootFile.Name.clear();
316     resetMD5Usage();
317     HasAnySource = false;
318   }
319 
320 private:
321   void emitV2FileDirTables(MCStreamer *MCOS) const;
322   void emitV5FileDirTables(MCStreamer *MCOS,
323                            std::optional<MCDwarfLineStr> &LineStr) const;
324 };
325 
326 class MCDwarfDwoLineTable {
327   MCDwarfLineTableHeader Header;
328   bool HasSplitLineTable = false;
329 
330 public:
maybeSetRootFile(StringRef Directory,StringRef FileName,std::optional<MD5::MD5Result> Checksum,std::optional<StringRef> Source)331   void maybeSetRootFile(StringRef Directory, StringRef FileName,
332                         std::optional<MD5::MD5Result> Checksum,
333                         std::optional<StringRef> Source) {
334     if (!Header.RootFile.Name.empty())
335       return;
336     Header.setRootFile(Directory, FileName, Checksum, Source);
337   }
338 
getFile(StringRef Directory,StringRef FileName,std::optional<MD5::MD5Result> Checksum,uint16_t DwarfVersion,std::optional<StringRef> Source)339   unsigned getFile(StringRef Directory, StringRef FileName,
340                    std::optional<MD5::MD5Result> Checksum,
341                    uint16_t DwarfVersion, std::optional<StringRef> Source) {
342     HasSplitLineTable = true;
343     return cantFail(Header.tryGetFile(Directory, FileName, Checksum, Source,
344                                       DwarfVersion));
345   }
346 
347   void Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params,
348             MCSection *Section) const;
349 };
350 
351 class MCDwarfLineTable {
352   MCDwarfLineTableHeader Header;
353   MCLineSection MCLineSections;
354 
355 public:
356   // This emits the Dwarf file and the line tables for all Compile Units.
357   static void emit(MCStreamer *MCOS, MCDwarfLineTableParams Params);
358 
359   // This emits the Dwarf file and the line tables for a given Compile Unit.
360   void emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
361               std::optional<MCDwarfLineStr> &LineStr) const;
362 
363   // This emits a single line table associated with a given Section.
364   static void
365   emitOne(MCStreamer *MCOS, MCSection *Section,
366           const MCLineSection::MCDwarfLineEntryCollection &LineEntries);
367 
368   Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
369                                 std::optional<MD5::MD5Result> Checksum,
370                                 std::optional<StringRef> Source,
371                                 uint16_t DwarfVersion, unsigned FileNumber = 0);
372   unsigned getFile(StringRef &Directory, StringRef &FileName,
373                    std::optional<MD5::MD5Result> Checksum,
374                    std::optional<StringRef> Source, uint16_t DwarfVersion,
375                    unsigned FileNumber = 0) {
376     return cantFail(tryGetFile(Directory, FileName, Checksum, Source,
377                                DwarfVersion, FileNumber));
378   }
379 
setRootFile(StringRef Directory,StringRef FileName,std::optional<MD5::MD5Result> Checksum,std::optional<StringRef> Source)380   void setRootFile(StringRef Directory, StringRef FileName,
381                    std::optional<MD5::MD5Result> Checksum,
382                    std::optional<StringRef> Source) {
383     Header.CompilationDir = std::string(Directory);
384     Header.RootFile.Name = std::string(FileName);
385     Header.RootFile.DirIndex = 0;
386     Header.RootFile.Checksum = Checksum;
387     Header.RootFile.Source = Source;
388     Header.trackMD5Usage(Checksum.has_value());
389     Header.HasAnySource |= Source.has_value();
390   }
391 
resetFileTable()392   void resetFileTable() { Header.resetFileTable(); }
393 
hasRootFile()394   bool hasRootFile() const { return !Header.RootFile.Name.empty(); }
395 
getRootFile()396   MCDwarfFile &getRootFile() { return Header.RootFile; }
getRootFile()397   const MCDwarfFile &getRootFile() const { return Header.RootFile; }
398 
399   // Report whether MD5 usage has been consistent (all-or-none).
isMD5UsageConsistent()400   bool isMD5UsageConsistent() const { return Header.isMD5UsageConsistent(); }
401 
getLabel()402   MCSymbol *getLabel() const {
403     return Header.Label;
404   }
405 
setLabel(MCSymbol * Label)406   void setLabel(MCSymbol *Label) {
407     Header.Label = Label;
408   }
409 
getMCDwarfDirs()410   const SmallVectorImpl<std::string> &getMCDwarfDirs() const {
411     return Header.MCDwarfDirs;
412   }
413 
getMCDwarfDirs()414   SmallVectorImpl<std::string> &getMCDwarfDirs() {
415     return Header.MCDwarfDirs;
416   }
417 
getMCDwarfFiles()418   const SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() const {
419     return Header.MCDwarfFiles;
420   }
421 
getMCDwarfFiles()422   SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() {
423     return Header.MCDwarfFiles;
424   }
425 
getMCLineSections()426   const MCLineSection &getMCLineSections() const {
427     return MCLineSections;
428   }
getMCLineSections()429   MCLineSection &getMCLineSections() {
430     return MCLineSections;
431   }
432 };
433 
434 class MCDwarfLineAddr {
435 public:
436   /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas.
437   static void encode(MCContext &Context, MCDwarfLineTableParams Params,
438                      int64_t LineDelta, uint64_t AddrDelta, SmallVectorImpl<char> &OS);
439 
440   /// Utility function to emit the encoding to a streamer.
441   static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
442                    int64_t LineDelta, uint64_t AddrDelta);
443 };
444 
445 class MCGenDwarfInfo {
446 public:
447   //
448   // When generating dwarf for assembly source files this emits the Dwarf
449   // sections.
450   //
451   static void Emit(MCStreamer *MCOS);
452 };
453 
454 // When generating dwarf for assembly source files this is the info that is
455 // needed to be gathered for each symbol that will have a dwarf label.
456 class MCGenDwarfLabelEntry {
457 private:
458   // Name of the symbol without a leading underbar, if any.
459   StringRef Name;
460   // The dwarf file number this symbol is in.
461   unsigned FileNumber;
462   // The line number this symbol is at.
463   unsigned LineNumber;
464   // The low_pc for the dwarf label is taken from this symbol.
465   MCSymbol *Label;
466 
467 public:
MCGenDwarfLabelEntry(StringRef name,unsigned fileNumber,unsigned lineNumber,MCSymbol * label)468   MCGenDwarfLabelEntry(StringRef name, unsigned fileNumber, unsigned lineNumber,
469                        MCSymbol *label)
470       : Name(name), FileNumber(fileNumber), LineNumber(lineNumber),
471         Label(label) {}
472 
getName()473   StringRef getName() const { return Name; }
getFileNumber()474   unsigned getFileNumber() const { return FileNumber; }
getLineNumber()475   unsigned getLineNumber() const { return LineNumber; }
getLabel()476   MCSymbol *getLabel() const { return Label; }
477 
478   // This is called when label is created when we are generating dwarf for
479   // assembly source files.
480   static void Make(MCSymbol *Symbol, MCStreamer *MCOS, SourceMgr &SrcMgr,
481                    SMLoc &Loc);
482 };
483 
484 class MCCFIInstruction {
485 public:
486   enum OpType : uint8_t {
487     OpSameValue,
488     OpRememberState,
489     OpRestoreState,
490     OpOffset,
491     OpLLVMDefAspaceCfa,
492     OpDefCfaRegister,
493     OpDefCfaOffset,
494     OpDefCfa,
495     OpRelOffset,
496     OpAdjustCfaOffset,
497     OpEscape,
498     OpRestore,
499     OpUndefined,
500     OpRegister,
501     OpWindowSave,
502     OpNegateRAState,
503     OpGnuArgsSize,
504     OpLabel,
505   };
506 
507 private:
508   MCSymbol *Label;
509   union {
510     struct {
511       unsigned Register;
512       int64_t Offset;
513     } RI;
514     struct {
515       unsigned Register;
516       int64_t Offset;
517       unsigned AddressSpace;
518     } RIA;
519     struct {
520       unsigned Register;
521       unsigned Register2;
522     } RR;
523     MCSymbol *CfiLabel;
524   } U;
525   OpType Operation;
526   SMLoc Loc;
527   std::vector<char> Values;
528   std::string Comment;
529 
530   MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int64_t O, SMLoc Loc,
531                    StringRef V = "", StringRef Comment = "")
Label(L)532       : Label(L), Operation(Op), Loc(Loc), Values(V.begin(), V.end()),
533         Comment(Comment) {
534     assert(Op != OpRegister && Op != OpLLVMDefAspaceCfa);
535     U.RI = {R, O};
536   }
MCCFIInstruction(OpType Op,MCSymbol * L,unsigned R1,unsigned R2,SMLoc Loc)537   MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2, SMLoc Loc)
538       : Label(L), Operation(Op), Loc(Loc) {
539     assert(Op == OpRegister);
540     U.RR = {R1, R2};
541   }
MCCFIInstruction(OpType Op,MCSymbol * L,unsigned R,int64_t O,unsigned AS,SMLoc Loc)542   MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int64_t O, unsigned AS,
543                    SMLoc Loc)
544       : Label(L), Operation(Op), Loc(Loc) {
545     assert(Op == OpLLVMDefAspaceCfa);
546     U.RIA = {R, O, AS};
547   }
548 
MCCFIInstruction(OpType Op,MCSymbol * L,MCSymbol * CfiLabel,SMLoc Loc)549   MCCFIInstruction(OpType Op, MCSymbol *L, MCSymbol *CfiLabel, SMLoc Loc)
550       : Label(L), Operation(Op), Loc(Loc) {
551     assert(Op == OpLabel);
552     U.CfiLabel = CfiLabel;
553   }
554 
555 public:
556   /// .cfi_def_cfa defines a rule for computing CFA as: take address from
557   /// Register and add Offset to it.
558   static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register,
559                                     int64_t Offset, SMLoc Loc = {}) {
560     return MCCFIInstruction(OpDefCfa, L, Register, Offset, Loc);
561   }
562 
563   /// .cfi_def_cfa_register modifies a rule for computing CFA. From now
564   /// on Register will be used instead of the old one. Offset remains the same.
565   static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register,
566                                                SMLoc Loc = {}) {
567     return MCCFIInstruction(OpDefCfaRegister, L, Register, INT64_C(0), Loc);
568   }
569 
570   /// .cfi_def_cfa_offset modifies a rule for computing CFA. Register
571   /// remains the same, but offset is new. Note that it is the absolute offset
572   /// that will be added to a defined register to the compute CFA address.
573   static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int64_t Offset,
574                                           SMLoc Loc = {}) {
575     return MCCFIInstruction(OpDefCfaOffset, L, 0, Offset, Loc);
576   }
577 
578   /// .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but
579   /// Offset is a relative value that is added/subtracted from the previous
580   /// offset.
581   static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int64_t Adjustment,
582                                                 SMLoc Loc = {}) {
583     return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, Loc);
584   }
585 
586   // FIXME: Update the remaining docs to use the new proposal wording.
587   /// .cfi_llvm_def_aspace_cfa defines the rule for computing the CFA to
588   /// be the result of evaluating the DWARF operation expression
589   /// `DW_OP_constu AS; DW_OP_aspace_bregx R, B` as a location description.
createLLVMDefAspaceCfa(MCSymbol * L,unsigned Register,int64_t Offset,unsigned AddressSpace,SMLoc Loc)590   static MCCFIInstruction createLLVMDefAspaceCfa(MCSymbol *L, unsigned Register,
591                                                  int64_t Offset,
592                                                  unsigned AddressSpace,
593                                                  SMLoc Loc) {
594     return MCCFIInstruction(OpLLVMDefAspaceCfa, L, Register, Offset,
595                             AddressSpace, Loc);
596   }
597 
598   /// .cfi_offset Previous value of Register is saved at offset Offset
599   /// from CFA.
600   static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register,
601                                        int64_t Offset, SMLoc Loc = {}) {
602     return MCCFIInstruction(OpOffset, L, Register, Offset, Loc);
603   }
604 
605   /// .cfi_rel_offset Previous value of Register is saved at offset
606   /// Offset from the current CFA register. This is transformed to .cfi_offset
607   /// using the known displacement of the CFA register from the CFA.
608   static MCCFIInstruction createRelOffset(MCSymbol *L, unsigned Register,
609                                           int64_t Offset, SMLoc Loc = {}) {
610     return MCCFIInstruction(OpRelOffset, L, Register, Offset, Loc);
611   }
612 
613   /// .cfi_register Previous value of Register1 is saved in
614   /// register Register2.
615   static MCCFIInstruction createRegister(MCSymbol *L, unsigned Register1,
616                                          unsigned Register2, SMLoc Loc = {}) {
617     return MCCFIInstruction(OpRegister, L, Register1, Register2, Loc);
618   }
619 
620   /// .cfi_window_save SPARC register window is saved.
621   static MCCFIInstruction createWindowSave(MCSymbol *L, SMLoc Loc = {}) {
622     return MCCFIInstruction(OpWindowSave, L, 0, INT64_C(0), Loc);
623   }
624 
625   /// .cfi_negate_ra_state AArch64 negate RA state.
626   static MCCFIInstruction createNegateRAState(MCSymbol *L, SMLoc Loc = {}) {
627     return MCCFIInstruction(OpNegateRAState, L, 0, INT64_C(0), Loc);
628   }
629 
630   /// .cfi_restore says that the rule for Register is now the same as it
631   /// was at the beginning of the function, after all initial instructions added
632   /// by .cfi_startproc were executed.
633   static MCCFIInstruction createRestore(MCSymbol *L, unsigned Register,
634                                         SMLoc Loc = {}) {
635     return MCCFIInstruction(OpRestore, L, Register, INT64_C(0), Loc);
636   }
637 
638   /// .cfi_undefined From now on the previous value of Register can't be
639   /// restored anymore.
640   static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register,
641                                           SMLoc Loc = {}) {
642     return MCCFIInstruction(OpUndefined, L, Register, INT64_C(0), Loc);
643   }
644 
645   /// .cfi_same_value Current value of Register is the same as in the
646   /// previous frame. I.e., no restoration is needed.
647   static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register,
648                                           SMLoc Loc = {}) {
649     return MCCFIInstruction(OpSameValue, L, Register, INT64_C(0), Loc);
650   }
651 
652   /// .cfi_remember_state Save all current rules for all registers.
653   static MCCFIInstruction createRememberState(MCSymbol *L, SMLoc Loc = {}) {
654     return MCCFIInstruction(OpRememberState, L, 0, INT64_C(0), Loc);
655   }
656 
657   /// .cfi_restore_state Restore the previously saved state.
658   static MCCFIInstruction createRestoreState(MCSymbol *L, SMLoc Loc = {}) {
659     return MCCFIInstruction(OpRestoreState, L, 0, INT64_C(0), Loc);
660   }
661 
662   /// .cfi_escape Allows the user to add arbitrary bytes to the unwind
663   /// info.
664   static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals,
665                                        SMLoc Loc = {}, StringRef Comment = "") {
666     return MCCFIInstruction(OpEscape, L, 0, 0, Loc, Vals, Comment);
667   }
668 
669   /// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE
670   static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int64_t Size,
671                                             SMLoc Loc = {}) {
672     return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, Loc);
673   }
674 
createLabel(MCSymbol * L,MCSymbol * CfiLabel,SMLoc Loc)675   static MCCFIInstruction createLabel(MCSymbol *L, MCSymbol *CfiLabel,
676                                       SMLoc Loc) {
677     return MCCFIInstruction(OpLabel, L, CfiLabel, Loc);
678   }
679 
getOperation()680   OpType getOperation() const { return Operation; }
getLabel()681   MCSymbol *getLabel() const { return Label; }
682 
getRegister()683   unsigned getRegister() const {
684     if (Operation == OpRegister)
685       return U.RR.Register;
686     if (Operation == OpLLVMDefAspaceCfa)
687       return U.RIA.Register;
688     assert(Operation == OpDefCfa || Operation == OpOffset ||
689            Operation == OpRestore || Operation == OpUndefined ||
690            Operation == OpSameValue || Operation == OpDefCfaRegister ||
691            Operation == OpRelOffset);
692     return U.RI.Register;
693   }
694 
getRegister2()695   unsigned getRegister2() const {
696     assert(Operation == OpRegister);
697     return U.RR.Register2;
698   }
699 
getAddressSpace()700   unsigned getAddressSpace() const {
701     assert(Operation == OpLLVMDefAspaceCfa);
702     return U.RIA.AddressSpace;
703   }
704 
getOffset()705   int64_t getOffset() const {
706     if (Operation == OpLLVMDefAspaceCfa)
707       return U.RIA.Offset;
708     assert(Operation == OpDefCfa || Operation == OpOffset ||
709            Operation == OpRelOffset || Operation == OpDefCfaOffset ||
710            Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize);
711     return U.RI.Offset;
712   }
713 
getCfiLabel()714   MCSymbol *getCfiLabel() const {
715     assert(Operation == OpLabel);
716     return U.CfiLabel;
717   }
718 
getValues()719   StringRef getValues() const {
720     assert(Operation == OpEscape);
721     return StringRef(&Values[0], Values.size());
722   }
723 
getComment()724   StringRef getComment() const { return Comment; }
getLoc()725   SMLoc getLoc() const { return Loc; }
726 };
727 
728 struct MCDwarfFrameInfo {
729   MCDwarfFrameInfo() = default;
730 
731   MCSymbol *Begin = nullptr;
732   MCSymbol *End = nullptr;
733   const MCSymbol *Personality = nullptr;
734   const MCSymbol *Lsda = nullptr;
735   std::vector<MCCFIInstruction> Instructions;
736   unsigned CurrentCfaRegister = 0;
737   unsigned PersonalityEncoding = 0;
738   unsigned LsdaEncoding = 0;
739   uint64_t CompactUnwindEncoding = 0;
740   bool IsSignalFrame = false;
741   bool IsSimple = false;
742   unsigned RAReg = static_cast<unsigned>(INT_MAX);
743   bool IsBKeyFrame = false;
744   bool IsMTETaggedFrame = false;
745 };
746 
747 class MCDwarfFrameEmitter {
748 public:
749   //
750   // This emits the frame info section.
751   //
752   static void Emit(MCObjectStreamer &streamer, MCAsmBackend *MAB, bool isEH);
753   static void encodeAdvanceLoc(MCContext &Context, uint64_t AddrDelta,
754                                SmallVectorImpl<char> &OS);
755 };
756 
757 } // end namespace llvm
758 
759 #endif // LLVM_MC_MCDWARF_H
760