LLVM: lib/ExecutionEngine/JITLink/EHFrameSupport.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

10

12#include "llvm/Config/config.h"

15

16#define DEBUG_TYPE "jitlink"

17

18namespace llvm {

19namespace jitlink {

20

22 unsigned PointerSize, Edge::Kind Pointer32,

23 Edge::Kind Pointer64, Edge::Kind Delta32,

24 Edge::Kind Delta64, Edge::Kind NegDelta32)

25 : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),

26 Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32),

27 Delta64(Delta64), NegDelta32(NegDelta32) {}

28

30 auto *EHFrame = G.findSectionByName(EHFrameSectionName);

31

32 if (!EHFrame) {

34 dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName

35 << " section in \"" << G.getName() << "\". Nothing to do.\n";

36 });

38 }

39

40

41 if (G.getPointerSize() != 4 && G.getPointerSize() != 8)

43 "EHFrameEdgeFixer only supports 32 and 64 bit targets");

44

46 dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << " in \""

47 << G.getName() << "\"...\n";

48 });

49

50 ParseContext PC(G);

51

52

53

54 for (auto &Sec : G.sections()) {

55

56

57 for (auto *Sym : Sec.symbols()) {

58 auto &CurSym = PC.AddrToSym[Sym->getAddress()];

59 if (!CurSym || (std::make_tuple(Sym->getLinkage(), Sym->getScope(),

60 !Sym->hasName(), Sym->getName()) <

61 std::make_tuple(CurSym->getLinkage(), CurSym->getScope(),

62 !CurSym->hasName(), CurSym->getName())))

63 CurSym = Sym;

64 }

65 if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),

67 return Err;

68 }

69

70

71

72 std::vector<Block *> EHFrameBlocks;

75 return LHS->getAddress() < RHS->getAddress();

76 });

77

78

79 for (auto *B : EHFrameBlocks)

80 if (auto Err = processBlock(PC, *B))

81 return Err;

82

84}

85

89 if (auto Err = R.readInteger(Length))

90 return std::move(Err);

91

92

93

94 if (Length != 0xffffffff)

96

98 if (auto Err = R.readInteger(ExtendedLength))

99 return std::move(Err);

100

101 if (ExtendedLength > std::numeric_limits<size_t>::max())

103 "In CFI record at " +

104 formatv("{0:x}", B.getAddress() + R.getOffset() - 12) +

105 ", extended length of " + formatv("{0:x}", ExtendedLength) +

106 " exceeds address-range max (" +

107 formatv("{0:x}", std::numeric_limits<size_t>::max()));

108

109 return ExtendedLength;

110}

111

112Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {

113

114 LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n");

115

116

117 if (B.isZeroFill())

119 EHFrameSectionName + " section");

120

121 if (B.getSize() == 0) {

122 LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n");

124 }

125

126

127 BlockEdgesInfo BlockEdges;

128 for (auto &E : B.edges())

129 if (E.isRelocation()) {

130

131 if (BlockEdges.Multiple.contains(E.getOffset()))

132 continue;

133

134

135

136

137 auto [It, Inserted] = BlockEdges.TargetMap.try_emplace(E.getOffset(), E);

138 if (!Inserted) {

139 BlockEdges.TargetMap.erase(It);

140 BlockEdges.Multiple.insert(E.getOffset());

141 }

142 }

143

144 BinaryStreamReader BlockReader(

145 StringRef(B.getContent().data(), B.getContent().size()),

146 PC.G.getEndianness());

147

148

150 if (!RecordRemaining)

151 return RecordRemaining.takeError();

152

153

154

155 if (BlockReader.bytesRemaining() != *RecordRemaining)

157 formatv("{0:x16}", B.getAddress()));

158

159

160 uint64_t CIEDeltaFieldOffset = BlockReader.getOffset();

161 uint32_t CIEDelta;

162 if (auto Err = BlockReader.readInteger(CIEDelta))

163 return Err;

164

165 if (CIEDelta == 0) {

166 if (auto Err = processCIE(PC, B, CIEDeltaFieldOffset, BlockEdges))

167 return Err;

168 } else {

169 if (auto Err = processFDE(PC, B, CIEDeltaFieldOffset, CIEDelta, BlockEdges))

170 return Err;

171 }

172

174}

175

176Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,

177 size_t CIEDeltaFieldOffset,

178 const BlockEdgesInfo &BlockEdges) {

179

181

182 BinaryStreamReader RecordReader(

183 StringRef(B.getContent().data(), B.getContent().size()),

184 PC.G.getEndianness());

185

186

187 RecordReader.setOffset(CIEDeltaFieldOffset + 4);

188

189 auto &CIESymbol = PC.G.addAnonymousSymbol(B, 0, B.getSize(), false, false);

190 CIEInformation CIEInfo(CIESymbol);

191

193 if (auto Err = RecordReader.readInteger(Version))

194 return Err;

195

198 " (should be 0x01) in eh-frame");

199

200 auto AugInfo = parseAugmentationString(RecordReader);

201 if (!AugInfo)

202 return AugInfo.takeError();

203

204

205 if (AugInfo->EHDataFieldPresent)

206 if (auto Err = RecordReader.skip(PC.G.getPointerSize()))

207 return Err;

208

209

210 {

211 uint64_t CodeAlignmentFactor = 0;

212 if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor))

213 return Err;

214 }

215

216

217 {

218 int64_t DataAlignmentFactor = 0;

219 if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor))

220 return Err;

221 }

222

223

224 if (auto Err = RecordReader.skip(1))

225 return Err;

226

227 if (AugInfo->AugmentationDataPresent) {

228

229 CIEInfo.AugmentationDataPresent = true;

230

231 uint64_t AugmentationDataLength = 0;

232 if (auto Err = RecordReader.readULEB128(AugmentationDataLength))

233 return Err;

234

235 uint32_t AugmentationDataStartOffset = RecordReader.getOffset();

236

237 uint8_t *NextField = &AugInfo->Fields[0];

238 while (uint8_t Field = *NextField++) {

240 case 'L':

241 CIEInfo.LSDAPresent = true;

242 if (auto PE = readPointerEncoding(RecordReader, B, "LSDA"))

243 CIEInfo.LSDAEncoding = *PE;

244 else

245 return PE.takeError();

246 break;

247 case 'P': {

248 auto PersonalityPointerEncoding =

249 readPointerEncoding(RecordReader, B, "personality");

250 if (!PersonalityPointerEncoding)

251 return PersonalityPointerEncoding.takeError();

252 if (auto Err =

253 getOrCreateEncodedPointerEdge(

254 PC, BlockEdges, *PersonalityPointerEncoding, RecordReader,

255 B, RecordReader.getOffset(), "personality")

256 .takeError())

257 return Err;

258 break;

259 }

260 case 'R':

261 if (auto PE = readPointerEncoding(RecordReader, B, "address")) {

262 CIEInfo.AddressEncoding = *PE;

265 "Invalid address encoding DW_EH_PE_omit in CIE at " +

266 formatv("{0:x}", B.getAddress().getValue()));

267 } else

268 return PE.takeError();

269 break;

270 default:

272 }

273 }

274

275 if (RecordReader.getOffset() - AugmentationDataStartOffset >

276 AugmentationDataLength)

278 "data while parsing fields");

279 }

280

281 assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&

282 "Multiple CIEs recorded at the same address?");

283 PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);

284

286}

287

288Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,

289 size_t CIEDeltaFieldOffset,

290 uint32_t CIEDelta,

291 const BlockEdgesInfo &BlockEdges) {

293

294 orc::ExecutorAddr RecordAddress = B.getAddress();

295

296 BinaryStreamReader RecordReader(

297 StringRef(B.getContent().data(), B.getContent().size()),

298 PC.G.getEndianness());

299

300

301 RecordReader.setOffset(CIEDeltaFieldOffset + 4);

302

303 auto &FDESymbol = PC.G.addAnonymousSymbol(B, 0, B.getSize(), false, false);

304

305 CIEInformation *CIEInfo = nullptr;

306

307 {

308

309 if (BlockEdges.Multiple.contains(CIEDeltaFieldOffset))

311 "CIE pointer field already has multiple edges at " +

312 formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset));

313

314 auto CIEEdgeItr = BlockEdges.TargetMap.find(CIEDeltaFieldOffset);

315

316 orc::ExecutorAddr CIEAddress =

319 if (CIEEdgeItr == BlockEdges.TargetMap.end()) {

321 dbgs() << " Adding edge at "

322 << (RecordAddress + CIEDeltaFieldOffset)

323 << " to CIE at: " << CIEAddress << "\n";

324 });

325 if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))

326 CIEInfo = *CIEInfoOrErr;

327 else

328 return CIEInfoOrErr.takeError();

329 assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");

330 B.addEdge(NegDelta32, CIEDeltaFieldOffset, *CIEInfo->CIESymbol, 0);

331 } else {

333 dbgs() << " Already has edge at "

334 << (RecordAddress + CIEDeltaFieldOffset) << " to CIE at "

335 << CIEAddress << "\n";

336 });

337 auto &EI = CIEEdgeItr->second;

338 if (EI.Addend)

340 "CIE edge at " +

341 formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) +

342 " has non-zero addend");

343 if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))

344 CIEInfo = *CIEInfoOrErr;

345 else

346 return CIEInfoOrErr.takeError();

347 }

348 }

349

350

352 dbgs() << " Processing PC-begin at "

353 << (RecordAddress + RecordReader.getOffset()) << "\n";

354 });

355 if (auto PCBegin = getOrCreateEncodedPointerEdge(

356 PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader, B,

357 RecordReader.getOffset(), "PC begin")) {

358 assert(*PCBegin && "PC-begin symbol not set");

359 if ((*PCBegin)->isDefined()) {

360

361

363 dbgs() << " Adding keep-alive edge from target at "

364 << (*PCBegin)->getBlock().getAddress() << " to FDE at "

365 << RecordAddress << "\n";

366 });

367 (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);

368 } else {

370 dbgs() << " WARNING: Not adding keep-alive edge to FDE at "

371 << RecordAddress << ", which points to "

372 << ((*PCBegin)->isExternal() ? "external" : "absolute")

373 << " symbol \"" << (*PCBegin)->getName()

374 << "\" -- FDE must be kept alive manually or it will be "

375 << "dead stripped.\n";

376 });

377 }

378 } else

379 return PCBegin.takeError();

380

381

382 if (auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader))

383 return Err;

384

385 if (CIEInfo->AugmentationDataPresent) {

386 uint64_t AugmentationDataSize;

387 if (auto Err = RecordReader.readULEB128(AugmentationDataSize))

388 return Err;

389

390 if (CIEInfo->LSDAPresent)

391 if (auto Err = getOrCreateEncodedPointerEdge(

392 PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader, B,

393 RecordReader.getOffset(), "LSDA")

394 .takeError())

395 return Err;

396 } else {

397 LLVM_DEBUG(dbgs() << " Record does not have LSDA field.\n");

398 }

399

401}

402

403ExpectedEHFrameEdgeFixer::AugmentationInfo

404EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {

405 AugmentationInfo AugInfo;

406 uint8_t NextChar;

407 uint8_t *NextField = &AugInfo.Fields[0];

408

409 if (auto Err = RecordReader.readInteger(NextChar))

410 return std::move(Err);

411

412 while (NextChar != 0) {

413 switch (NextChar) {

414 case 'z':

415 AugInfo.AugmentationDataPresent = true;

416 break;

417 case 'e':

418 if (auto Err = RecordReader.readInteger(NextChar))

419 return std::move(Err);

420 if (NextChar != 'h')

422 Twine(NextChar) +

423 " in augmentation string");

424 AugInfo.EHDataFieldPresent = true;

425 break;

426 case 'L':

427 case 'P':

428 case 'R':

429 *NextField++ = NextChar;

430 break;

431 default:

433 Twine(NextChar) +

434 " in augmentation string");

435 }

436

437 if (auto Err = RecordReader.readInteger(NextChar))

438 return std::move(Err);

439 }

440

441 return std::move(AugInfo);

442}

443

444Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R,

446 const char *FieldName) {

447 using namespace dwarf;

448

449 uint8_t PointerEncoding;

450 if (auto Err = R.readInteger(PointerEncoding))

451 return std::move(Err);

452

453 bool Supported = true;

454 switch (PointerEncoding & 0xf) {

459 Supported = false;

460 break;

461 }

462 if (Supported) {

463 switch (PointerEncoding & 0x70) {

468 Supported = false;

469 break;

470 }

471 }

472

473 if (Supported)

474 return PointerEncoding;

475

477 formatv("{0:x2}", PointerEncoding) + " for " +

478 FieldName + "in CFI record at " +

480}

481

482Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,

483 BinaryStreamReader &RecordReader) {

484 using namespace dwarf;

485

486

487 if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)

488 PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;

489

490 switch (PointerEncoding & 0xf) {

493 if (auto Err = RecordReader.skip(4))

494 return Err;

495 break;

498 if (auto Err = RecordReader.skip(8))

499 return Err;

500 break;

501 default:

503 }

505}

506

507Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(

508 ParseContext &PC, const BlockEdgesInfo &BlockEdges, uint8_t PointerEncoding,

509 BinaryStreamReader &RecordReader, Block &BlockToFix,

510 size_t PointerFieldOffset, const char *FieldName) {

511 using namespace dwarf;

512

513 if (PointerEncoding == DW_EH_PE_omit)

514 return nullptr;

515

516

517

518 {

519 auto EdgeI = BlockEdges.TargetMap.find(PointerFieldOffset);

520 if (EdgeI != BlockEdges.TargetMap.end()) {

522 dbgs() << " Existing edge at "

523 << (BlockToFix.getAddress() + PointerFieldOffset) << " to "

524 << FieldName << " at " << EdgeI->second.Target->getAddress();

525 if (EdgeI->second.Target->hasName())

526 dbgs() << " (" << EdgeI->second.Target->getName() << ")";

527 dbgs() << "\n";

528 });

529 if (auto Err = skipEncodedPointer(PointerEncoding, RecordReader))

530 return std::move(Err);

531 return EdgeI->second.Target;

532 }

533

534 if (BlockEdges.Multiple.contains(PointerFieldOffset))

536 formatv("{0:x16}", PointerFieldOffset));

537 }

538

539

540 if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)

541 PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;

542

543

544 uint64_t FieldValue;

545 bool Is64Bit = false;

546 switch (PointerEncoding & 0xf) {

548 uint32_t Val;

549 if (auto Err = RecordReader.readInteger(Val))

550 return std::move(Err);

551 FieldValue = Val;

552 break;

553 }

555 uint32_t Val;

556 if (auto Err = RecordReader.readInteger(Val))

557 return std::move(Err);

558 FieldValue = Val;

559 break;

560 }

563 Is64Bit = true;

564 if (auto Err = RecordReader.readInteger(FieldValue))

565 return std::move(Err);

566 break;

567 default:

569 }

570

571

572 orc::ExecutorAddr Target;

573 Edge::Kind PtrEdgeKind = Edge::Invalid;

574 if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) {

575 Target = BlockToFix.getAddress() + PointerFieldOffset;

576 PtrEdgeKind = Is64Bit ? Delta64 : Delta32;

577 } else

578 PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32;

579 Target += FieldValue;

580

581

582 auto TargetSym = getOrCreateSymbol(PC, Target);

583 if (!TargetSym)

584 return TargetSym.takeError();

585 BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0);

586

588 dbgs() << " Adding edge at "

589 << (BlockToFix.getAddress() + PointerFieldOffset) << " to "

590 << FieldName << " at " << TargetSym->getAddress();

591 if (TargetSym->hasName())

592 dbgs() << " (" << TargetSym->getName() << ")";

593 dbgs() << "\n";

594 });

595

596 return &*TargetSym;

597}

598

599Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,

600 orc::ExecutorAddr Addr) {

601

602 auto CanonicalSymI = PC.AddrToSym.find(Addr);

603 if (CanonicalSymI != PC.AddrToSym.end())

604 return *CanonicalSymI->second;

605

606

607 auto *B = PC.AddrToBlock.getBlockCovering(Addr);

608 if (B)

610 formatv("{0:x16}", Addr));

611

612 auto &S =

613 PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);

614 PC.AddrToSym[S.getAddress()] = &S;

615 return S;

616}

617

618char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};

619

621 : EHFrameSectionName(EHFrameSectionName) {}

622

624 auto *EHFrame = G.findSectionByName(EHFrameSectionName);

625

626 if (!EHFrame)

628

630 dbgs() << "EHFrameNullTerminator adding null terminator to "

631 << EHFrameSectionName << "\n";

632 });

633

634 auto &NullTerminatorBlock =

635 G.createContentBlock(*EHFrame, NullTerminatorBlockContent,

637 G.addAnonymousSymbol(NullTerminatorBlock, 0, 4, false, true);

639}

640

642 if (B.edges_empty())

643 return EHFrameCFIBlockInspector(nullptr);

644 if (B.edges_size() == 1)

645 return EHFrameCFIBlockInspector(&*B.edges().begin());

647 assert(Es.size() >= 2 && Es.size() <= 3 && "Unexpected number of edges");

649 return LHS->getOffset() < RHS->getOffset();

650 });

651 return EHFrameCFIBlockInspector(*Es[0], *Es[1],

652 Es.size() == 3 ? Es[2] : nullptr);

653 return EHFrameCFIBlockInspector(nullptr);

654}

655

656EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge *PersonalityEdge)

657 : PersonalityEdge(PersonalityEdge) {}

658

659EHFrameCFIBlockInspector::EHFrameCFIBlockInspector(Edge &CIEEdge,

660 Edge &PCBeginEdge,

661 Edge *LSDAEdge)

662 : CIEEdge(&CIEEdge), PCBeginEdge(&PCBeginEdge), LSDAEdge(LSDAEdge) {}

663

665 const char *EHFrameSectionName = nullptr;

666 switch (G.getTargetTriple().getObjectFormat()) {

668 EHFrameSectionName = "__TEXT,__eh_frame";

669 break;

671 EHFrameSectionName = ".eh_frame";

672 break;

673 default:

674 return nullptr;

675 }

676

677 if (auto *S = G.findSectionByName(EHFrameSectionName))

678 if (!S->empty())

679 return S;

680

681 return nullptr;

682}

683

684}

685}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

This file contains constants used for implementing Dwarf debug support.

OptimizedStructLayoutField Field

static bool InBlock(const Value *V, const BasicBlock *BB)

Provides read only access to a subclass of BinaryStream.

Lightweight error class with error context and mandatory checking.

static ErrorSuccess success()

Create a success value.

Tagged union holding either a T or a Error.

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

StringRef - Represent a constant reference to a string, i.e.

static bool includeNonNull(const Block &B)

A block predicate that always includes blocks with non-null addresses.

An Addressable with content and edges.

static LLVM_ABI EHFrameCFIBlockInspector FromEdgeScan(Block &B)

Identify CFI record type and edges based on number and order of edges in the given block only.

Definition EHFrameSupport.cpp:641

Error operator()(LinkGraph &G)

Definition EHFrameSupport.cpp:29

EHFrameEdgeFixer(StringRef EHFrameSectionName, unsigned PointerSize, Edge::Kind Pointer32, Edge::Kind Pointer64, Edge::Kind Delta32, Edge::Kind Delta64, Edge::Kind NegDelta32)

Create an eh-frame edge fixer.

Definition EHFrameSupport.cpp:21

Represents fixups and constraints in the LinkGraph.

Represents an object file section.

Represents an address in the executor process.

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

LLVM_ABI Section * getEHFrameSection(LinkGraph &G)

Returns a pointer to the DWARF eh-frame section if the graph contains a non-empty one,...

Definition EHFrameSupport.cpp:664

static Expected< size_t > readCFIRecordLength(const Block &B, BinaryStreamReader &R)

Definition EHFrameSupport.cpp:86

uint64_t ExecutorAddrDiff

This is an optimization pass for GlobalISel generic memory operations.

void append_range(Container &C, Range &&R)

Wrapper function to append range R to container C.

auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)

FunctionAddr VTableAddr uintptr_t uintptr_t Version

void sort(IteratorTy Start, IteratorTy End)

LLVM_ABI raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

Error make_error(ArgTs &&... Args)

Make a Error instance representing failure using the given error info type.

iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)