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