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