LLVM: lib/ExecutionEngine/JITLink/CompactUnwindSupport.h Source File (original) (raw)

50

53 "Truncated CU record?");

56 }

57

60 "Truncated CU record?");

63 }

64

67 static_cast<uint32_t>(Delta) & CRTPImpl::DWARFSectionOffsetMask;

68 if (Encoded != Delta)

69 return std::nullopt;

70 return Encoded;

71 }

72};

76public:

80 : CompactUnwindSectionName(CompactUnwindSectionName),

81 UnwindInfoSectionName(UnwindInfoSectionName),

82 EHFrameSectionName(EHFrameSectionName) {}

83

84

85

86

87

88

89

90

92 Section *CUSec = G.findSectionByName(CompactUnwindSectionName);

93 if (!CUSec || CUSec->empty()) {

95 dbgs() << "Compact unwind: No compact unwind info for " << G.getName()

96 << "\n";

97 });

99 }

100

102 dbgs() << "Compact unwind: preparing " << G.getName() << " for prune\n";

103 });

104

105 Section *EHFrameSec = G.findSectionByName(EHFrameSectionName);

106

108 return Err;

109

111 dbgs() << " Preparing " << CUSec->blocks_size() << " blocks in "

112 << CompactUnwindSectionName << "\n";

113 });

114

115 for (auto *B : CUSec->blocks()) {

116

117

118 Edge *PCBeginEdge = nullptr;

119 for (auto &E : B->edges_at(CURecTraits::FnFieldOffset)) {

120 PCBeginEdge = &E;

121 break;

122 }

123

124 if (!PCBeginEdge)

126 "In " + G.getName() + ", compact unwind record at " +

127 formatv("{0:x}", B->getAddress()) + " has no pc-begin edge");

128

131 "In " + G.getName() + ", compact unwind record at " +

132 formatv("{0:x}", B->getAddress()) + " points at external symbol " +

134

135 auto &Fn = PCBeginEdge->getTarget();

136

137 if (!Fn.isDefined()) {

139 dbgs() << "In " << CompactUnwindSectionName << " for " << G.getName()

140 << " encountered unexpected pc-edge to undefined symbol "

141 << Fn.getName() << "\n";

142 });

143 continue;

144 }

145

146 uint32_t Encoding = CURecTraits::readEncoding(B->getContent());

147 bool NeedsDWARF = CURecTraits::encodingSpecifiesDWARF(Encoding);

148

150 dbgs() << " Found record for function ";

151 if (Fn.hasName())

152 dbgs() << Fn.getName();

153 else

154 dbgs() << "<anon @ " << Fn.getAddress() << '>';

155 dbgs() << ": encoding = " << formatv("{0:x}", Encoding);

156 if (NeedsDWARF)

157 dbgs() << " (needs DWARF)";

158 dbgs() << "\n";

159 });

160

161 auto &CURecSym =

162 G.addAnonymousSymbol(*B, 0, CURecTraits::Size, false, false);

163

164 bool KeepAliveAlreadyPresent = false;

165 if (EHFrameSec) {

166 Edge *KeepAliveEdge = nullptr;

167 for (auto &E : Fn.getBlock().edges_at(0)) {

168 if (E.getKind() == Edge::KeepAlive && E.getTarget().isDefined() &&

169 &E.getTarget().getSection() == EHFrameSec) {

170 KeepAliveEdge = &E;

171 break;

172 }

173 }

174

175 if (KeepAliveEdge) {

176

177

178

179 auto &FDE = KeepAliveEdge->getTarget();

180 KeepAliveEdge->setTarget(CURecSym);

181 KeepAliveAlreadyPresent = true;

182 if (NeedsDWARF) {

184 dbgs() << " Adding keep-alive edge to FDE at "

185 << FDE.getAddress() << "\n";

186 });

187 B->addEdge(Edge::KeepAlive, 0, FDE, 0);

188 }

189 } else {

190 if (NeedsDWARF)

192 "In " + G.getName() + ", compact unwind recard ot " +

193 formatv("{0:x}", B->getAddress()) +

194 " needs DWARF, but no FDE was found");

195 }

196 } else {

197 if (NeedsDWARF)

199 "In " + G.getName() + ", compact unwind recard ot " +

200 formatv("{0:x}", B->getAddress()) + " needs DWARF, but no " +

201 EHFrameSectionName + " section exists");

202 }

203

204 if (!KeepAliveAlreadyPresent) {

205

206

207 Fn.getBlock().addEdge(Edge::KeepAlive, 0, CURecSym, 0);

208 }

209 }

210

212 }

213

214

216

217 Section *CUSec = G.findSectionByName(CompactUnwindSectionName);

218 if (!CUSec)

220

221

222

224

225

226

227 if (auto Err = getOrCreateCompactUnwindBase(G))

228 return Err;

229

230

231

232 if (G.findSectionByName(UnwindInfoSectionName))

234 UnwindInfoSectionName +

235 " already exists");

236

237

238

239 if (auto Err = processCompactUnwind(G, *CUSec))

240 return Err;

241

242

243 size_t UnwindInfoSectionSize =

244 UnwindInfoSectionHeaderSize +

245 Personalities.size() * PersonalityEntrySize +

246 (NumSecondLevelPages + 1) * IndexEntrySize + NumLSDAs * LSDAEntrySize +

247 NumSecondLevelPages * SecondLevelPageHeaderSize +

248 Records.size() * SecondLevelPageEntrySize;

249

251 dbgs() << "In " << G.getName() << ", reserving "

252 << formatv("{0:x}", UnwindInfoSectionSize) << " bytes for "

253 << UnwindInfoSectionName << "\n";

254 });

255

256

259

260 auto UnwindInfoSectionContent = G.allocateBuffer(UnwindInfoSectionSize);

261 memset(UnwindInfoSectionContent.data(), 0, UnwindInfoSectionContent.size());

262 auto &B = G.createMutableContentBlock(

263 UnwindInfoSec, UnwindInfoSectionContent, orc::ExecutorAddr(), 8, 0);

264

265

266

267 for (auto &R : Records)

268 B.addEdge(Edge::KeepAlive, 0, *R.Fn, 0);

269

271 }

272

274 Section *CUSec = G.findSectionByName(CompactUnwindSectionName);

275 if (!CUSec || CUSec->empty())

277

278 Section *UnwindInfoSec = G.findSectionByName(UnwindInfoSectionName);

279 if (!UnwindInfoSec)

281 UnwindInfoSectionName +

282 " missing after allocation");

283

286 "In " + G.getName() + ", " + UnwindInfoSectionName +

287 " contains more than one block post-allocation");

288

290 { dbgs() << "Writing unwind info for " << G.getName() << "...\n"; });

291

292 mergeRecords();

293

294 auto &UnwindInfoBlock = **UnwindInfoSec->blocks().begin();

295 auto Content = UnwindInfoBlock.getMutableContent(G);

297 {reinterpret_cast<uint8_t *>(Content.data()), Content.size()},

298 CURecTraits::Endianness);

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318 if (auto Err = writeHeader(G, Writer))

319 return Err;

320

321

322

323 if (auto Err = writePersonalities(G, Writer))

324 return Err;

325

326

327 size_t SectionOffsetToLSDAs =

328 Writer.getOffset() + (NumSecondLevelPages + 1) * IndexEntrySize;

329

330

331 size_t SectionOffsetToSecondLevelPages =

332 SectionOffsetToLSDAs + NumLSDAs * LSDAEntrySize;

333

334 if (auto Err = writeIndexes(G, Writer, SectionOffsetToLSDAs,

335 SectionOffsetToSecondLevelPages))

336 return Err;

337

338 if (auto Err = writeLSDAs(G, Writer))

339 return Err;

340

341 if (auto Err = writeSecondLevelPages(G, Writer))

342 return Err;

343

345 dbgs() << " Wrote " << formatv("{0:x}", Writer.getOffset())

346 << " bytes of unwind info.\n";

347 });

348

350 }

351

352private:

353

354 static constexpr size_t MaxPersonalities = 4;

355 static constexpr size_t PersonalityShift = 28;

356

357 static constexpr size_t UnwindInfoSectionHeaderSize = 4 * 7;

358 static constexpr size_t PersonalityEntrySize = 4;

359 static constexpr size_t IndexEntrySize = 3 * 4;

360 static constexpr size_t LSDAEntrySize = 2 * 4;

361 static constexpr size_t SecondLevelPageSize = 4096;

362 static constexpr size_t SecondLevelPageHeaderSize = 8;

363 static constexpr size_t SecondLevelPageEntrySize = 8;

364 static constexpr size_t NumRecordsPerSecondLevelPage =

365 (SecondLevelPageSize - SecondLevelPageHeaderSize) /

366 SecondLevelPageEntrySize;

367

368 struct CompactUnwindRecord {

369 Symbol *Fn = nullptr;

372 Symbol *LSDA = nullptr;

373 Symbol *FDE = nullptr;

374 };

375

376 Error processCompactUnwind(LinkGraph &G, Section &CUSec) {

377

378

379 assert(NumLSDAs == 0 && "NumLSDAs should be zero");

380 assert(Records.empty() && "CompactUnwindRecords vector should be empty.");

381 assert(Personalities.empty() && "Personalities vector should be empty.");

382

384 NonUniquedRecords.reserve(CUSec.blocks_size());

385

386

387 for (auto *B : CUSec.blocks()) {

388 CompactUnwindRecord R;

389 R.Encoding = CURecTraits::readEncoding(B->getContent());

390 for (auto &E : B->edges()) {

391 switch (E.getOffset()) {

392 case CURecTraits::FnFieldOffset:

393

394

395 if (E.getKind() == Edge::KeepAlive)

396 R.FDE = &E.getTarget();

397 else

398 R.Fn = &E.getTarget();

399 break;

400 case CURecTraits::PersonalityFieldOffset: {

401

402

403 size_t PersonalityIdx = 0;

404 for (; PersonalityIdx != Personalities.size(); ++PersonalityIdx)

405 if (Personalities[PersonalityIdx] == &E.getTarget())

406 break;

407 if (PersonalityIdx == MaxPersonalities)

409 "In " + G.getName() +

410 ", __compact_unwind contains too many personalities (max " +

411 formatv("{}", MaxPersonalities) + ")");

412 if (PersonalityIdx == Personalities.size())

413 Personalities.push_back(&E.getTarget());

414

415 R.Encoding |= (PersonalityIdx + 1) << PersonalityShift;

416 break;

417 }

418 case CURecTraits::LSDAFieldOffset:

419 ++NumLSDAs;

420 R.LSDA = &E.getTarget();

421 break;

422 default:

424 ", compact unwind record at " +

425 formatv("{0:x}", B->getAddress()) +

426 " has unrecognized edge at offset " +

427 formatv("{0:x}", E.getOffset()));

428 }

429 }

430 Records.push_back(R);

431 }

432

433

434 llvm::sort(Records, [](const CompactUnwindRecord &LHS,

435 const CompactUnwindRecord &RHS) {

436 return LHS.Fn->getAddress() < RHS.Fn->getAddress();

437 });

438

439

440 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /

441 NumRecordsPerSecondLevelPage;

442

443

444 typename CURecTraits::GOTManager GOT(G);

445 for (auto &Personality : Personalities)

446 Personality = &GOT.getEntryForTarget(G, *Personality);

447

449 dbgs() << " In " << G.getName() << ", " << CompactUnwindSectionName

450 << ": raw records = " << Records.size()

451 << ", personalities = " << Personalities.size()

452 << ", lsdas = " << NumLSDAs << "\n";

453 });

454

456 }

457

458 void mergeRecords() {

459 SmallVector NonUniqued = std::move(Records);

460 Records.reserve(NonUniqued.size());

461

462 Records.push_back(NonUniqued.front());

463 for (size_t I = 1; I != NonUniqued.size(); ++I) {

464 auto &Next = NonUniqued[I];

465 auto &Last = Records.back();

466

467 bool NextNeedsDWARF = CURecTraits::encodingSpecifiesDWARF(Next.Encoding);

468 bool CannotBeMerged = CURecTraits::encodingCannotBeMerged(Next.Encoding);

469 if (NextNeedsDWARF || (Next.Encoding != Last.Encoding) ||

470 CannotBeMerged || Next.LSDA || Last.LSDA)

471 Records.push_back(Next);

472 }

473

474

475 NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) /

476 NumRecordsPerSecondLevelPage;

477 }

478

479 Error writeHeader(LinkGraph &G, BinaryStreamWriter &W) {

480 if (isUInt<32>(NumSecondLevelPages + 1))

482 UnwindInfoSectionName +

483 "second-level pages required");

484

485

486 size_t IndexArrayOffset = UnwindInfoSectionHeaderSize +

487 Personalities.size() * PersonalityEntrySize;

488

489 cantFail(W.writeInteger<uint32_t>(1));

490 cantFail(W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize));

491 cantFail(W.writeInteger<uint32_t>(0));

492 cantFail(W.writeInteger<uint32_t>(UnwindInfoSectionHeaderSize));

493 cantFail(W.writeInteger<uint32_t>(Personalities.size()));

494 cantFail(W.writeInteger<uint32_t>(IndexArrayOffset));

495 cantFail(W.writeInteger<uint32_t>(NumSecondLevelPages + 1));

496

498 }

499

500 Error writePersonalities(LinkGraph &G, BinaryStreamWriter &W) {

501

502 for (auto *PSym : Personalities) {

503 auto Delta = PSym->getAddress() - CompactUnwindBase->getAddress();

505 return makePersonalityRangeError(G, *PSym);

506 cantFail(W.writeInteger<uint32_t>(Delta));

507 }

509 }

510

511 Error writeIndexes(LinkGraph &G, BinaryStreamWriter &W,

512 size_t SectionOffsetToLSDAs,

513 size_t SectionOffsetToSecondLevelPages) {

514

515

516

517

518 size_t RecordIdx = 0;

519 size_t NumPreviousLSDAs = 0;

520 for (auto &R : Records) {

521

522 if (RecordIdx % NumRecordsPerSecondLevelPage == 0) {

523 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();

524 auto SecondLevelPageOffset =

525 SectionOffsetToSecondLevelPages +

526 SecondLevelPageSize * (RecordIdx / NumRecordsPerSecondLevelPage);

527 auto LSDAOffset =

528 SectionOffsetToLSDAs + NumPreviousLSDAs * LSDAEntrySize;

529

530 cantFail(W.writeInteger<uint32_t>(FnDelta));

531 cantFail(W.writeInteger<uint32_t>(SecondLevelPageOffset));

532 cantFail(W.writeInteger<uint32_t>(LSDAOffset));

533 }

534 if (R.LSDA)

535 ++NumPreviousLSDAs;

536 ++RecordIdx;

537 }

538

539

540 {

541 auto FnEndDelta =

542 Records.back().Fn->getRange().End - CompactUnwindBase->getAddress();

543

546 "In " + G.getName() + " " + UnwindInfoSectionName +

547 ", delta to end of functions " +

548 formatv("{0:x}", Records.back().Fn->getRange().End) +

549 " exceeds 32 bits");

550

551 cantFail(W.writeInteger<uint32_t>(FnEndDelta));

552 cantFail(W.writeInteger<uint32_t>(0));

553 cantFail(W.writeInteger<uint32_t>(SectionOffsetToSecondLevelPages));

554 }

555

557 }

558

559 Error writeLSDAs(LinkGraph &G, BinaryStreamWriter &W) {

560

561 for (auto &R : Records) {

562 if (R.LSDA) {

563 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();

564 auto LSDADelta = R.LSDA->getAddress() - CompactUnwindBase->getAddress();

565

568 "In " + G.getName() + " " + UnwindInfoSectionName +

569 ", delta to lsda at " + formatv("{0:x}", R.LSDA->getAddress()) +

570 " exceeds 32 bits");

571

572 cantFail(W.writeInteger<uint32_t>(FnDelta));

573 cantFail(W.writeInteger<uint32_t>(LSDADelta));

574 }

575 }

576

578 }

579

580 Error writeSecondLevelPages(LinkGraph &G, BinaryStreamWriter &W) {

581 size_t RecordIdx = 0;

582

583 for (auto &R : Records) {

584

585

586

587

588

589 if (RecordIdx % NumRecordsPerSecondLevelPage == 0) {

590 constexpr uint32_t SecondLevelPageHeaderKind = 2;

591 constexpr uint16_t SecondLevelPageHeaderSize = 8;

592 uint16_t SecondLevelPageNumEntries =

593 std::min(Records.size() - RecordIdx, NumRecordsPerSecondLevelPage);

594

595 cantFail(W.writeInteger<uint32_t>(SecondLevelPageHeaderKind));

596 cantFail(W.writeInteger<uint16_t>(SecondLevelPageHeaderSize));

597 cantFail(W.writeInteger<uint16_t>(SecondLevelPageNumEntries));

598 }

599

600

601 auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress();

602

605 "In " + G.getName() + " " + UnwindInfoSectionName +

606 ", delta to function at " + formatv("{0:x}", R.Fn->getAddress()) +

607 " exceeds 32 bits");

608

609 auto Encoding = R.Encoding;

610

611 if (LLVM_UNLIKELY(CURecTraits::encodingSpecifiesDWARF(R.Encoding))) {

612 if (!EHFrameBase)

613 EHFrameBase = SectionRange(R.FDE->getSection()).getStart();

614 auto FDEDelta = R.FDE->getAddress() - EHFrameBase;

615

616 if (auto EncodedFDEDelta = CURecTraits::encodeDWARFOffset(FDEDelta))

617 Encoding |= *EncodedFDEDelta;

618 else

620 "In " + G.getName() + " " + UnwindInfoSectionName +

621 ", cannot encode delta " + formatv("{0:x}", FDEDelta) +

622 " to FDE at " + formatv("{0:x}", R.FDE->getAddress()));

623 }

624

625 cantFail(W.writeInteger<uint32_t>(FnDelta));

626 cantFail(W.writeInteger<uint32_t>(Encoding));

627

628 ++RecordIdx;

629 }

630

632 }

633

634 Error getOrCreateCompactUnwindBase(LinkGraph &G) {

635 auto Name = G.intern("__jitlink$libunwind_dso_base");

636 CompactUnwindBase = G.findAbsoluteSymbolByName(Name);

637 if (!CompactUnwindBase) {

639 CompactUnwindBase = &*LocalCUBase;

640 auto &B = LocalCUBase->getBlock();

643 } else

644 return LocalCUBase.takeError();

645 }

646 CompactUnwindBase->setLive(true);

648 }

649

650 Error makePersonalityRangeError(LinkGraph &G, Symbol &PSym) {

651 std::string ErrMsg;

652 {

653 raw_string_ostream ErrStream(ErrMsg);

654 ErrStream << "In " << G.getName() << " " << UnwindInfoSectionName

655 << ", personality ";

656 if (PSym.hasName())

657 ErrStream << PSym.getName() << " ";

658 ErrStream << "at " << PSym.getAddress()

659 << " is out of 32-bit delta range of compact-unwind base at "

660 << CompactUnwindBase->getAddress();

661 }

663 }

664

665 StringRef CompactUnwindSectionName;

666 StringRef UnwindInfoSectionName;

667 StringRef EHFrameSectionName;

668 Symbol *CompactUnwindBase = nullptr;

669 orc::ExecutorAddr EHFrameBase;

670

671 size_t NumLSDAs = 0;

672 size_t NumSecondLevelPages = 0;

674 SmallVector Records;

675};