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