11233c15bSLang Hames //===-------- JITLink_EHFrameSupport.cpp - JITLink eh-frame utils ---------===//
21233c15bSLang Hames //
3c874dd53SChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c874dd53SChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information.
5c874dd53SChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61233c15bSLang Hames //
71233c15bSLang Hames //===----------------------------------------------------------------------===//
81233c15bSLang Hames
91233c15bSLang Hames #include "EHFrameSupportImpl.h"
101233c15bSLang Hames
111233c15bSLang Hames #include "llvm/BinaryFormat/Dwarf.h"
12ae032e27SDavid Tenty #include "llvm/Config/config.h"
13d46409fcSShubham Sandeep Rastogi #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
141d0676b5SLang Hames #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
151233c15bSLang Hames #include "llvm/Support/DynamicLibrary.h"
161233c15bSLang Hames
171233c15bSLang Hames #define DEBUG_TYPE "jitlink"
181233c15bSLang Hames
191233c15bSLang Hames namespace llvm {
201233c15bSLang Hames namespace jitlink {
211233c15bSLang Hames
EHFrameEdgeFixer(StringRef EHFrameSectionName,unsigned PointerSize,Edge::Kind Pointer32,Edge::Kind Pointer64,Edge::Kind Delta32,Edge::Kind Delta64,Edge::Kind NegDelta32)2276aee8a3SLang Hames EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName,
2343acef48SLang Hames unsigned PointerSize, Edge::Kind Pointer32,
2443acef48SLang Hames Edge::Kind Pointer64, Edge::Kind Delta32,
2543acef48SLang Hames Edge::Kind Delta64, Edge::Kind NegDelta32)
26cda4d3d3SLang Hames : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
2743acef48SLang Hames Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32),
2843acef48SLang Hames Delta64(Delta64), NegDelta32(NegDelta32) {}
2976aee8a3SLang Hames
operator ()(LinkGraph & G)3076aee8a3SLang Hames Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
3176aee8a3SLang Hames auto *EHFrame = G.findSectionByName(EHFrameSectionName);
3276aee8a3SLang Hames
3376aee8a3SLang Hames if (!EHFrame) {
3476aee8a3SLang Hames LLVM_DEBUG({
3576aee8a3SLang Hames dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName
36*3a7986f5SLang Hames << " section in \"" << G.getName() << "\". Nothing to do.\n";
3776aee8a3SLang Hames });
3876aee8a3SLang Hames return Error::success();
3976aee8a3SLang Hames }
4076aee8a3SLang Hames
41cda4d3d3SLang Hames // Check that we support the graph's pointer size.
42cda4d3d3SLang Hames if (G.getPointerSize() != 4 && G.getPointerSize() != 8)
43cda4d3d3SLang Hames return make_error<JITLinkError>(
44cda4d3d3SLang Hames "EHFrameEdgeFixer only supports 32 and 64 bit targets");
45cda4d3d3SLang Hames
4676aee8a3SLang Hames LLVM_DEBUG({
47*3a7986f5SLang Hames dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << " in \""
48*3a7986f5SLang Hames << G.getName() << "\"...\n";
4976aee8a3SLang Hames });
5076aee8a3SLang Hames
5176aee8a3SLang Hames ParseContext PC(G);
5276aee8a3SLang Hames
5376aee8a3SLang Hames // Build a map of all blocks and symbols in the text sections. We will use
5476aee8a3SLang Hames // these for finding / building edge targets when processing FDEs.
5576aee8a3SLang Hames for (auto &Sec : G.sections()) {
5601bc5b70SLang Hames // Just record the most-canonical symbol (for eh-frame purposes) at each
5701bc5b70SLang Hames // address.
5801bc5b70SLang Hames for (auto *Sym : Sec.symbols()) {
5901bc5b70SLang Hames auto &CurSym = PC.AddrToSym[Sym->getAddress()];
6001bc5b70SLang Hames if (!CurSym || (std::make_tuple(Sym->getLinkage(), Sym->getScope(),
6101bc5b70SLang Hames !Sym->hasName(), Sym->getName()) <
6201bc5b70SLang Hames std::make_tuple(CurSym->getLinkage(), CurSym->getScope(),
6301bc5b70SLang Hames !CurSym->hasName(), CurSym->getName())))
6401bc5b70SLang Hames CurSym = Sym;
6501bc5b70SLang Hames }
6676aee8a3SLang Hames if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
6776aee8a3SLang Hames BlockAddressMap::includeNonNull))
6876aee8a3SLang Hames return Err;
6976aee8a3SLang Hames }
7076aee8a3SLang Hames
7176aee8a3SLang Hames // Sort eh-frame blocks into address order to ensure we visit CIEs before
7276aee8a3SLang Hames // their child FDEs.
7376aee8a3SLang Hames std::vector<Block *> EHFrameBlocks;
7476aee8a3SLang Hames for (auto *B : EHFrame->blocks())
7576aee8a3SLang Hames EHFrameBlocks.push_back(B);
7676aee8a3SLang Hames llvm::sort(EHFrameBlocks, [](const Block *LHS, const Block *RHS) {
7776aee8a3SLang Hames return LHS->getAddress() < RHS->getAddress();
7876aee8a3SLang Hames });
7976aee8a3SLang Hames
8076aee8a3SLang Hames // Loop over the blocks in address order.
8176aee8a3SLang Hames for (auto *B : EHFrameBlocks)
8276aee8a3SLang Hames if (auto Err = processBlock(PC, *B))
8376aee8a3SLang Hames return Err;
8476aee8a3SLang Hames
8576aee8a3SLang Hames return Error::success();
8676aee8a3SLang Hames }
8776aee8a3SLang Hames
processBlock(ParseContext & PC,Block & B)8876aee8a3SLang Hames Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
8976aee8a3SLang Hames
9043acef48SLang Hames LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n");
9176aee8a3SLang Hames
9276aee8a3SLang Hames // eh-frame should not contain zero-fill blocks.
9376aee8a3SLang Hames if (B.isZeroFill())
9476aee8a3SLang Hames return make_error<JITLinkError>("Unexpected zero-fill block in " +
9576aee8a3SLang Hames EHFrameSectionName + " section");
9676aee8a3SLang Hames
9776aee8a3SLang Hames if (B.getSize() == 0) {
9876aee8a3SLang Hames LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n");
9976aee8a3SLang Hames return Error::success();
10076aee8a3SLang Hames }
10176aee8a3SLang Hames
10276aee8a3SLang Hames // Find the offsets of any existing edges from this block.
10376aee8a3SLang Hames BlockEdgeMap BlockEdges;
10476aee8a3SLang Hames for (auto &E : B.edges())
10576aee8a3SLang Hames if (E.isRelocation()) {
10676aee8a3SLang Hames if (BlockEdges.count(E.getOffset()))
10776aee8a3SLang Hames return make_error<JITLinkError>(
10876aee8a3SLang Hames "Multiple relocations at offset " +
10976aee8a3SLang Hames formatv("{0:x16}", E.getOffset()) + " in " + EHFrameSectionName +
11076aee8a3SLang Hames " block at address " + formatv("{0:x16}", B.getAddress()));
11176aee8a3SLang Hames
11276aee8a3SLang Hames BlockEdges[E.getOffset()] = EdgeTarget(E);
11376aee8a3SLang Hames }
11476aee8a3SLang Hames
11576aee8a3SLang Hames CIEInfosMap CIEInfos;
1160269a407SLang Hames BinaryStreamReader BlockReader(
1170269a407SLang Hames StringRef(B.getContent().data(), B.getContent().size()),
1180269a407SLang Hames PC.G.getEndianness());
11976aee8a3SLang Hames while (!BlockReader.empty()) {
12076aee8a3SLang Hames size_t RecordStartOffset = BlockReader.getOffset();
12176aee8a3SLang Hames
12276aee8a3SLang Hames LLVM_DEBUG({
12376aee8a3SLang Hames dbgs() << " Processing CFI record at "
12443acef48SLang Hames << (B.getAddress() + RecordStartOffset) << "\n";
12576aee8a3SLang Hames });
12676aee8a3SLang Hames
12776aee8a3SLang Hames // Get the record length.
12876aee8a3SLang Hames size_t RecordRemaining;
12976aee8a3SLang Hames {
13076aee8a3SLang Hames uint32_t Length;
13176aee8a3SLang Hames if (auto Err = BlockReader.readInteger(Length))
13276aee8a3SLang Hames return Err;
13376aee8a3SLang Hames // If Length < 0xffffffff then use the regular length field, otherwise
13476aee8a3SLang Hames // read the extended length field.
13576aee8a3SLang Hames if (Length != 0xffffffff)
13676aee8a3SLang Hames RecordRemaining = Length;
13776aee8a3SLang Hames else {
13876aee8a3SLang Hames uint64_t ExtendedLength;
13976aee8a3SLang Hames if (auto Err = BlockReader.readInteger(ExtendedLength))
14076aee8a3SLang Hames return Err;
14176aee8a3SLang Hames RecordRemaining = ExtendedLength;
14276aee8a3SLang Hames }
14376aee8a3SLang Hames }
14476aee8a3SLang Hames
14576aee8a3SLang Hames if (BlockReader.bytesRemaining() < RecordRemaining)
14676aee8a3SLang Hames return make_error<JITLinkError>(
14776aee8a3SLang Hames "Incomplete CFI record at " +
14876aee8a3SLang Hames formatv("{0:x16}", B.getAddress() + RecordStartOffset));
14976aee8a3SLang Hames
15076aee8a3SLang Hames // Read the CIE delta for this record.
15176aee8a3SLang Hames uint64_t CIEDeltaFieldOffset = BlockReader.getOffset() - RecordStartOffset;
15276aee8a3SLang Hames uint32_t CIEDelta;
15376aee8a3SLang Hames if (auto Err = BlockReader.readInteger(CIEDelta))
15476aee8a3SLang Hames return Err;
15576aee8a3SLang Hames
15676aee8a3SLang Hames if (CIEDelta == 0) {
15776aee8a3SLang Hames if (auto Err = processCIE(PC, B, RecordStartOffset,
15876aee8a3SLang Hames CIEDeltaFieldOffset + RecordRemaining,
15943acef48SLang Hames CIEDeltaFieldOffset, BlockEdges))
16076aee8a3SLang Hames return Err;
16176aee8a3SLang Hames } else {
16276aee8a3SLang Hames if (auto Err = processFDE(PC, B, RecordStartOffset,
16376aee8a3SLang Hames CIEDeltaFieldOffset + RecordRemaining,
16476aee8a3SLang Hames CIEDeltaFieldOffset, CIEDelta, BlockEdges))
16576aee8a3SLang Hames return Err;
16676aee8a3SLang Hames }
16776aee8a3SLang Hames
16876aee8a3SLang Hames // Move to the next record.
16976aee8a3SLang Hames BlockReader.setOffset(RecordStartOffset + CIEDeltaFieldOffset +
17076aee8a3SLang Hames RecordRemaining);
17176aee8a3SLang Hames }
17276aee8a3SLang Hames
17376aee8a3SLang Hames return Error::success();
17476aee8a3SLang Hames }
17576aee8a3SLang Hames
processCIE(ParseContext & PC,Block & B,size_t RecordOffset,size_t RecordLength,size_t CIEDeltaFieldOffset,const BlockEdgeMap & BlockEdges)17676aee8a3SLang Hames Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
17776aee8a3SLang Hames size_t RecordOffset, size_t RecordLength,
17843acef48SLang Hames size_t CIEDeltaFieldOffset,
17943acef48SLang Hames const BlockEdgeMap &BlockEdges) {
18076aee8a3SLang Hames
18176aee8a3SLang Hames LLVM_DEBUG(dbgs() << " Record is CIE\n");
18276aee8a3SLang Hames
1830269a407SLang Hames auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
1840269a407SLang Hames BinaryStreamReader RecordReader(
1850269a407SLang Hames StringRef(RecordContent.data(), RecordContent.size()),
1860269a407SLang Hames PC.G.getEndianness());
18776aee8a3SLang Hames
18876aee8a3SLang Hames // Skip past the CIE delta field: we've already processed this far.
18976aee8a3SLang Hames RecordReader.setOffset(CIEDeltaFieldOffset + 4);
19076aee8a3SLang Hames
19176aee8a3SLang Hames auto &CIESymbol =
19276aee8a3SLang Hames PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
19376aee8a3SLang Hames CIEInformation CIEInfo(CIESymbol);
19476aee8a3SLang Hames
19576aee8a3SLang Hames uint8_t Version = 0;
19676aee8a3SLang Hames if (auto Err = RecordReader.readInteger(Version))
19776aee8a3SLang Hames return Err;
19876aee8a3SLang Hames
19976aee8a3SLang Hames if (Version != 0x01)
20076aee8a3SLang Hames return make_error<JITLinkError>("Bad CIE version " + Twine(Version) +
20176aee8a3SLang Hames " (should be 0x01) in eh-frame");
20276aee8a3SLang Hames
20376aee8a3SLang Hames auto AugInfo = parseAugmentationString(RecordReader);
20476aee8a3SLang Hames if (!AugInfo)
20576aee8a3SLang Hames return AugInfo.takeError();
20676aee8a3SLang Hames
20776aee8a3SLang Hames // Skip the EH Data field if present.
20876aee8a3SLang Hames if (AugInfo->EHDataFieldPresent)
20976aee8a3SLang Hames if (auto Err = RecordReader.skip(PC.G.getPointerSize()))
21076aee8a3SLang Hames return Err;
21176aee8a3SLang Hames
21259c84774SZarko Todorovski // Read and validate the code alignment factor.
21376aee8a3SLang Hames {
21476aee8a3SLang Hames uint64_t CodeAlignmentFactor = 0;
21576aee8a3SLang Hames if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor))
21676aee8a3SLang Hames return Err;
21776aee8a3SLang Hames }
21876aee8a3SLang Hames
21959c84774SZarko Todorovski // Read and validate the data alignment factor.
22076aee8a3SLang Hames {
22176aee8a3SLang Hames int64_t DataAlignmentFactor = 0;
22276aee8a3SLang Hames if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor))
22376aee8a3SLang Hames return Err;
22476aee8a3SLang Hames }
22576aee8a3SLang Hames
22676aee8a3SLang Hames // Skip the return address register field.
22776aee8a3SLang Hames if (auto Err = RecordReader.skip(1))
22876aee8a3SLang Hames return Err;
22976aee8a3SLang Hames
23043acef48SLang Hames if (AugInfo->AugmentationDataPresent) {
23143acef48SLang Hames
23243acef48SLang Hames CIEInfo.AugmentationDataPresent = true;
23343acef48SLang Hames
23476aee8a3SLang Hames uint64_t AugmentationDataLength = 0;
23576aee8a3SLang Hames if (auto Err = RecordReader.readULEB128(AugmentationDataLength))
23676aee8a3SLang Hames return Err;
23776aee8a3SLang Hames
23876aee8a3SLang Hames uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
23976aee8a3SLang Hames
24076aee8a3SLang Hames uint8_t *NextField = &AugInfo->Fields[0];
24176aee8a3SLang Hames while (uint8_t Field = *NextField++) {
24276aee8a3SLang Hames switch (Field) {
24343acef48SLang Hames case 'L':
24443acef48SLang Hames CIEInfo.LSDAPresent = true;
24543acef48SLang Hames if (auto PE = readPointerEncoding(RecordReader, B, "LSDA"))
24643acef48SLang Hames CIEInfo.LSDAEncoding = *PE;
24743acef48SLang Hames else
24843acef48SLang Hames return PE.takeError();
24976aee8a3SLang Hames break;
25076aee8a3SLang Hames case 'P': {
25143acef48SLang Hames auto PersonalityPointerEncoding =
25243acef48SLang Hames readPointerEncoding(RecordReader, B, "personality");
25343acef48SLang Hames if (!PersonalityPointerEncoding)
25443acef48SLang Hames return PersonalityPointerEncoding.takeError();
25543acef48SLang Hames if (auto Err =
25643acef48SLang Hames getOrCreateEncodedPointerEdge(
25743acef48SLang Hames PC, BlockEdges, *PersonalityPointerEncoding, RecordReader,
25843acef48SLang Hames B, RecordOffset + RecordReader.getOffset(), "personality")
25943acef48SLang Hames .takeError())
26076aee8a3SLang Hames return Err;
26176aee8a3SLang Hames break;
26276aee8a3SLang Hames }
26343acef48SLang Hames case 'R':
26443acef48SLang Hames if (auto PE = readPointerEncoding(RecordReader, B, "address")) {
26543acef48SLang Hames CIEInfo.AddressEncoding = *PE;
26643acef48SLang Hames if (CIEInfo.AddressEncoding == dwarf::DW_EH_PE_omit)
26776aee8a3SLang Hames return make_error<JITLinkError>(
26843acef48SLang Hames "Invalid address encoding DW_EH_PE_omit in CIE at " +
26943acef48SLang Hames formatv("{0:x}", (B.getAddress() + RecordOffset).getValue()));
27043acef48SLang Hames } else
27143acef48SLang Hames return PE.takeError();
27276aee8a3SLang Hames break;
27376aee8a3SLang Hames default:
27476aee8a3SLang Hames llvm_unreachable("Invalid augmentation string field");
27576aee8a3SLang Hames }
27676aee8a3SLang Hames }
27776aee8a3SLang Hames
27876aee8a3SLang Hames if (RecordReader.getOffset() - AugmentationDataStartOffset >
27976aee8a3SLang Hames AugmentationDataLength)
28076aee8a3SLang Hames return make_error<JITLinkError>("Read past the end of the augmentation "
28176aee8a3SLang Hames "data while parsing fields");
28243acef48SLang Hames }
28376aee8a3SLang Hames
28476aee8a3SLang Hames assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
28576aee8a3SLang Hames "Multiple CIEs recorded at the same address?");
28676aee8a3SLang Hames PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
28776aee8a3SLang Hames
28876aee8a3SLang Hames return Error::success();
28976aee8a3SLang Hames }
29076aee8a3SLang Hames
processFDE(ParseContext & PC,Block & B,size_t RecordOffset,size_t RecordLength,size_t CIEDeltaFieldOffset,uint32_t CIEDelta,const BlockEdgeMap & BlockEdges)29176aee8a3SLang Hames Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
29276aee8a3SLang Hames size_t RecordOffset, size_t RecordLength,
29376aee8a3SLang Hames size_t CIEDeltaFieldOffset,
29476aee8a3SLang Hames uint32_t CIEDelta,
29543acef48SLang Hames const BlockEdgeMap &BlockEdges) {
29676aee8a3SLang Hames LLVM_DEBUG(dbgs() << " Record is FDE\n");
29776aee8a3SLang Hames
298118e953bSLang Hames orc::ExecutorAddr RecordAddress = B.getAddress() + RecordOffset;
29976aee8a3SLang Hames
3000269a407SLang Hames auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
3010269a407SLang Hames BinaryStreamReader RecordReader(
3020269a407SLang Hames StringRef(RecordContent.data(), RecordContent.size()),
3030269a407SLang Hames PC.G.getEndianness());
30476aee8a3SLang Hames
30576aee8a3SLang Hames // Skip past the CIE delta field: we've already read this far.
30676aee8a3SLang Hames RecordReader.setOffset(CIEDeltaFieldOffset + 4);
30776aee8a3SLang Hames
30876aee8a3SLang Hames auto &FDESymbol =
30976aee8a3SLang Hames PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
31076aee8a3SLang Hames
31176aee8a3SLang Hames CIEInformation *CIEInfo = nullptr;
31276aee8a3SLang Hames
31376aee8a3SLang Hames {
31476aee8a3SLang Hames // Process the CIE pointer field.
31576aee8a3SLang Hames auto CIEEdgeItr = BlockEdges.find(RecordOffset + CIEDeltaFieldOffset);
316118e953bSLang Hames orc::ExecutorAddr CIEAddress =
317118e953bSLang Hames RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) -
318118e953bSLang Hames orc::ExecutorAddrDiff(CIEDelta);
31976aee8a3SLang Hames if (CIEEdgeItr == BlockEdges.end()) {
32076aee8a3SLang Hames
32176aee8a3SLang Hames LLVM_DEBUG({
32276aee8a3SLang Hames dbgs() << " Adding edge at "
32343acef48SLang Hames << (RecordAddress + CIEDeltaFieldOffset)
32443acef48SLang Hames << " to CIE at: " << CIEAddress << "\n";
32576aee8a3SLang Hames });
32676aee8a3SLang Hames if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
32776aee8a3SLang Hames CIEInfo = *CIEInfoOrErr;
32876aee8a3SLang Hames else
32976aee8a3SLang Hames return CIEInfoOrErr.takeError();
33076aee8a3SLang Hames assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");
33145ad6facSLang Hames B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset,
33276aee8a3SLang Hames *CIEInfo->CIESymbol, 0);
33376aee8a3SLang Hames } else {
33476aee8a3SLang Hames LLVM_DEBUG({
33576aee8a3SLang Hames dbgs() << " Already has edge at "
33643acef48SLang Hames << (RecordAddress + CIEDeltaFieldOffset) << " to CIE at "
33743acef48SLang Hames << CIEAddress << "\n";
33876aee8a3SLang Hames });
33976aee8a3SLang Hames auto &EI = CIEEdgeItr->second;
34076aee8a3SLang Hames if (EI.Addend)
34176aee8a3SLang Hames return make_error<JITLinkError>(
34276aee8a3SLang Hames "CIE edge at " +
34376aee8a3SLang Hames formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) +
34476aee8a3SLang Hames " has non-zero addend");
34576aee8a3SLang Hames if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))
34676aee8a3SLang Hames CIEInfo = *CIEInfoOrErr;
34776aee8a3SLang Hames else
34876aee8a3SLang Hames return CIEInfoOrErr.takeError();
34976aee8a3SLang Hames }
35076aee8a3SLang Hames }
35176aee8a3SLang Hames
35276aee8a3SLang Hames // Process the PC-Begin field.
35376aee8a3SLang Hames LLVM_DEBUG({
35443acef48SLang Hames dbgs() << " Processing PC-begin at "
35543acef48SLang Hames << (RecordAddress + RecordReader.getOffset()) << "\n";
35676aee8a3SLang Hames });
35743acef48SLang Hames if (auto PCBegin = getOrCreateEncodedPointerEdge(
35843acef48SLang Hames PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader, B,
35943acef48SLang Hames RecordReader.getOffset(), "PC begin")) {
36043acef48SLang Hames assert(*PCBegin && "PC-begin symbol not set");
36176aee8a3SLang Hames // Add a keep-alive edge from the FDE target to the FDE to ensure that the
36276aee8a3SLang Hames // FDE is kept alive if its target is.
363cda4d3d3SLang Hames LLVM_DEBUG({
364cda4d3d3SLang Hames dbgs() << " Adding keep-alive edge from target at "
36543acef48SLang Hames << (*PCBegin)->getBlock().getAddress() << " to FDE at "
36643acef48SLang Hames << RecordAddress << "\n";
367cda4d3d3SLang Hames });
36843acef48SLang Hames (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
36943acef48SLang Hames } else
37043acef48SLang Hames return PCBegin.takeError();
37176aee8a3SLang Hames
37276aee8a3SLang Hames // Skip over the PC range size field.
37343acef48SLang Hames if (auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader))
37476aee8a3SLang Hames return Err;
37576aee8a3SLang Hames
37643acef48SLang Hames if (CIEInfo->AugmentationDataPresent) {
37776aee8a3SLang Hames uint64_t AugmentationDataSize;
37876aee8a3SLang Hames if (auto Err = RecordReader.readULEB128(AugmentationDataSize))
37976aee8a3SLang Hames return Err;
38076aee8a3SLang Hames
38143acef48SLang Hames if (CIEInfo->LSDAPresent)
38243acef48SLang Hames if (auto Err = getOrCreateEncodedPointerEdge(
38343acef48SLang Hames PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader, B,
38443acef48SLang Hames RecordReader.getOffset(), "LSDA")
38543acef48SLang Hames .takeError())
38676aee8a3SLang Hames return Err;
38776aee8a3SLang Hames } else {
38876aee8a3SLang Hames LLVM_DEBUG(dbgs() << " Record does not have LSDA field.\n");
38976aee8a3SLang Hames }
39076aee8a3SLang Hames
39176aee8a3SLang Hames return Error::success();
39276aee8a3SLang Hames }
39376aee8a3SLang Hames
39476aee8a3SLang Hames Expected<EHFrameEdgeFixer::AugmentationInfo>
parseAugmentationString(BinaryStreamReader & RecordReader)39576aee8a3SLang Hames EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
3961233c15bSLang Hames AugmentationInfo AugInfo;
3971233c15bSLang Hames uint8_t NextChar;
3981233c15bSLang Hames uint8_t *NextField = &AugInfo.Fields[0];
3991233c15bSLang Hames
40076aee8a3SLang Hames if (auto Err = RecordReader.readInteger(NextChar))
401c55cf4afSBill Wendling return std::move(Err);
4021233c15bSLang Hames
4031233c15bSLang Hames while (NextChar != 0) {
4041233c15bSLang Hames switch (NextChar) {
4051233c15bSLang Hames case 'z':
4061233c15bSLang Hames AugInfo.AugmentationDataPresent = true;
4071233c15bSLang Hames break;
4081233c15bSLang Hames case 'e':
40976aee8a3SLang Hames if (auto Err = RecordReader.readInteger(NextChar))
410c55cf4afSBill Wendling return std::move(Err);
4111233c15bSLang Hames if (NextChar != 'h')
4121233c15bSLang Hames return make_error<JITLinkError>("Unrecognized substring e" +
4131233c15bSLang Hames Twine(NextChar) +
4141233c15bSLang Hames " in augmentation string");
4151233c15bSLang Hames AugInfo.EHDataFieldPresent = true;
4161233c15bSLang Hames break;
4171233c15bSLang Hames case 'L':
4181233c15bSLang Hames case 'P':
4191233c15bSLang Hames case 'R':
4201233c15bSLang Hames *NextField++ = NextChar;
4211233c15bSLang Hames break;
4221233c15bSLang Hames default:
4231233c15bSLang Hames return make_error<JITLinkError>("Unrecognized character " +
4241233c15bSLang Hames Twine(NextChar) +
4251233c15bSLang Hames " in augmentation string");
4261233c15bSLang Hames }
4271233c15bSLang Hames
42876aee8a3SLang Hames if (auto Err = RecordReader.readInteger(NextChar))
429c55cf4afSBill Wendling return std::move(Err);
4301233c15bSLang Hames }
4311233c15bSLang Hames
432c55cf4afSBill Wendling return std::move(AugInfo);
4331233c15bSLang Hames }
4341233c15bSLang Hames
readPointerEncoding(BinaryStreamReader & R,Block & InBlock,const char * FieldName)43543acef48SLang Hames Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R,
43643acef48SLang Hames Block &InBlock,
43743acef48SLang Hames const char *FieldName) {
438cda4d3d3SLang Hames using namespace dwarf;
439cda4d3d3SLang Hames
44043acef48SLang Hames uint8_t PointerEncoding;
44143acef48SLang Hames if (auto Err = R.readInteger(PointerEncoding))
4420d11351bSLang Hames return std::move(Err);
443cda4d3d3SLang Hames
44443acef48SLang Hames bool Supported = true;
445cda4d3d3SLang Hames switch (PointerEncoding & 0xf) {
44643acef48SLang Hames case DW_EH_PE_uleb128:
44743acef48SLang Hames case DW_EH_PE_udata2:
44843acef48SLang Hames case DW_EH_PE_sleb128:
44943acef48SLang Hames case DW_EH_PE_sdata2:
45043acef48SLang Hames Supported = false;
45143acef48SLang Hames break;
452cda4d3d3SLang Hames }
45343acef48SLang Hames if (Supported) {
45443acef48SLang Hames switch (PointerEncoding & 0x70) {
45543acef48SLang Hames case DW_EH_PE_textrel:
45643acef48SLang Hames case DW_EH_PE_datarel:
45743acef48SLang Hames case DW_EH_PE_funcrel:
45843acef48SLang Hames case DW_EH_PE_aligned:
45943acef48SLang Hames Supported = false;
46043acef48SLang Hames break;
461cda4d3d3SLang Hames }
462cda4d3d3SLang Hames }
463cda4d3d3SLang Hames
46443acef48SLang Hames if (Supported)
46543acef48SLang Hames return PointerEncoding;
46643acef48SLang Hames
46743acef48SLang Hames return make_error<JITLinkError>("Unsupported pointer encoding " +
46843acef48SLang Hames formatv("{0:x2}", PointerEncoding) + " for " +
46943acef48SLang Hames FieldName + "in CFI record at " +
47043acef48SLang Hames formatv("{0:x16}", InBlock.getAddress()));
47143acef48SLang Hames }
47243acef48SLang Hames
skipEncodedPointer(uint8_t PointerEncoding,BinaryStreamReader & RecordReader)47343acef48SLang Hames Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding,
47476aee8a3SLang Hames BinaryStreamReader &RecordReader) {
475cda4d3d3SLang Hames using namespace dwarf;
476cda4d3d3SLang Hames
47743acef48SLang Hames // Switch absptr to corresponding udata encoding.
47843acef48SLang Hames if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
47943acef48SLang Hames PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
480cda4d3d3SLang Hames
48143acef48SLang Hames switch (PointerEncoding & 0xf) {
48243acef48SLang Hames case DW_EH_PE_udata4:
48343acef48SLang Hames case DW_EH_PE_sdata4:
48443acef48SLang Hames if (auto Err = RecordReader.skip(4))
48543acef48SLang Hames return Err;
48643acef48SLang Hames break;
48743acef48SLang Hames case DW_EH_PE_udata8:
48843acef48SLang Hames case DW_EH_PE_sdata8:
48943acef48SLang Hames if (auto Err = RecordReader.skip(8))
49043acef48SLang Hames return Err;
49143acef48SLang Hames break;
49243acef48SLang Hames default:
49343acef48SLang Hames llvm_unreachable("Unrecognized encoding");
49443acef48SLang Hames }
49543acef48SLang Hames return Error::success();
49643acef48SLang Hames }
49743acef48SLang Hames
getOrCreateEncodedPointerEdge(ParseContext & PC,const BlockEdgeMap & BlockEdges,uint8_t PointerEncoding,BinaryStreamReader & RecordReader,Block & BlockToFix,size_t PointerFieldOffset,const char * FieldName)49843acef48SLang Hames Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge(
49943acef48SLang Hames ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding,
50043acef48SLang Hames BinaryStreamReader &RecordReader, Block &BlockToFix,
50143acef48SLang Hames size_t PointerFieldOffset, const char *FieldName) {
50243acef48SLang Hames using namespace dwarf;
50343acef48SLang Hames
50443acef48SLang Hames if (PointerEncoding == DW_EH_PE_omit)
50543acef48SLang Hames return nullptr;
50643acef48SLang Hames
50743acef48SLang Hames // If there's already an edge here then just skip the encoded pointer and
50843acef48SLang Hames // return the edge's target.
50943acef48SLang Hames {
51043acef48SLang Hames auto EdgeI = BlockEdges.find(PointerFieldOffset);
51143acef48SLang Hames if (EdgeI != BlockEdges.end()) {
51243acef48SLang Hames LLVM_DEBUG({
51343acef48SLang Hames dbgs() << " Existing edge at "
51443acef48SLang Hames << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
51543acef48SLang Hames << FieldName << " at " << EdgeI->second.Target->getAddress();
51643acef48SLang Hames if (EdgeI->second.Target->hasName())
51743acef48SLang Hames dbgs() << " (" << EdgeI->second.Target->getName() << ")";
51843acef48SLang Hames dbgs() << "\n";
51943acef48SLang Hames });
52043acef48SLang Hames if (auto Err = skipEncodedPointer(PointerEncoding, RecordReader))
5210d11351bSLang Hames return std::move(Err);
52243acef48SLang Hames return EdgeI->second.Target;
52343acef48SLang Hames }
52443acef48SLang Hames }
52543acef48SLang Hames
52643acef48SLang Hames // Switch absptr to corresponding udata encoding.
52743acef48SLang Hames if ((PointerEncoding & 0xf) == DW_EH_PE_absptr)
52843acef48SLang Hames PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
52943acef48SLang Hames
53043acef48SLang Hames // We need to create an edge. Start by reading the field value.
53143acef48SLang Hames uint64_t FieldValue;
53243acef48SLang Hames bool Is64Bit = false;
53343acef48SLang Hames switch (PointerEncoding & 0xf) {
534cda4d3d3SLang Hames case DW_EH_PE_udata4: {
535cda4d3d3SLang Hames uint32_t Val;
536cda4d3d3SLang Hames if (auto Err = RecordReader.readInteger(Val))
537c55cf4afSBill Wendling return std::move(Err);
53843acef48SLang Hames FieldValue = Val;
539cda4d3d3SLang Hames break;
540cda4d3d3SLang Hames }
541cda4d3d3SLang Hames case DW_EH_PE_sdata4: {
54243acef48SLang Hames uint32_t Val;
543cda4d3d3SLang Hames if (auto Err = RecordReader.readInteger(Val))
544cda4d3d3SLang Hames return std::move(Err);
54543acef48SLang Hames FieldValue = Val;
546cda4d3d3SLang Hames break;
547cda4d3d3SLang Hames }
54843acef48SLang Hames case DW_EH_PE_udata8:
54943acef48SLang Hames case DW_EH_PE_sdata8:
55043acef48SLang Hames Is64Bit = true;
55143acef48SLang Hames if (auto Err = RecordReader.readInteger(FieldValue))
552cda4d3d3SLang Hames return std::move(Err);
553cda4d3d3SLang Hames break;
55443acef48SLang Hames default:
55543acef48SLang Hames llvm_unreachable("Unsupported encoding");
556cda4d3d3SLang Hames }
557cda4d3d3SLang Hames
55843acef48SLang Hames // Find the edge target and edge kind to use.
55943acef48SLang Hames orc::ExecutorAddr Target;
56043acef48SLang Hames Edge::Kind PtrEdgeKind = Edge::Invalid;
56143acef48SLang Hames if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) {
56243acef48SLang Hames Target = BlockToFix.getAddress() + PointerFieldOffset;
56343acef48SLang Hames PtrEdgeKind = Is64Bit ? Delta64 : Delta32;
56443acef48SLang Hames } else
56543acef48SLang Hames PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32;
56643acef48SLang Hames Target += FieldValue;
567cda4d3d3SLang Hames
56843acef48SLang Hames // Find or create a symbol to point the edge at.
56943acef48SLang Hames auto TargetSym = getOrCreateSymbol(PC, Target);
57043acef48SLang Hames if (!TargetSym)
57143acef48SLang Hames return TargetSym.takeError();
57243acef48SLang Hames BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0);
57343acef48SLang Hames
57443acef48SLang Hames LLVM_DEBUG({
57543acef48SLang Hames dbgs() << " Adding edge at "
57643acef48SLang Hames << (BlockToFix.getAddress() + PointerFieldOffset) << " to "
57743acef48SLang Hames << FieldName << " at " << TargetSym->getAddress();
57843acef48SLang Hames if (TargetSym->hasName())
57943acef48SLang Hames dbgs() << " (" << TargetSym->getName() << ")";
58043acef48SLang Hames dbgs() << "\n";
58143acef48SLang Hames });
58243acef48SLang Hames
58343acef48SLang Hames return &*TargetSym;
5841233c15bSLang Hames }
5851233c15bSLang Hames
getOrCreateSymbol(ParseContext & PC,orc::ExecutorAddr Addr)58676aee8a3SLang Hames Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
587118e953bSLang Hames orc::ExecutorAddr Addr) {
58801bc5b70SLang Hames // See whether we have a canonical symbol for the given address already.
58901bc5b70SLang Hames auto CanonicalSymI = PC.AddrToSym.find(Addr);
59001bc5b70SLang Hames if (CanonicalSymI != PC.AddrToSym.end())
59101bc5b70SLang Hames return *CanonicalSymI->second;
5921233c15bSLang Hames
59376aee8a3SLang Hames // Otherwise search for a block covering the address and create a new symbol.
59476aee8a3SLang Hames auto *B = PC.AddrToBlock.getBlockCovering(Addr);
59576aee8a3SLang Hames if (!B)
59676aee8a3SLang Hames return make_error<JITLinkError>("No symbol or block covering address " +
59776aee8a3SLang Hames formatv("{0:x16}", Addr));
5981233c15bSLang Hames
59901bc5b70SLang Hames auto &S =
60001bc5b70SLang Hames PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
60101bc5b70SLang Hames PC.AddrToSym[S.getAddress()] = &S;
60201bc5b70SLang Hames return S;
6031233c15bSLang Hames }
6041233c15bSLang Hames
6050269a407SLang Hames char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
606bcb53999SLang Hames
EHFrameNullTerminator(StringRef EHFrameSectionName)607bcb53999SLang Hames EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName)
608bcb53999SLang Hames : EHFrameSectionName(EHFrameSectionName) {}
609bcb53999SLang Hames
operator ()(LinkGraph & G)610bcb53999SLang Hames Error EHFrameNullTerminator::operator()(LinkGraph &G) {
611bcb53999SLang Hames auto *EHFrame = G.findSectionByName(EHFrameSectionName);
612bcb53999SLang Hames
613bcb53999SLang Hames if (!EHFrame)
614bcb53999SLang Hames return Error::success();
615bcb53999SLang Hames
616bcb53999SLang Hames LLVM_DEBUG({
617bcb53999SLang Hames dbgs() << "EHFrameNullTerminator adding null terminator to "
618bcb53999SLang Hames << EHFrameSectionName << "\n";
619bcb53999SLang Hames });
620bcb53999SLang Hames
621118e953bSLang Hames auto &NullTerminatorBlock =
622118e953bSLang Hames G.createContentBlock(*EHFrame, NullTerminatorBlockContent,
623118e953bSLang Hames orc::ExecutorAddr(~uint64_t(4)), 1, 0);
624bcb53999SLang Hames G.addAnonymousSymbol(NullTerminatorBlock, 0, 4, false, true);
625bcb53999SLang Hames return Error::success();
626bcb53999SLang Hames }
627bcb53999SLang Hames
6283a3cb929SKazu Hirata EHFrameRegistrar::~EHFrameRegistrar() = default;
629f5a885fdSLang Hames
registerEHFrames(orc::ExecutorAddrRange EHFrameSection)630605df811SLang Hames Error InProcessEHFrameRegistrar::registerEHFrames(
631089acf25SLang Hames orc::ExecutorAddrRange EHFrameSection) {
632089acf25SLang Hames return orc::registerEHFrameSection(EHFrameSection.Start.toPtr<void *>(),
633089acf25SLang Hames EHFrameSection.size());
634f5a885fdSLang Hames }
635f5a885fdSLang Hames
deregisterEHFrames(orc::ExecutorAddrRange EHFrameSection)636605df811SLang Hames Error InProcessEHFrameRegistrar::deregisterEHFrames(
637089acf25SLang Hames orc::ExecutorAddrRange EHFrameSection) {
638089acf25SLang Hames return orc::deregisterEHFrameSection(EHFrameSection.Start.toPtr<void *>(),
639089acf25SLang Hames EHFrameSection.size());
640605df811SLang Hames }
641f5a885fdSLang Hames
6424e920e58SLang Hames LinkGraphPassFunction
createEHFrameRecorderPass(const Triple & TT,StoreFrameRangeFunction StoreRangeAddress)643a9fdf375SLang Hames createEHFrameRecorderPass(const Triple &TT,
644c48f1f6dSLang Hames StoreFrameRangeFunction StoreRangeAddress) {
6451233c15bSLang Hames const char *EHFrameSectionName = nullptr;
6461233c15bSLang Hames if (TT.getObjectFormat() == Triple::MachO)
64719e402d2SLang Hames EHFrameSectionName = "__TEXT,__eh_frame";
6481233c15bSLang Hames else
6491233c15bSLang Hames EHFrameSectionName = ".eh_frame";
6501233c15bSLang Hames
651c48f1f6dSLang Hames auto RecordEHFrame =
652c48f1f6dSLang Hames [EHFrameSectionName,
6534e920e58SLang Hames StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error {
6544e920e58SLang Hames // Search for a non-empty eh-frame and record the address of the first
6554e920e58SLang Hames // symbol in it.
656118e953bSLang Hames orc::ExecutorAddr Addr;
657c48f1f6dSLang Hames size_t Size = 0;
658c48f1f6dSLang Hames if (auto *S = G.findSectionByName(EHFrameSectionName)) {
6594e920e58SLang Hames auto R = SectionRange(*S);
660c48f1f6dSLang Hames Addr = R.getStart();
661c48f1f6dSLang Hames Size = R.getSize();
662c48f1f6dSLang Hames }
663118e953bSLang Hames if (!Addr && Size != 0)
66419e402d2SLang Hames return make_error<JITLinkError>(
66519e402d2SLang Hames StringRef(EHFrameSectionName) +
66619e402d2SLang Hames " section can not have zero address with non-zero size");
667c48f1f6dSLang Hames StoreFrameRange(Addr, Size);
6681233c15bSLang Hames return Error::success();
6691233c15bSLang Hames };
6701233c15bSLang Hames
6711233c15bSLang Hames return RecordEHFrame;
6721233c15bSLang Hames }
6731233c15bSLang Hames
6741233c15bSLang Hames } // end namespace jitlink
6751233c15bSLang Hames } // end namespace llvm
676