38 FREInfo<endianness::native> Info;
39 bool CFARegSet =
false;
41 SFrameFRE(
const MCSymbol *Start) : Label(
Start) { Info.Info = 0; }
43 void emitOffset(MCObjectStreamer &S,
FREOffset OffsetSize,
size_t Offset) {
57 void emit(MCObjectStreamer &S,
const MCSymbol *FuncBegin,
58 MCFragment *FDEFrag) {
64 unsigned RegsTracked = 1;
69 Info.setOffsetCount(RegsTracked);
73 Info.setOffsetSize(FREOffset::B1);
75 Info.setOffsetSize(FREOffset::B2);
78 isInt<32>(RAOffset) &&
"Offset too big for sframe");
79 Info.setOffsetSize(FREOffset::B4);
83 Info.setReturnAddressSigned(
false);
89 [[maybe_unused]]
unsigned OffsetsEmitted = 1;
90 emitOffset(S, Info.getOffsetSize(), CFAOffset);
93 emitOffset(S, Info.getOffsetSize(), FPOffset);
97 emitOffset(S, Info.getOffsetSize(), RAOffset);
99 assert(OffsetsEmitted == RegsTracked &&
100 "Didn't emit the right number of offsets");
108 const MCDwarfFrameInfo &DFrame;
118 SFrameFDE(
const MCDwarfFrameInfo &
DF, MCSymbol *FRES)
119 : DFrame(
DF), FREStart(FRES), Frag(nullptr) {}
121 void emit(MCObjectStreamer &S,
const MCSymbol *FRESubSectionStart) {
125 const MCExpr *
V =
C.getAsmInfo().getExprForFDESymbol(
126 &(*DFrame.Begin),
C.getObjectFileInfo()->getFDEEncoding(), S);
170class SFrameEmitterImpl {
171 MCObjectStreamer &Streamer;
182 int8_t FixedRAOffset;
187 bool setCFARegister(SFrameFRE &FRE,
const MCCFIInstruction &
I) {
188 if (
I.getRegister() == SPReg) {
189 FRE.CFARegSet =
true;
193 if (
I.getRegister() == FPReg) {
194 FRE.CFARegSet =
true;
198 Streamer.getContext().reportWarning(
199 I.getLoc(),
"canonical Frame Address not in stack- or frame-pointer. "
200 "Omitting SFrame unwind info for this function");
204 bool setCFAOffset(SFrameFRE &FRE, SMLoc Loc,
size_t Offset) {
205 if (!FRE.CFARegSet) {
206 Streamer.getContext().reportWarning(
207 Loc,
"adjusting CFA offset without a base register. "
208 "Omitting SFrame unwind info for this function");
223 bool isCFIEscapeSafe(SFrameFDE &FDE,
const SFrameFRE &FRE,
224 const MCCFIInstruction &CFI) {
225 const MCAsmInfo &AI = Streamer.getContext().getAsmInfo();
233 dwarf::CFIProgram
P(1,
235 Streamer.getContext().getTargetTriple().getArch());
239 Streamer.getContext().reportWarning(
241 "skipping SFrame FDE; .cfi_escape with unknown effects");
247 for (
const dwarf::CFIProgram::Instruction &
I :
P) {
249 case dwarf::DW_CFA_nop:
251 case dwarf::DW_CFA_val_offset: {
255 auto Reg =
I.getOperandAsUnsigned(
P, 0);
257 assert(
Reg &&
"DW_CFA_val_offset with no register.");
260 auto Opnd =
I.getOperandAsSigned(
P, 1);
261 if (!Opnd || *Opnd != 0)
264 if (!SPOk || *
Reg == RAReg || *
Reg == FPReg) {
265 StringRef
RN = *
Reg == SPReg
267 : (*
Reg == FPReg ?
"FP reg " :
"RA reg ");
268 Streamer.getContext().reportWarning(
271 "skipping SFrame FDE; .cfi_escape DW_CFA_val_offset with ") +
276 case dwarf::DW_CFA_expression: {
279 auto Reg =
I.getOperandAsUnsigned(
P, 0);
281 Streamer.getContext().reportWarning(
283 "skipping SFrame FDE; .cfi_escape with unknown effects");
286 if (*
Reg == SPReg || *
Reg == RAReg || *
Reg == FPReg) {
287 StringRef
RN = *
Reg == SPReg
289 : (*
Reg == FPReg ?
"FP reg " :
"RA reg ");
290 Streamer.getContext().reportWarning(
293 "skipping SFrame FDE; .cfi_escape DW_CFA_expression with ") +
298 case dwarf::DW_CFA_GNU_args_size: {
299 auto Size =
I.getOperandAsSigned(
P, 0);
304 Streamer.getContext().reportWarning(
306 Twine(
"skipping SFrame FDE; .cfi_escape DW_CFA_GNU_args_size "
307 "with non frame-pointer CFA"));
315 case dwarf::DW_CFA_advance_loc:
316 case dwarf::DW_CFA_offset:
317 case dwarf::DW_CFA_restore:
318 case dwarf::DW_CFA_set_loc:
319 case dwarf::DW_CFA_advance_loc1:
320 case dwarf::DW_CFA_advance_loc2:
321 case dwarf::DW_CFA_advance_loc4:
322 case dwarf::DW_CFA_offset_extended:
323 case dwarf::DW_CFA_restore_extended:
324 case dwarf::DW_CFA_undefined:
325 case dwarf::DW_CFA_same_value:
326 case dwarf::DW_CFA_register:
327 case dwarf::DW_CFA_remember_state:
328 case dwarf::DW_CFA_restore_state:
329 case dwarf::DW_CFA_def_cfa:
330 case dwarf::DW_CFA_def_cfa_register:
331 case dwarf::DW_CFA_def_cfa_offset:
332 case dwarf::DW_CFA_def_cfa_expression:
333 case dwarf::DW_CFA_offset_extended_sf:
334 case dwarf::DW_CFA_def_cfa_sf:
335 case dwarf::DW_CFA_def_cfa_offset_sf:
336 case dwarf::DW_CFA_val_offset_sf:
337 case dwarf::DW_CFA_val_expression:
338 case dwarf::DW_CFA_MIPS_advance_loc8:
339 case dwarf::DW_CFA_AARCH64_negate_ra_state_with_pc:
340 case dwarf::DW_CFA_AARCH64_negate_ra_state:
341 case dwarf::DW_CFA_AARCH64_set_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");
351 Streamer.getContext().reportWarning(
353 "skipping SFrame FDE; .cfi_escape with unknown effects");
362 bool handleCFI(SFrameFDE &FDE, SFrameFRE &FRE,
const MCCFIInstruction &CFI) {
365 return setCFARegister(FRE, CFI);
368 if (!setCFARegister(FRE, CFI))
386 return setCFAOffset(FRE, CFI.
getLoc(), FRE.CFAOffset + CFI.
getOffset());
388 if (FDE.FREs.size() == 1) {
392 Streamer.getContext().reportWarning(
393 CFI.
getLoc(),
"skipping SFrame FDE; .cfi_remember_state without "
394 "prior SFrame FRE state");
397 FDE.SaveState.push_back(FRE);
402 FRE.FPOffset = FDE.FREs.front().FPOffset;
404 FRE.RAOffset = FDE.FREs.front().RAOffset;
409 assert(!FDE.SaveState.empty() &&
410 "cfi_restore_state without cfi_save_state");
411 FRE = FDE.SaveState.pop_back_val();
416 return isCFIEscapeSafe(FDE, FRE, CFI);
425 SFrameEmitterImpl(MCObjectStreamer &Streamer)
426 : Streamer(Streamer), TotalFREs(0) {
427 assert(Streamer.getContext()
431 FDEs.reserve(Streamer.getDwarfFrameInfos().size());
432 SFrameABI = *Streamer.getContext().getObjectFileInfo()->getSFrameABIArch();
434 case ABI::AArch64EndianBig:
435 case ABI::AArch64EndianLittle:
441 case ABI::AMD64EndianLittle:
445 RAReg =
static_cast<unsigned>(INT_MAX);
451 FDESubSectionStart = Streamer.getContext().createTempSymbol();
452 FRESubSectionStart = Streamer.getContext().createTempSymbol();
453 FRESubSectionEnd = Streamer.getContext().createTempSymbol();
456 bool atSameLocation(
const MCSymbol *
Left,
const MCSymbol *
Right) {
457 return Left !=
nullptr &&
Right !=
nullptr &&
458 Left->getFragment() ==
Right->getFragment() &&
462 bool equalIgnoringLocation(
const SFrameFRE &
Left,
const SFrameFRE &
Right) {
463 return Left.CFAOffset ==
Right.CFAOffset &&
465 Left.Info.getFREInfo() ==
Right.Info.getFREInfo() &&
469 void buildSFDE(
const MCDwarfFrameInfo &
DF) {
473 if (atSameLocation(
DF.Begin,
DF.End))
476 SFrameFDE FDE(
DF, Streamer.getContext().createTempSymbol());
483 if (
DF.RAReg != RAReg) {
484 Streamer.getContext().reportWarning(
485 SMLoc(),
"non-default RA register in .cfi_return_column " +
487 ". Omitting SFrame unwind info for this function");
491 SFrameFRE BaseFRE(LastLabel);
493 for (
const auto &CFI :
494 Streamer.getContext().getAsmInfo().getInitialFrameState())
495 if (!handleCFI(FDE, BaseFRE, CFI))
498 FDE.FREs.push_back(BaseFRE);
500 for (
const auto &CFI :
DF.Instructions) {
508 if (L && !
L->isDefined())
511 SFrameFRE FRE = FDE.FREs.back();
512 if (!handleCFI(FDE, FRE, CFI))
516 if (equalIgnoringLocation(FRE, FDE.FREs.back()))
521 if (atSameLocation(LastLabel, L))
522 FDE.FREs.back() = FRE;
524 FDE.FREs.push_back(FRE);
525 FDE.FREs.back().Label =
L;
532 TotalFREs += FDE.FREs.size();
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));
545 Streamer.emitInt8(
static_cast<uint8_t
>(SFrameABI));
547 Streamer.emitInt8(0);
549 Streamer.emitInt8(FixedRAOffset);
551 Streamer.emitInt8(0);
553 Streamer.emitInt32(FDEs.size());
555 Streamer.emitInt32(TotalFREs);
558 Streamer.emitAbsoluteSymbolDiff(FRESubSectionEnd, FRESubSectionStart,
561 Streamer.emitInt32(0);
563 Streamer.emitInt32(FDEs.size() *
564 sizeof(sframe::FuncDescEntry<endianness::native>));
568 Streamer.emitLabel(FDESubSectionStart);
569 for (
auto &FDE : FDEs) {
570 FDE.emit(Streamer, FRESubSectionStart);
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);
581 Streamer.emitLabel(FRESubSectionEnd);
603 for (
const auto &DFrame : FrameArray)
606 MCSection *Section = Context.getObjectFileInfo()->getSFrameSection();
608 Section->ensureMinAlignment(
Align(8));
610 MCSymbol *SectionStart = Context.createTempSymbol();
621 if (FDEFrag ==
nullptr) {
629 I.setFREType(FREType::Addr1);
631 I.setFREType(FREType::Addr2);
634 I.setFREType(FREType::Addr4);
636 I.setFDEType(FDEType::PCInc);
647 I.Info = FDEData.back();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
dxil DXContainer Global Emitter
static RegisterPass< DebugifyFunctionPass > DF("debugify-function", "Attach debug info to a function")
This file contains data-structure definitions and constants to support unwinding based on ....
std::unique_ptr< MCStreamer > && Streamer
Represent a constant reference to an array (0 or more elements consecutively in memory),...
bool isLittleEndian() const
True if the target is little endian.
unsigned getCodePointerSize() const
Get the code pointer size in bytes.
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
MCSymbol * getLabel() const
unsigned getRegister() const
OpType getOperation() const
StringRef getValues() const
int64_t getOffset() const
Context object for machine code objects.
static MCFixupKind getDataKindForSize(unsigned Size)
Return the generic fixup kind for a value with the given size.
static MCFixup create(uint32_t Offset, const MCExpr *Value, MCFixupKind Kind, bool PCRel=false)
Consider bit fields if we need more flags.
MutableArrayRef< char > getVarContents()
Streaming object file generation interface.
void emitSFrameCalculateFuncOffset(const MCSymbol *FunCabsel, const MCSymbol *FREBegin, MCFragment *FDEFrag, SMLoc Loc)
void emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) override
Emit the absolute difference between two symbols if possible.
static LLVM_ABI void emit(MCObjectStreamer &Streamer)
static LLVM_ABI void encodeFuncOffset(MCContext &C, uint64_t Offset, SmallVectorImpl< char > &Out, MCFragment *FDEFrag)
Instances of this class represent a uniqued identifier for a section in the current translation unit.
MCFragment * getCurrentFragment() const
MCContext & getContext() const
void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
void emitInt16(uint64_t Value)
void emitInt32(uint64_t Value)
void emitInt8(uint64_t Value)
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
constexpr size_t size() const
Get the string size.
@ Valid
The data is already valid.
FREOffset
Size of stack offsets. Bits 6-7 of FREInfo.Info.
FREType
SFrame FRE Types. Bits 0-3 of FuncDescEntry.Info.
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
This is an optimization pass for GlobalISel generic memory operations.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
This struct is a compact representation of a valid (non-zero power of two) alignment.
BaseReg getBaseRegister() const
void setBaseRegister(BaseReg Reg)