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