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 (Reg) {

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 (DF.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 && 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)