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) {
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);
641 Out.push_back(
I.getFuncInfo());
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 container 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.
const MCExpr * getExprForFDESymbol(const MCSymbol *Sym, unsigned Encoding, MCStreamer &Streamer) const
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.
const MCAsmInfo & getAsmInfo() const
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...
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)