LLVM: lib/MC/MCSFrame.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
21
22using namespace llvm;
23using namespace sframe;
24
25namespace {
26
27
28
29
30
31
32struct SFrameFRE {
33
34
35 const MCSymbol *Label = nullptr;
36 size_t CFAOffset = 0;
37 size_t FPOffset = 0;
38 size_t RAOffset = 0;
39 FREInfoendianness::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):
48 return;
49 case (FREOffset::B2):
51 return;
52 case (FREOffset::B4):
54 return;
55 }
56 }
57
58 void emit(MCObjectStreamer &S, const MCSymbol *FuncBegin,
59 MCFragment *FDEFrag) {
61
62
63
64
65 unsigned RegsTracked = 1;
66 if (FPOffset != 0)
67 ++RegsTracked;
68 if (RAOffset != 0)
69 ++RegsTracked;
70 Info.setOffsetCount(RegsTracked);
71
72
74 Info.setOffsetSize(FREOffset::B1);
76 Info.setOffsetSize(FREOffset::B2);
77 else {
79 isInt<32>(RAOffset) && "Offset too big for sframe");
80 Info.setOffsetSize(FREOffset::B4);
81 }
82
83
84 Info.setReturnAddressSigned(false);
85
86
87 S.emitInt8(Info.getFREInfo());
88
89
90 [[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
106
107struct SFrameFDE {
108
109 const MCDwarfFrameInfo &DFrame;
110
112
113 MCFragment *Frag;
114
116
118
119 SFrameFDE(const MCDwarfFrameInfo &DF, MCSymbol *FRES)
120 : DFrame(DF), FREStart(FRES), Frag(nullptr) {}
121
122 void emit(MCObjectStreamer &S, const MCSymbol *FRESubSectionStart) {
124
125
126 const MCExpr *V = C.getAsmInfo()->getExprForFDESymbol(
127 &(*DFrame.Begin), C.getObjectFileInfo()->getFDEEncoding(), S);
129
130
132
133
138
142
143
145
146
147
148
149
150
151
152
153
154
155
158 SMLoc());
159
160
162
163
165 }
166};
167
168
169
170
171class SFrameEmitterImpl {
172 MCObjectStreamer &Streamer;
174 uint32_t TotalFREs;
175 ABI SFrameABI;
176
177
178
179
180 unsigned SPReg;
181 unsigned FPReg;
182 unsigned RAReg;
183 int8_t FixedRAOffset;
184 MCSymbol *FDESubSectionStart;
185 MCSymbol *FRESubSectionStart;
187
188 bool setCFARegister(SFrameFRE &FRE, const MCCFIInstruction &I) {
189 if (I.getRegister() == SPReg) {
190 FRE.CFARegSet = true;
192 return true;
193 }
194 if (I.getRegister() == FPReg) {
195 FRE.CFARegSet = true;
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
217
218
219
220
221
222
223
224 bool isCFIEscapeSafe(SFrameFDE &FDE, const SFrameFRE &FRE,
225 const MCCFIInstruction &CFI) {
226 const MCAsmInfo *AI = Streamer.getContext().getAsmInfo();
229
230
231
232
233
234 dwarf::CFIProgram P(1,
235 1,
236 Streamer.getContext().getTargetTriple().getArch());
239
240 Streamer.getContext().reportWarning(
242 "skipping SFrame FDE; .cfi_escape with unknown effects");
243 return false;
244 }
245
246
247
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
254
255
256 auto Reg = I.getOperandAsUnsigned(P, 0);
257
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 == SPReg
267 ? "SP reg "
268 : (*Reg == FPReg ? "FP reg " : "RA reg ");
269 Streamer.getContext().reportWarning(
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
279
280 auto Reg = I.getOperandAsUnsigned(P, 0);
281 if () {
282 Streamer.getContext().reportWarning(
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 == SPReg
289 ? "SP reg "
290 : (*Reg == FPReg ? "FP reg " : "RA reg ");
291 Streamer.getContext().reportWarning(
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
303 break;
305 Streamer.getContext().reportWarning(
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
313
314
315
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
350
351 Streamer.getContext().reportWarning(
353 "skipping SFrame FDE; .cfi_escape with unknown effects");
354 return false;
355 }
356 }
357 return true;
358 }
359
360
361
362 bool handleCFI(SFrameFDE &FDE, SFrameFRE &FRE, const MCCFIInstruction &CFI) {
365 return setCFARegister(FRE, CFI);
368 if (!setCFARegister(FRE, CFI))
369 return false;
376 return true;
382 return true;
386 return setCFAOffset(FRE, CFI.getLoc(), FRE.CFAOffset + CFI.getOffset());
388 if (FDE.FREs.size() == 1) {
389
390
391
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;
400
402 FRE.FPOffset = FDE.FREs.front().FPOffset;
404 FRE.RAOffset = FDE.FREs.front().RAOffset;
405 return true;
407
408
409 assert(!FDE.SaveState.empty() &&
410 "cfi_restore_state without cfi_save_state");
411 FRE = FDE.SaveState.pop_back_val();
412 return true;
414
415
416 return isCFIEscapeSafe(FDE, FRE, CFI);
417 default:
418
419
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
444
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
471
472
473 if (atSameLocation(DF.Begin, DF.End))
474 return;
475 bool Valid = true;
476 SFrameFDE FDE(DF, Streamer.getContext().createTempSymbol());
477
478
479
480
481
482
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");
489 }
491 SFrameFRE BaseFRE(LastLabel);
492 if (.IsSimple) {
493 for (const auto &CFI :
494 Streamer.getContext().getAsmInfo()->getInitialFrameState())
495 if (!handleCFI(FDE, BaseFRE, CFI))
497 }
498 FDE.FREs.push_back(BaseFRE);
499
500 for (const auto &CFI : DF.Instructions) {
501
502
503
504
505
506
508 if (L && ->isDefined())
509 continue;
510
511 SFrameFRE FRE = FDE.FREs.back();
512 if (!handleCFI(FDE, FRE, CFI))
514
515
516 if (equalIgnoringLocation(FRE, FDE.FREs.back()))
517 continue;
518
519
520
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
545 Streamer.emitInt8(static_cast<uint8_t>(SFrameABI));
546
547 Streamer.emitInt8(0);
548
549 Streamer.emitInt8(FixedRAOffset);
550
551 Streamer.emitInt8(0);
552
553 Streamer.emitInt32(FDEs.size());
554
555 Streamer.emitInt32(TotalFREs);
556
557
558 Streamer.emitAbsoluteSymbolDiff(FRESubSectionEnd, FRESubSectionStart,
559 sizeof(int32_t));
560
561 Streamer.emitInt32(0);
562
563 Streamer.emitInt32(FDEs.size() *
564 sizeof(sframe::FuncDescEntryendianness::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}
586
589
590
591
595 .has_value())
596 return;
597
598 SFrameEmitterImpl Emitter(Streamer);
600
601
602
603 for (const auto &DFrame : FrameArray)
604 Emitter.buildSFDE(DFrame);
605
606 MCSection *Section = Context.getObjectFileInfo()->getSFrameSection();
607
608 Section->ensureMinAlignment(Align(8));
610 MCSymbol *SectionStart = Context.createTempSymbol();
611 Streamer.emitLabel(SectionStart);
615}
616
620
621 if (FDEFrag == nullptr) {
622
623
624
625
627 I.Info = 0;
629 I.setFREType(FREType::Addr1);
631 I.setFREType(FREType::Addr2);
632 else {
634 I.setFREType(FREType::Addr4);
635 }
636 I.setFDEType(FDEType::PCInc);
637
638
639 I.setPAuthKey(0);
640
642 return;
643 }
644
647 I.Info = FDEData.back();
652
653 switch (T) {
654 case FREType::Addr1:
657 break;
658 case FREType::Addr2:
661 break;
662 case FREType::Addr4:
665 break;
666 }
667}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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 ....
ArrayRef - 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.
const MCObjectFileInfo * getObjectFileInfo() 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()
std::optional< sframe::ABI > getSFrameABIArch() const
Streaming object file generation interface.
void emitSFrameCalculateFuncOffset(const MCSymbol *FunCabsel, const MCSymbol *FREBegin, MCFragment *FDEFrag, SMLoc Loc)
void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc()) override
Emit a label for Symbol into the current section.
void emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) override
Emit the absolute difference between two symbols if possible.
static void emit(MCObjectStreamer &Streamer)
Definition MCSFrame.cpp:587
static void encodeFuncOffset(MCContext &C, uint64_t Offset, SmallVectorImpl< char > &Out, MCFragment *FDEFrag)
Definition MCSFrame.cpp:617
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)
ArrayRef< MCDwarfFrameInfo > getDwarfFrameInfos() const
virtual void switchSection(MCSection *Section, uint32_t Subsec=0)
Set the current section where code is being emitted to Section.
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
size - Get the string size.
@ C
The default llvm calling convention, compatible with C.
@ 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)