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