brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.8 KiB · e0a90df Raw
668 lines · cpp
1//===- lib/MC/MCSFrame.cpp - MCSFrame implementation ----------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/MC/MCSFrame.h"10#include "llvm/BinaryFormat/SFrame.h"11#include "llvm/DebugInfo/DWARF/LowLevel/DWARFCFIProgram.h"12#include "llvm/DebugInfo/DWARF/LowLevel/DWARFDataExtractorSimple.h"13#include "llvm/MC/MCAsmInfo.h"14#include "llvm/MC/MCContext.h"15#include "llvm/MC/MCObjectFileInfo.h"16#include "llvm/MC/MCObjectStreamer.h"17#include "llvm/MC/MCSection.h"18#include "llvm/MC/MCSymbol.h"19#include "llvm/Support/Endian.h"20#include "llvm/Support/EndianStream.h"21 22using namespace llvm;23using namespace sframe;24 25namespace {26 27// High-level structure to track info needed to emit a28// sframe_frame_row_entry_addrX. On disk these have both a fixed portion of type29// sframe_frame_row_entry_addrX and trailing data of X * S bytes, where X is the30// datum size, and S is 1, 2, or 3 depending on which of CFA, SP, and FP are31// being tracked.32struct SFrameFRE {33  // An FRE describes how to find the registers when the PC is at this34  // Label from function start.35  const MCSymbol *Label = nullptr;36  size_t CFAOffset = 0;37  size_t FPOffset = 0;38  size_t RAOffset = 0;39  FREInfo<endianness::native> Info;40  bool CFARegSet = false;41 42  SFrameFRE(const MCSymbol *Start) : Label(Start) { Info.Info = 0; }43 44  void emitOffset(MCObjectStreamer &S, FREOffset OffsetSize, size_t Offset) {45    switch (OffsetSize) {46    case (FREOffset::B1):47      S.emitInt8(Offset);48      return;49    case (FREOffset::B2):50      S.emitInt16(Offset);51      return;52    case (FREOffset::B4):53      S.emitInt32(Offset);54      return;55    }56  }57 58  void emit(MCObjectStreamer &S, const MCSymbol *FuncBegin,59            MCFragment *FDEFrag) {60    S.emitSFrameCalculateFuncOffset(FuncBegin, Label, FDEFrag, SMLoc());61 62    // fre_cfa_base_reg_id already set during parsing63 64    // fre_offset_count65    unsigned RegsTracked = 1; // always track the cfa.66    if (FPOffset != 0)67      ++RegsTracked;68    if (RAOffset != 0)69      ++RegsTracked;70    Info.setOffsetCount(RegsTracked);71 72    // fre_offset_size73    if (isInt<8>(CFAOffset) && isInt<8>(FPOffset) && isInt<8>(RAOffset))74      Info.setOffsetSize(FREOffset::B1);75    else if (isInt<16>(CFAOffset) && isInt<16>(FPOffset) && isInt<16>(RAOffset))76      Info.setOffsetSize(FREOffset::B2);77    else {78      assert(isInt<32>(CFAOffset) && isInt<32>(FPOffset) &&79             isInt<32>(RAOffset) && "Offset too big for sframe");80      Info.setOffsetSize(FREOffset::B4);81    }82 83    // No support for fre_mangled_ra_p yet.84    Info.setReturnAddressSigned(false);85 86    // sframe_fre_info_word87    S.emitInt8(Info.getFREInfo());88 89    // FRE Offsets90    [[maybe_unused]] unsigned OffsetsEmitted = 1;91    emitOffset(S, Info.getOffsetSize(), CFAOffset);92    if (FPOffset) {93      ++OffsetsEmitted;94      emitOffset(S, Info.getOffsetSize(), FPOffset);95    }96    if (RAOffset) {97      ++OffsetsEmitted;98      emitOffset(S, Info.getOffsetSize(), RAOffset);99    }100    assert(OffsetsEmitted == RegsTracked &&101           "Didn't emit the right number of offsets");102  }103};104 105// High-level structure to track info needed to emit a sframe_func_desc_entry106// and its associated FREs.107struct SFrameFDE {108  // Reference to the original dwarf frame to avoid copying.109  const MCDwarfFrameInfo &DFrame;110  // Label where this FDE's FREs start.111  MCSymbol *FREStart;112  // Frag where this FDE is emitted.113  MCFragment *Frag;114  // Unwinding fres115  SmallVector<SFrameFRE> FREs;116  // .cfi_remember_state stack117  SmallVector<SFrameFRE> SaveState;118 119  SFrameFDE(const MCDwarfFrameInfo &DF, MCSymbol *FRES)120      : DFrame(DF), FREStart(FRES), Frag(nullptr) {}121 122  void emit(MCObjectStreamer &S, const MCSymbol *FRESubSectionStart) {123    MCContext &C = S.getContext();124 125    // sfde_func_start_address126    const MCExpr *V = C.getAsmInfo()->getExprForFDESymbol(127        &(*DFrame.Begin), C.getObjectFileInfo()->getFDEEncoding(), S);128    S.emitValue(V, sizeof(int32_t));129 130    // sfde_func_size131    S.emitAbsoluteSymbolDiff(DFrame.End, DFrame.Begin, sizeof(uint32_t));132 133    // sfde_func_start_fre_off134    auto *F = S.getCurrentFragment();135    const MCExpr *Diff = MCBinaryExpr::createSub(136        MCSymbolRefExpr::create(FREStart, C),137        MCSymbolRefExpr::create(FRESubSectionStart, C), C);138 139    F->addFixup(MCFixup::create(F->getContents().size(), Diff,140                                MCFixup::getDataKindForSize(4)));141    S.emitInt32(0);142 143    // sfde_func_num_fres144    S.emitInt32(FREs.size());145 146    // sfde_func_info word147 148    // All FREs within an FDE share the same sframe::FREType::AddrX. The value149    // of 'X' is determined by the FRE with the largest offset, which is the150    // last. This offset isn't known until relax time, so emit a frag which can151    // calculate that now.152    //153    // At relax time, this FDE frag calculates the proper AddrX value (as well154    // as the rest of the FDE FuncInfo word). Subsequent FRE frags will read it155    // from this frag and emit the proper number of bytes.156    Frag = S.getCurrentFragment();157    S.emitSFrameCalculateFuncOffset(DFrame.Begin, FREs.back().Label, nullptr,158                                    SMLoc());159 160    // sfde_func_rep_size. Not relevant in non-PCMASK fdes.161    S.emitInt8(0);162 163    // sfde_func_padding2164    S.emitInt16(0);165  }166};167 168// Emitting these field-by-field, instead of constructing the actual structures169// lets Streamer do target endian-fixups for free.170 171class SFrameEmitterImpl {172  MCObjectStreamer &Streamer;173  SmallVector<SFrameFDE> FDEs;174  uint32_t TotalFREs;175  ABI SFrameABI;176  // Target-specific convenience variables to detect when a CFI instruction177  // references these registers. Unlike in dwarf frame descriptions, they never178  // escape into the sframe section itself. TODO: These should be retrieved from179  // the target.180  unsigned SPReg;181  unsigned FPReg;182  unsigned RAReg;183  int8_t FixedRAOffset;184  MCSymbol *FDESubSectionStart;185  MCSymbol *FRESubSectionStart;186  MCSymbol *FRESubSectionEnd;187 188  bool setCFARegister(SFrameFRE &FRE, const MCCFIInstruction &I) {189    if (I.getRegister() == SPReg) {190      FRE.CFARegSet = true;191      FRE.Info.setBaseRegister(BaseReg::SP);192      return true;193    }194    if (I.getRegister() == FPReg) {195      FRE.CFARegSet = true;196      FRE.Info.setBaseRegister(BaseReg::FP);197      return true;198    }199    Streamer.getContext().reportWarning(200        I.getLoc(), "canonical Frame Address not in stack- or frame-pointer. "201                    "Omitting SFrame unwind info for this function");202    return false;203  }204 205  bool setCFAOffset(SFrameFRE &FRE, SMLoc Loc, size_t Offset) {206    if (!FRE.CFARegSet) {207      Streamer.getContext().reportWarning(208          Loc, "adjusting CFA offset without a base register. "209               "Omitting SFrame unwind info for this function");210      return false;211    }212    FRE.CFAOffset = Offset;213    return true;214  }215 216  // Technically, the escape data could be anything, but it is commonly a dwarf217  // CFI program. Even then, it could contain an arbitrarily complicated Dwarf218  // expression. Following gnu-gas, look for certain common cases that could219  // invalidate an FDE, emit a warning for those sequences, and don't generate220  // an FDE in those cases. Allow any that are known safe. It is likely that221  // more thorough test cases could refine this code, but it handles the most222  // important ones compatibly with gas.223  // Returns true if the CFI escape sequence is safe for sframes.224  bool isCFIEscapeSafe(SFrameFDE &FDE, const SFrameFRE &FRE,225                       const MCCFIInstruction &CFI) {226    const MCAsmInfo *AI = Streamer.getContext().getAsmInfo();227    DWARFDataExtractorSimple data(CFI.getValues(), AI->isLittleEndian(),228                                  AI->getCodePointerSize());229 230    // Normally, both alignment factors are extracted from the enclosing Dwarf231    // FDE or CIE. We don't have one here. Alignments are used for scaling232    // factors for ops like CFA_def_cfa_offset_sf. But this particular function233    // is only interested in registers.234    dwarf::CFIProgram P(/*CodeAlignmentFactor=*/1,235                        /*DataAlignmentFactor=*/1,236                        Streamer.getContext().getTargetTriple().getArch());237    uint64_t Offset = 0;238    if (P.parse(data, &Offset, CFI.getValues().size())) {239      // Not a parsable dwarf expression. Assume the worst.240      Streamer.getContext().reportWarning(241          CFI.getLoc(),242          "skipping SFrame FDE; .cfi_escape with unknown effects");243      return false;244    }245 246    // This loop deals with dwarf::CFIProgram::Instructions. Everywhere else247    // this file deals with MCCFIInstructions.248    for (const dwarf::CFIProgram::Instruction &I : P) {249      switch (I.Opcode) {250      case dwarf::DW_CFA_nop:251        break;252      case dwarf::DW_CFA_val_offset: {253        // First argument is a register. Anything that touches CFA, FP, or RA is254        // a problem, but allow others through. As an even more special case,255        // allow SP + 0.256        auto Reg = I.getOperandAsUnsigned(P, 0);257        // The parser should have failed in this case.258        assert(Reg && "DW_CFA_val_offset with no register.");259        bool SPOk = true;260        if (*Reg == SPReg) {261          auto Opnd = I.getOperandAsSigned(P, 1);262          if (!Opnd || *Opnd != 0)263            SPOk = false;264        }265        if (!SPOk || *Reg == RAReg || *Reg == FPReg) {266          StringRef RN = *Reg == SPReg267                             ? "SP reg "268                             : (*Reg == FPReg ? "FP reg " : "RA reg ");269          Streamer.getContext().reportWarning(270              CFI.getLoc(),271              Twine(272                  "skipping SFrame FDE; .cfi_escape DW_CFA_val_offset with ") +273                  RN + Twine(*Reg));274          return false;275        }276      } break;277      case dwarf::DW_CFA_expression: {278        // First argument is a register. Anything that touches CFA, FP, or RA is279        // a problem, but allow others through.280        auto Reg = I.getOperandAsUnsigned(P, 0);281        if (!Reg) {282          Streamer.getContext().reportWarning(283              CFI.getLoc(),284              "skipping SFrame FDE; .cfi_escape with unknown effects");285          return false;286        }287        if (*Reg == SPReg || *Reg == RAReg || *Reg == FPReg) {288          StringRef RN = *Reg == SPReg289                             ? "SP reg "290                             : (*Reg == FPReg ? "FP reg " : "RA reg ");291          Streamer.getContext().reportWarning(292              CFI.getLoc(),293              Twine(294                  "skipping SFrame FDE; .cfi_escape DW_CFA_expression with ") +295                  RN + Twine(*Reg));296          return false;297        }298      } break;299      case dwarf::DW_CFA_GNU_args_size: {300        auto Size = I.getOperandAsSigned(P, 0);301        // Zero size doesn't affect the cfa.302        if (Size && *Size == 0)303          break;304        if (FRE.Info.getBaseRegister() != BaseReg::FP) {305          Streamer.getContext().reportWarning(306              CFI.getLoc(),307              Twine("skipping SFrame FDE; .cfi_escape DW_CFA_GNU_args_size "308                    "with non frame-pointer CFA"));309          return false;310        }311      } break;312      // Cases that gas doesn't specially handle. TODO: Some of these could be313      // analyzed and handled instead of just punting. But these are uncommon,314      // or should be written as normal cfi directives. Some will need fixes to315      // the scaling factor.316      case dwarf::DW_CFA_advance_loc:317      case dwarf::DW_CFA_offset:318      case dwarf::DW_CFA_restore:319      case dwarf::DW_CFA_set_loc:320      case dwarf::DW_CFA_advance_loc1:321      case dwarf::DW_CFA_advance_loc2:322      case dwarf::DW_CFA_advance_loc4:323      case dwarf::DW_CFA_offset_extended:324      case dwarf::DW_CFA_restore_extended:325      case dwarf::DW_CFA_undefined:326      case dwarf::DW_CFA_same_value:327      case dwarf::DW_CFA_register:328      case dwarf::DW_CFA_remember_state:329      case dwarf::DW_CFA_restore_state:330      case dwarf::DW_CFA_def_cfa:331      case dwarf::DW_CFA_def_cfa_register:332      case dwarf::DW_CFA_def_cfa_offset:333      case dwarf::DW_CFA_def_cfa_expression:334      case dwarf::DW_CFA_offset_extended_sf:335      case dwarf::DW_CFA_def_cfa_sf:336      case dwarf::DW_CFA_def_cfa_offset_sf:337      case dwarf::DW_CFA_val_offset_sf:338      case dwarf::DW_CFA_val_expression:339      case dwarf::DW_CFA_MIPS_advance_loc8:340      case dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc:341      case dwarf::DW_CFA_AARCH64_negate_ra_state:342      case dwarf::DW_CFA_LLVM_def_aspace_cfa:343      case dwarf::DW_CFA_LLVM_def_aspace_cfa_sf:344        Streamer.getContext().reportWarning(345            CFI.getLoc(), "skipping SFrame FDE; .cfi_escape "346                          "CFA expression with unknown side effects");347        return false;348      default:349        // Dwarf expression was only partially valid, and user could have350        // written anything.351        Streamer.getContext().reportWarning(352            CFI.getLoc(),353            "skipping SFrame FDE; .cfi_escape with unknown effects");354        return false;355      }356    }357    return true;358  }359 360  // Add the effects of CFI to the current FDE, creating a new FRE when361  // necessary. Return true if the CFI is representable in the sframe format.362  bool handleCFI(SFrameFDE &FDE, SFrameFRE &FRE, const MCCFIInstruction &CFI) {363    switch (CFI.getOperation()) {364    case MCCFIInstruction::OpDefCfaRegister:365      return setCFARegister(FRE, CFI);366    case MCCFIInstruction::OpDefCfa:367    case MCCFIInstruction::OpLLVMDefAspaceCfa:368      if (!setCFARegister(FRE, CFI))369        return false;370      return setCFAOffset(FRE, CFI.getLoc(), CFI.getOffset());371    case MCCFIInstruction::OpOffset:372      if (CFI.getRegister() == FPReg)373        FRE.FPOffset = CFI.getOffset();374      else if (CFI.getRegister() == RAReg)375        FRE.RAOffset = CFI.getOffset();376      return true;377    case MCCFIInstruction::OpRelOffset:378      if (CFI.getRegister() == FPReg)379        FRE.FPOffset += CFI.getOffset();380      else if (CFI.getRegister() == RAReg)381        FRE.RAOffset += CFI.getOffset();382      return true;383    case MCCFIInstruction::OpDefCfaOffset:384      return setCFAOffset(FRE, CFI.getLoc(), CFI.getOffset());385    case MCCFIInstruction::OpAdjustCfaOffset:386      return setCFAOffset(FRE, CFI.getLoc(), FRE.CFAOffset + CFI.getOffset());387    case MCCFIInstruction::OpRememberState:388      if (FDE.FREs.size() == 1) {389        // Error for gas compatibility: If the initial FRE isn't complete,390        // then any state is incomplete.  FIXME: Dwarf doesn't error here.391        // Why should sframe?392        Streamer.getContext().reportWarning(393            CFI.getLoc(), "skipping SFrame FDE; .cfi_remember_state without "394                          "prior SFrame FRE state");395        return false;396      }397      FDE.SaveState.push_back(FRE);398      return true;399    case MCCFIInstruction::OpRestore:400      // The first FRE generated has the original state.401      if (CFI.getRegister() == FPReg)402        FRE.FPOffset = FDE.FREs.front().FPOffset;403      else if (CFI.getRegister() == RAReg)404        FRE.RAOffset = FDE.FREs.front().RAOffset;405      return true;406    case MCCFIInstruction::OpRestoreState:407      // The cfi parser will have caught unbalanced directives earlier, so a408      // mismatch here is an implementation error.409      assert(!FDE.SaveState.empty() &&410             "cfi_restore_state without cfi_save_state");411      FRE = FDE.SaveState.pop_back_val();412      return true;413    case MCCFIInstruction::OpEscape:414      // This is a string of bytes that contains an arbitrary dwarf-expression415      // that may or may not affect unwind info.416      return isCFIEscapeSafe(FDE, FRE, CFI);417    default:418      // Instructions that don't affect the CFA, RA, and FP can be safely419      // ignored.420      return true;421    }422  }423 424public:425  SFrameEmitterImpl(MCObjectStreamer &Streamer)426      : Streamer(Streamer), TotalFREs(0) {427    assert(Streamer.getContext()428               .getObjectFileInfo()429               ->getSFrameABIArch()430               .has_value());431    FDEs.reserve(Streamer.getDwarfFrameInfos().size());432    SFrameABI = *Streamer.getContext().getObjectFileInfo()->getSFrameABIArch();433    switch (SFrameABI) {434    case ABI::AArch64EndianBig:435    case ABI::AArch64EndianLittle:436      SPReg = 31;437      RAReg = 29;438      FPReg = 30;439      FixedRAOffset = 0;440      break;441    case ABI::AMD64EndianLittle:442      SPReg = 7;443      // RARegister untracked in this abi. Value chosen to match444      // MCDwarfFrameInfo constructor.445      RAReg = static_cast<unsigned>(INT_MAX);446      FPReg = 6;447      FixedRAOffset = -8;448      break;449    }450 451    FDESubSectionStart = Streamer.getContext().createTempSymbol();452    FRESubSectionStart = Streamer.getContext().createTempSymbol();453    FRESubSectionEnd = Streamer.getContext().createTempSymbol();454  }455 456  bool atSameLocation(const MCSymbol *Left, const MCSymbol *Right) {457    return Left != nullptr && Right != nullptr &&458           Left->getFragment() == Right->getFragment() &&459           Left->getOffset() == Right->getOffset();460  }461 462  bool equalIgnoringLocation(const SFrameFRE &Left, const SFrameFRE &Right) {463    return Left.CFAOffset == Right.CFAOffset &&464           Left.FPOffset == Right.FPOffset && Left.RAOffset == Right.RAOffset &&465           Left.Info.getFREInfo() == Right.Info.getFREInfo() &&466           Left.CFARegSet == Right.CFARegSet;467  }468 469  void buildSFDE(const MCDwarfFrameInfo &DF) {470    // Functions with zero size can happen with assembler macros and471    // machine-generated code. They don't need unwind info at all, so472    // no need to warn.473    if (atSameLocation(DF.Begin, DF.End))474      return;475    bool Valid = true;476    SFrameFDE FDE(DF, Streamer.getContext().createTempSymbol());477    // This would have been set via ".cfi_return_column", but478    // MCObjectStreamer doesn't emit an MCCFIInstruction for that. It just479    // sets the DF.RAReg.480    // FIXME: This also prevents providing a proper location for the error.481    // LLVM doesn't change the return column itself, so this was482    // hand-written assembly.483    if (DF.RAReg != RAReg) {484      Streamer.getContext().reportWarning(485          SMLoc(), "non-default RA register in .cfi_return_column " +486                       Twine(DF.RAReg) +487                       ". Omitting SFrame unwind info for this function");488      Valid = false;489    }490    MCSymbol *LastLabel = DF.Begin;491    SFrameFRE BaseFRE(LastLabel);492    if (!DF.IsSimple) {493      for (const auto &CFI :494           Streamer.getContext().getAsmInfo()->getInitialFrameState())495        if (!handleCFI(FDE, BaseFRE, CFI))496          Valid = false;497    }498    FDE.FREs.push_back(BaseFRE);499 500    for (const auto &CFI : DF.Instructions) {501      // Instructions from InitialFrameState may not have a label, but if these502      // instructions don't, then they are in dead code or otherwise unused.503      // TODO: This check follows MCDwarf.cpp504      // FrameEmitterImplementation::emitCFIInstructions, but nothing in the505      // testsuite triggers it. We should see if it can be removed in both506      // places, or alternately, add a test to exercise it.507      auto *L = CFI.getLabel();508      if (L && !L->isDefined())509        continue;510 511      SFrameFRE FRE = FDE.FREs.back();512      if (!handleCFI(FDE, FRE, CFI))513        Valid = false;514 515      // If nothing relevant but the location changed, don't add the FRE.516      if (equalIgnoringLocation(FRE, FDE.FREs.back()))517        continue;518 519      // If the location stayed the same, then update the current520      // row. Otherwise, add a new one.521      if (atSameLocation(LastLabel, L))522        FDE.FREs.back() = FRE;523      else {524        FDE.FREs.push_back(FRE);525        FDE.FREs.back().Label = L;526        LastLabel = L;527      }528    }529 530    if (Valid) {531      FDEs.push_back(FDE);532      TotalFREs += FDE.FREs.size();533    }534  }535 536  void emitPreamble() {537    Streamer.emitInt16(Magic);538    Streamer.emitInt8(static_cast<uint8_t>(Version::V2));539    Streamer.emitInt8(static_cast<uint8_t>(Flags::FDEFuncStartPCRel));540  }541 542  void emitHeader() {543    emitPreamble();544    // sfh_abi_arch545    Streamer.emitInt8(static_cast<uint8_t>(SFrameABI));546    // sfh_cfa_fixed_fp_offset547    Streamer.emitInt8(0);548    // sfh_cfa_fixed_ra_offset549    Streamer.emitInt8(FixedRAOffset);550    // sfh_auxhdr_len551    Streamer.emitInt8(0);552    // shf_num_fdes553    Streamer.emitInt32(FDEs.size());554    // shf_num_fres555    Streamer.emitInt32(TotalFREs);556 557    // shf_fre_len558    Streamer.emitAbsoluteSymbolDiff(FRESubSectionEnd, FRESubSectionStart,559                                    sizeof(int32_t));560    // shf_fdeoff. With no sfh_auxhdr, these immediately follow this header.561    Streamer.emitInt32(0);562    // shf_freoff563    Streamer.emitInt32(FDEs.size() *564                       sizeof(sframe::FuncDescEntry<endianness::native>));565  }566 567  void emitFDEs() {568    Streamer.emitLabel(FDESubSectionStart);569    for (auto &FDE : FDEs) {570      FDE.emit(Streamer, FRESubSectionStart);571    }572  }573 574  void emitFREs() {575    Streamer.emitLabel(FRESubSectionStart);576    for (auto &FDE : FDEs) {577      Streamer.emitLabel(FDE.FREStart);578      for (auto &FRE : FDE.FREs)579        FRE.emit(Streamer, FDE.DFrame.Begin, FDE.Frag);580    }581    Streamer.emitLabel(FRESubSectionEnd);582  }583};584 585} // end anonymous namespace586 587void MCSFrameEmitter::emit(MCObjectStreamer &Streamer) {588  MCContext &Context = Streamer.getContext();589  // If this target doesn't support sframes, return now. Gas doesn't warn in590  // this case, but if we want to, it should be done at option-parsing time,591  // rather than here.592  if (!Streamer.getContext()593           .getObjectFileInfo()594           ->getSFrameABIArch()595           .has_value())596    return;597 598  SFrameEmitterImpl Emitter(Streamer);599  ArrayRef<MCDwarfFrameInfo> FrameArray = Streamer.getDwarfFrameInfos();600 601  // Both the header itself and the FDEs include various offsets and counts.602  // Therefore, all of this must be precomputed.603  for (const auto &DFrame : FrameArray)604    Emitter.buildSFDE(DFrame);605 606  MCSection *Section = Context.getObjectFileInfo()->getSFrameSection();607  // Not strictly necessary, but gas always aligns to 8, so match that.608  Section->ensureMinAlignment(Align(8));609  Streamer.switchSection(Section);610  MCSymbol *SectionStart = Context.createTempSymbol();611  Streamer.emitLabel(SectionStart);612  Emitter.emitHeader();613  Emitter.emitFDEs();614  Emitter.emitFREs();615}616 617void MCSFrameEmitter::encodeFuncOffset(MCContext &C, uint64_t Offset,618                                       SmallVectorImpl<char> &Out,619                                       MCFragment *FDEFrag) {620  // If encoding into the FDE Frag itself, generate the sfde_func_info.621  if (FDEFrag == nullptr) {622    // sfde_func_info623 624    // Offset is the difference between the function start label and the final625    // FRE's offset, which is the max offset for this FDE.626    FDEInfo<endianness::native> I;627    I.Info = 0;628    if (isUInt<8>(Offset))629      I.setFREType(FREType::Addr1);630    else if (isUInt<16>(Offset))631      I.setFREType(FREType::Addr2);632    else {633      assert(isUInt<32>(Offset));634      I.setFREType(FREType::Addr4);635    }636    I.setFDEType(FDEType::PCInc);637    // TODO: When we support pauth keys, this will need to be retrieved638    // from the frag itself.639    I.setPAuthKey(0);640 641    Out.push_back(I.getFuncInfo());642    return;643  }644 645  const auto &FDEData = FDEFrag->getVarContents();646  FDEInfo<endianness::native> I;647  I.Info = FDEData.back();648  FREType T = I.getFREType();649  llvm::endianness E = C.getAsmInfo()->isLittleEndian()650                           ? llvm::endianness::little651                           : llvm::endianness::big;652  // sfre_start_address653  switch (T) {654  case FREType::Addr1:655    assert(isUInt<8>(Offset) && "Miscalculated Sframe FREType");656    support::endian::write<uint8_t>(Out, Offset, E);657    break;658  case FREType::Addr2:659    assert(isUInt<16>(Offset) && "Miscalculated Sframe FREType");660    support::endian::write<uint16_t>(Out, Offset, E);661    break;662  case FREType::Addr4:663    assert(isUInt<32>(Offset) && "Miscalculated Sframe FREType");664    support::endian::write<uint32_t>(Out, Offset, E);665    break;666  }667}668