123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806 |
- //===-------- JITLink_EHFrameSupport.cpp - JITLink eh-frame utils ---------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "EHFrameSupportImpl.h"
- #include "llvm/BinaryFormat/Dwarf.h"
- #include "llvm/Config/config.h"
- #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
- #include "llvm/Support/DynamicLibrary.h"
- #define DEBUG_TYPE "jitlink"
- namespace llvm {
- namespace jitlink {
- EHFrameSplitter::EHFrameSplitter(StringRef EHFrameSectionName)
- : EHFrameSectionName(EHFrameSectionName) {}
- Error EHFrameSplitter::operator()(LinkGraph &G) {
- auto *EHFrame = G.findSectionByName(EHFrameSectionName);
- if (!EHFrame) {
- LLVM_DEBUG({
- dbgs() << "EHFrameSplitter: No " << EHFrameSectionName
- << " section. Nothing to do\n";
- });
- return Error::success();
- }
- LLVM_DEBUG({
- dbgs() << "EHFrameSplitter: Processing " << EHFrameSectionName << "...\n";
- });
- DenseMap<Block *, LinkGraph::SplitBlockCache> Caches;
- {
- // Pre-build the split caches.
- for (auto *B : EHFrame->blocks())
- Caches[B] = LinkGraph::SplitBlockCache::value_type();
- for (auto *Sym : EHFrame->symbols())
- Caches[&Sym->getBlock()]->push_back(Sym);
- for (auto *B : EHFrame->blocks())
- llvm::sort(*Caches[B], [](const Symbol *LHS, const Symbol *RHS) {
- return LHS->getOffset() > RHS->getOffset();
- });
- }
- // Iterate over blocks (we do this by iterating over Caches entries rather
- // than EHFrame->blocks() as we will be inserting new blocks along the way,
- // which would invalidate iterators in the latter sequence.
- for (auto &KV : Caches) {
- auto &B = *KV.first;
- auto &BCache = KV.second;
- if (auto Err = processBlock(G, B, BCache))
- return Err;
- }
- return Error::success();
- }
- Error EHFrameSplitter::processBlock(LinkGraph &G, Block &B,
- LinkGraph::SplitBlockCache &Cache) {
- LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n");
- // eh-frame should not contain zero-fill blocks.
- if (B.isZeroFill())
- return make_error<JITLinkError>("Unexpected zero-fill block in " +
- EHFrameSectionName + " section");
- if (B.getSize() == 0) {
- LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n");
- return Error::success();
- }
- BinaryStreamReader BlockReader(
- StringRef(B.getContent().data(), B.getContent().size()),
- G.getEndianness());
- while (true) {
- uint64_t RecordStartOffset = BlockReader.getOffset();
- LLVM_DEBUG({
- dbgs() << " Processing CFI record at "
- << formatv("{0:x16}", B.getAddress()) << "\n";
- });
- uint32_t Length;
- if (auto Err = BlockReader.readInteger(Length))
- return Err;
- if (Length != 0xffffffff) {
- if (auto Err = BlockReader.skip(Length))
- return Err;
- } else {
- uint64_t ExtendedLength;
- if (auto Err = BlockReader.readInteger(ExtendedLength))
- return Err;
- if (auto Err = BlockReader.skip(ExtendedLength))
- return Err;
- }
- // If this was the last block then there's nothing to split
- if (BlockReader.empty()) {
- LLVM_DEBUG(dbgs() << " Extracted " << B << "\n");
- return Error::success();
- }
- uint64_t BlockSize = BlockReader.getOffset() - RecordStartOffset;
- auto &NewBlock = G.splitBlock(B, BlockSize);
- (void)NewBlock;
- LLVM_DEBUG(dbgs() << " Extracted " << NewBlock << "\n");
- }
- }
- EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName,
- unsigned PointerSize, Edge::Kind Delta64,
- Edge::Kind Delta32, Edge::Kind NegDelta32)
- : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize),
- Delta64(Delta64), Delta32(Delta32), NegDelta32(NegDelta32) {}
- Error EHFrameEdgeFixer::operator()(LinkGraph &G) {
- auto *EHFrame = G.findSectionByName(EHFrameSectionName);
- if (!EHFrame) {
- LLVM_DEBUG({
- dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName
- << " section. Nothing to do\n";
- });
- return Error::success();
- }
- // Check that we support the graph's pointer size.
- if (G.getPointerSize() != 4 && G.getPointerSize() != 8)
- return make_error<JITLinkError>(
- "EHFrameEdgeFixer only supports 32 and 64 bit targets");
- LLVM_DEBUG({
- dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << "...\n";
- });
- ParseContext PC(G);
- // Build a map of all blocks and symbols in the text sections. We will use
- // these for finding / building edge targets when processing FDEs.
- for (auto &Sec : G.sections()) {
- PC.AddrToSyms.addSymbols(Sec.symbols());
- if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(),
- BlockAddressMap::includeNonNull))
- return Err;
- }
- // Sort eh-frame blocks into address order to ensure we visit CIEs before
- // their child FDEs.
- std::vector<Block *> EHFrameBlocks;
- for (auto *B : EHFrame->blocks())
- EHFrameBlocks.push_back(B);
- llvm::sort(EHFrameBlocks, [](const Block *LHS, const Block *RHS) {
- return LHS->getAddress() < RHS->getAddress();
- });
- // Loop over the blocks in address order.
- for (auto *B : EHFrameBlocks)
- if (auto Err = processBlock(PC, *B))
- return Err;
- return Error::success();
- }
- Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) {
- LLVM_DEBUG({
- dbgs() << " Processing block at " << formatv("{0:x16}", B.getAddress())
- << "\n";
- });
- // eh-frame should not contain zero-fill blocks.
- if (B.isZeroFill())
- return make_error<JITLinkError>("Unexpected zero-fill block in " +
- EHFrameSectionName + " section");
- if (B.getSize() == 0) {
- LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n");
- return Error::success();
- }
- // Find the offsets of any existing edges from this block.
- BlockEdgeMap BlockEdges;
- for (auto &E : B.edges())
- if (E.isRelocation()) {
- if (BlockEdges.count(E.getOffset()))
- return make_error<JITLinkError>(
- "Multiple relocations at offset " +
- formatv("{0:x16}", E.getOffset()) + " in " + EHFrameSectionName +
- " block at address " + formatv("{0:x16}", B.getAddress()));
- BlockEdges[E.getOffset()] = EdgeTarget(E);
- }
- CIEInfosMap CIEInfos;
- BinaryStreamReader BlockReader(
- StringRef(B.getContent().data(), B.getContent().size()),
- PC.G.getEndianness());
- while (!BlockReader.empty()) {
- size_t RecordStartOffset = BlockReader.getOffset();
- LLVM_DEBUG({
- dbgs() << " Processing CFI record at "
- << formatv("{0:x16}", B.getAddress() + RecordStartOffset) << "\n";
- });
- // Get the record length.
- size_t RecordRemaining;
- {
- uint32_t Length;
- if (auto Err = BlockReader.readInteger(Length))
- return Err;
- // If Length < 0xffffffff then use the regular length field, otherwise
- // read the extended length field.
- if (Length != 0xffffffff)
- RecordRemaining = Length;
- else {
- uint64_t ExtendedLength;
- if (auto Err = BlockReader.readInteger(ExtendedLength))
- return Err;
- RecordRemaining = ExtendedLength;
- }
- }
- if (BlockReader.bytesRemaining() < RecordRemaining)
- return make_error<JITLinkError>(
- "Incomplete CFI record at " +
- formatv("{0:x16}", B.getAddress() + RecordStartOffset));
- // Read the CIE delta for this record.
- uint64_t CIEDeltaFieldOffset = BlockReader.getOffset() - RecordStartOffset;
- uint32_t CIEDelta;
- if (auto Err = BlockReader.readInteger(CIEDelta))
- return Err;
- if (CIEDelta == 0) {
- if (auto Err = processCIE(PC, B, RecordStartOffset,
- CIEDeltaFieldOffset + RecordRemaining,
- CIEDeltaFieldOffset))
- return Err;
- } else {
- if (auto Err = processFDE(PC, B, RecordStartOffset,
- CIEDeltaFieldOffset + RecordRemaining,
- CIEDeltaFieldOffset, CIEDelta, BlockEdges))
- return Err;
- }
- // Move to the next record.
- BlockReader.setOffset(RecordStartOffset + CIEDeltaFieldOffset +
- RecordRemaining);
- }
- return Error::success();
- }
- Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B,
- size_t RecordOffset, size_t RecordLength,
- size_t CIEDeltaFieldOffset) {
- LLVM_DEBUG(dbgs() << " Record is CIE\n");
- auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
- BinaryStreamReader RecordReader(
- StringRef(RecordContent.data(), RecordContent.size()),
- PC.G.getEndianness());
- // Skip past the CIE delta field: we've already processed this far.
- RecordReader.setOffset(CIEDeltaFieldOffset + 4);
- auto &CIESymbol =
- PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
- CIEInformation CIEInfo(CIESymbol);
- uint8_t Version = 0;
- if (auto Err = RecordReader.readInteger(Version))
- return Err;
- if (Version != 0x01)
- return make_error<JITLinkError>("Bad CIE version " + Twine(Version) +
- " (should be 0x01) in eh-frame");
- auto AugInfo = parseAugmentationString(RecordReader);
- if (!AugInfo)
- return AugInfo.takeError();
- // Skip the EH Data field if present.
- if (AugInfo->EHDataFieldPresent)
- if (auto Err = RecordReader.skip(PC.G.getPointerSize()))
- return Err;
- // Read and validate the code alignment factor.
- {
- uint64_t CodeAlignmentFactor = 0;
- if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor))
- return Err;
- if (CodeAlignmentFactor != 1)
- return make_error<JITLinkError>("Unsupported CIE code alignment factor " +
- Twine(CodeAlignmentFactor) +
- " (expected 1)");
- }
- // Read and validate the data alignment factor.
- {
- int64_t DataAlignmentFactor = 0;
- if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor))
- return Err;
- if (DataAlignmentFactor != -8)
- return make_error<JITLinkError>("Unsupported CIE data alignment factor " +
- Twine(DataAlignmentFactor) +
- " (expected -8)");
- }
- // Skip the return address register field.
- if (auto Err = RecordReader.skip(1))
- return Err;
- uint64_t AugmentationDataLength = 0;
- if (auto Err = RecordReader.readULEB128(AugmentationDataLength))
- return Err;
- uint32_t AugmentationDataStartOffset = RecordReader.getOffset();
- uint8_t *NextField = &AugInfo->Fields[0];
- while (uint8_t Field = *NextField++) {
- switch (Field) {
- case 'L': {
- CIEInfo.FDEsHaveLSDAField = true;
- uint8_t LSDAPointerEncoding;
- if (auto Err = RecordReader.readInteger(LSDAPointerEncoding))
- return Err;
- if (!isSupportedPointerEncoding(LSDAPointerEncoding))
- return make_error<JITLinkError>(
- "Unsupported LSDA pointer encoding " +
- formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " +
- formatv("{0:x16}", CIESymbol.getAddress()));
- CIEInfo.LSDAPointerEncoding = LSDAPointerEncoding;
- break;
- }
- case 'P': {
- uint8_t PersonalityPointerEncoding = 0;
- if (auto Err = RecordReader.readInteger(PersonalityPointerEncoding))
- return Err;
- if (PersonalityPointerEncoding !=
- (dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
- dwarf::DW_EH_PE_sdata4))
- return make_error<JITLinkError>(
- "Unspported personality pointer "
- "encoding " +
- formatv("{0:x2}", PersonalityPointerEncoding) + " in CIE at " +
- formatv("{0:x16}", CIESymbol.getAddress()));
- uint32_t PersonalityPointerAddress;
- if (auto Err = RecordReader.readInteger(PersonalityPointerAddress))
- return Err;
- break;
- }
- case 'R': {
- uint8_t FDEPointerEncoding;
- if (auto Err = RecordReader.readInteger(FDEPointerEncoding))
- return Err;
- if (!isSupportedPointerEncoding(FDEPointerEncoding))
- return make_error<JITLinkError>(
- "Unsupported FDE pointer encoding " +
- formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " +
- formatv("{0:x16}", CIESymbol.getAddress()));
- CIEInfo.FDEPointerEncoding = FDEPointerEncoding;
- break;
- }
- default:
- llvm_unreachable("Invalid augmentation string field");
- }
- }
- if (RecordReader.getOffset() - AugmentationDataStartOffset >
- AugmentationDataLength)
- return make_error<JITLinkError>("Read past the end of the augmentation "
- "data while parsing fields");
- assert(!PC.CIEInfos.count(CIESymbol.getAddress()) &&
- "Multiple CIEs recorded at the same address?");
- PC.CIEInfos[CIESymbol.getAddress()] = std::move(CIEInfo);
- return Error::success();
- }
- Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B,
- size_t RecordOffset, size_t RecordLength,
- size_t CIEDeltaFieldOffset,
- uint32_t CIEDelta,
- BlockEdgeMap &BlockEdges) {
- LLVM_DEBUG(dbgs() << " Record is FDE\n");
- orc::ExecutorAddr RecordAddress = B.getAddress() + RecordOffset;
- auto RecordContent = B.getContent().slice(RecordOffset, RecordLength);
- BinaryStreamReader RecordReader(
- StringRef(RecordContent.data(), RecordContent.size()),
- PC.G.getEndianness());
- // Skip past the CIE delta field: we've already read this far.
- RecordReader.setOffset(CIEDeltaFieldOffset + 4);
- auto &FDESymbol =
- PC.G.addAnonymousSymbol(B, RecordOffset, RecordLength, false, false);
- CIEInformation *CIEInfo = nullptr;
- {
- // Process the CIE pointer field.
- auto CIEEdgeItr = BlockEdges.find(RecordOffset + CIEDeltaFieldOffset);
- orc::ExecutorAddr CIEAddress =
- RecordAddress + orc::ExecutorAddrDiff(CIEDeltaFieldOffset) -
- orc::ExecutorAddrDiff(CIEDelta);
- if (CIEEdgeItr == BlockEdges.end()) {
- LLVM_DEBUG({
- dbgs() << " Adding edge at "
- << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset)
- << " to CIE at: " << formatv("{0:x16}", CIEAddress) << "\n";
- });
- if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress))
- CIEInfo = *CIEInfoOrErr;
- else
- return CIEInfoOrErr.takeError();
- assert(CIEInfo->CIESymbol && "CIEInfo has no CIE symbol set");
- B.addEdge(NegDelta32, RecordOffset + CIEDeltaFieldOffset,
- *CIEInfo->CIESymbol, 0);
- } else {
- LLVM_DEBUG({
- dbgs() << " Already has edge at "
- << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset)
- << " to CIE at " << formatv("{0:x16}", CIEAddress) << "\n";
- });
- auto &EI = CIEEdgeItr->second;
- if (EI.Addend)
- return make_error<JITLinkError>(
- "CIE edge at " +
- formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) +
- " has non-zero addend");
- if (auto CIEInfoOrErr = PC.findCIEInfo(EI.Target->getAddress()))
- CIEInfo = *CIEInfoOrErr;
- else
- return CIEInfoOrErr.takeError();
- }
- }
- {
- // Process the PC-Begin field.
- Block *PCBeginBlock = nullptr;
- orc::ExecutorAddrDiff PCBeginFieldOffset = RecordReader.getOffset();
- auto PCEdgeItr = BlockEdges.find(RecordOffset + PCBeginFieldOffset);
- if (PCEdgeItr == BlockEdges.end()) {
- auto PCBeginPtrInfo =
- readEncodedPointer(CIEInfo->FDEPointerEncoding,
- RecordAddress + PCBeginFieldOffset, RecordReader);
- if (!PCBeginPtrInfo)
- return PCBeginPtrInfo.takeError();
- orc::ExecutorAddr PCBegin = PCBeginPtrInfo->first;
- Edge::Kind PCBeginEdgeKind = PCBeginPtrInfo->second;
- LLVM_DEBUG({
- dbgs() << " Adding edge at "
- << (RecordAddress + PCBeginFieldOffset) << " to PC at "
- << formatv("{0:x16}", PCBegin) << "\n";
- });
- auto PCBeginSym = getOrCreateSymbol(PC, PCBegin);
- if (!PCBeginSym)
- return PCBeginSym.takeError();
- B.addEdge(PCBeginEdgeKind, RecordOffset + PCBeginFieldOffset, *PCBeginSym,
- 0);
- PCBeginBlock = &PCBeginSym->getBlock();
- } else {
- auto &EI = PCEdgeItr->second;
- LLVM_DEBUG({
- dbgs() << " Already has edge at "
- << formatv("{0:x16}", RecordAddress + PCBeginFieldOffset)
- << " to PC at " << formatv("{0:x16}", EI.Target->getAddress());
- if (EI.Addend)
- dbgs() << " + " << formatv("{0:x16}", EI.Addend);
- dbgs() << "\n";
- });
- // Make sure the existing edge points at a defined block.
- if (!EI.Target->isDefined()) {
- auto EdgeAddr = RecordAddress + PCBeginFieldOffset;
- return make_error<JITLinkError>("FDE edge at " +
- formatv("{0:x16}", EdgeAddr) +
- " points at external block");
- }
- PCBeginBlock = &EI.Target->getBlock();
- if (auto Err = RecordReader.skip(
- getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
- return Err;
- }
- // Add a keep-alive edge from the FDE target to the FDE to ensure that the
- // FDE is kept alive if its target is.
- assert(PCBeginBlock && "PC-begin block not recorded");
- LLVM_DEBUG({
- dbgs() << " Adding keep-alive edge from target at "
- << formatv("{0:x16}", PCBeginBlock->getAddress()) << " to FDE at "
- << formatv("{0:x16}", RecordAddress) << "\n";
- });
- PCBeginBlock->addEdge(Edge::KeepAlive, 0, FDESymbol, 0);
- }
- // Skip over the PC range size field.
- if (auto Err = RecordReader.skip(
- getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding)))
- return Err;
- if (CIEInfo->FDEsHaveLSDAField) {
- uint64_t AugmentationDataSize;
- if (auto Err = RecordReader.readULEB128(AugmentationDataSize))
- return Err;
- orc::ExecutorAddrDiff LSDAFieldOffset = RecordReader.getOffset();
- auto LSDAEdgeItr = BlockEdges.find(RecordOffset + LSDAFieldOffset);
- if (LSDAEdgeItr == BlockEdges.end()) {
- auto LSDAPointerInfo =
- readEncodedPointer(CIEInfo->LSDAPointerEncoding,
- RecordAddress + LSDAFieldOffset, RecordReader);
- if (!LSDAPointerInfo)
- return LSDAPointerInfo.takeError();
- orc::ExecutorAddr LSDA = LSDAPointerInfo->first;
- Edge::Kind LSDAEdgeKind = LSDAPointerInfo->second;
- auto LSDASym = getOrCreateSymbol(PC, LSDA);
- if (!LSDASym)
- return LSDASym.takeError();
- LLVM_DEBUG({
- dbgs() << " Adding edge at "
- << formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
- << " to LSDA at " << formatv("{0:x16}", LSDA) << "\n";
- });
- B.addEdge(LSDAEdgeKind, RecordOffset + LSDAFieldOffset, *LSDASym, 0);
- } else {
- LLVM_DEBUG({
- auto &EI = LSDAEdgeItr->second;
- dbgs() << " Already has edge at "
- << formatv("{0:x16}", RecordAddress + LSDAFieldOffset)
- << " to LSDA at " << formatv("{0:x16}", EI.Target->getAddress());
- if (EI.Addend)
- dbgs() << " + " << formatv("{0:x16}", EI.Addend);
- dbgs() << "\n";
- });
- if (auto Err = RecordReader.skip(AugmentationDataSize))
- return Err;
- }
- } else {
- LLVM_DEBUG(dbgs() << " Record does not have LSDA field.\n");
- }
- return Error::success();
- }
- Expected<EHFrameEdgeFixer::AugmentationInfo>
- EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) {
- AugmentationInfo AugInfo;
- uint8_t NextChar;
- uint8_t *NextField = &AugInfo.Fields[0];
- if (auto Err = RecordReader.readInteger(NextChar))
- return std::move(Err);
- while (NextChar != 0) {
- switch (NextChar) {
- case 'z':
- AugInfo.AugmentationDataPresent = true;
- break;
- case 'e':
- if (auto Err = RecordReader.readInteger(NextChar))
- return std::move(Err);
- if (NextChar != 'h')
- return make_error<JITLinkError>("Unrecognized substring e" +
- Twine(NextChar) +
- " in augmentation string");
- AugInfo.EHDataFieldPresent = true;
- break;
- case 'L':
- case 'P':
- case 'R':
- *NextField++ = NextChar;
- break;
- default:
- return make_error<JITLinkError>("Unrecognized character " +
- Twine(NextChar) +
- " in augmentation string");
- }
- if (auto Err = RecordReader.readInteger(NextChar))
- return std::move(Err);
- }
- return std::move(AugInfo);
- }
- bool EHFrameEdgeFixer::isSupportedPointerEncoding(uint8_t PointerEncoding) {
- using namespace dwarf;
- // We only support PC-rel for now.
- if ((PointerEncoding & 0x70) != DW_EH_PE_pcrel)
- return false;
- // readEncodedPointer does not handle indirect.
- if (PointerEncoding & DW_EH_PE_indirect)
- return false;
- // Supported datatypes.
- switch (PointerEncoding & 0xf) {
- case DW_EH_PE_absptr:
- case DW_EH_PE_udata4:
- case DW_EH_PE_udata8:
- case DW_EH_PE_sdata4:
- case DW_EH_PE_sdata8:
- return true;
- }
- return false;
- }
- unsigned EHFrameEdgeFixer::getPointerEncodingDataSize(uint8_t PointerEncoding) {
- using namespace dwarf;
- assert(isSupportedPointerEncoding(PointerEncoding) &&
- "Unsupported pointer encoding");
- switch (PointerEncoding & 0xf) {
- case DW_EH_PE_absptr:
- return PointerSize;
- case DW_EH_PE_udata4:
- case DW_EH_PE_sdata4:
- return 4;
- case DW_EH_PE_udata8:
- case DW_EH_PE_sdata8:
- return 8;
- default:
- llvm_unreachable("Unsupported encoding");
- }
- }
- Expected<std::pair<orc::ExecutorAddr, Edge::Kind>>
- EHFrameEdgeFixer::readEncodedPointer(uint8_t PointerEncoding,
- orc::ExecutorAddr PointerFieldAddress,
- BinaryStreamReader &RecordReader) {
- assert(isSupportedPointerEncoding(PointerEncoding) &&
- "Unsupported pointer encoding");
- using namespace dwarf;
- // Isolate data type, remap absptr to udata4 or udata8. This relies on us
- // having verified that the graph uses 32-bit or 64-bit pointers only at the
- // start of this pass.
- uint8_t EffectiveType = PointerEncoding & 0xf;
- if (EffectiveType == DW_EH_PE_absptr)
- EffectiveType = (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4;
- orc::ExecutorAddr Addr;
- Edge::Kind PointerEdgeKind = Edge::Invalid;
- switch (EffectiveType) {
- case DW_EH_PE_udata4: {
- uint32_t Val;
- if (auto Err = RecordReader.readInteger(Val))
- return std::move(Err);
- Addr = PointerFieldAddress + Val;
- PointerEdgeKind = Delta32;
- break;
- }
- case DW_EH_PE_udata8: {
- uint64_t Val;
- if (auto Err = RecordReader.readInteger(Val))
- return std::move(Err);
- Addr = PointerFieldAddress + Val;
- PointerEdgeKind = Delta64;
- break;
- }
- case DW_EH_PE_sdata4: {
- int32_t Val;
- if (auto Err = RecordReader.readInteger(Val))
- return std::move(Err);
- Addr = PointerFieldAddress + Val;
- PointerEdgeKind = Delta32;
- break;
- }
- case DW_EH_PE_sdata8: {
- int64_t Val;
- if (auto Err = RecordReader.readInteger(Val))
- return std::move(Err);
- Addr = PointerFieldAddress + Val;
- PointerEdgeKind = Delta64;
- break;
- }
- }
- if (PointerEdgeKind == Edge::Invalid)
- return make_error<JITLinkError>(
- "Unspported edge kind for encoded pointer at " +
- formatv("{0:x}", PointerFieldAddress));
- return std::make_pair(Addr, Delta64);
- }
- Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
- orc::ExecutorAddr Addr) {
- Symbol *CanonicalSym = nullptr;
- auto UpdateCanonicalSym = [&](Symbol *Sym) {
- if (!CanonicalSym || Sym->getLinkage() < CanonicalSym->getLinkage() ||
- Sym->getScope() < CanonicalSym->getScope() ||
- (Sym->hasName() && !CanonicalSym->hasName()) ||
- Sym->getName() < CanonicalSym->getName())
- CanonicalSym = Sym;
- };
- if (auto *SymbolsAtAddr = PC.AddrToSyms.getSymbolsAt(Addr))
- for (auto *Sym : *SymbolsAtAddr)
- UpdateCanonicalSym(Sym);
- // If we found an existing symbol at the given address then use it.
- if (CanonicalSym)
- return *CanonicalSym;
- // Otherwise search for a block covering the address and create a new symbol.
- auto *B = PC.AddrToBlock.getBlockCovering(Addr);
- if (!B)
- return make_error<JITLinkError>("No symbol or block covering address " +
- formatv("{0:x16}", Addr));
- return PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
- }
- char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0};
- EHFrameNullTerminator::EHFrameNullTerminator(StringRef EHFrameSectionName)
- : EHFrameSectionName(EHFrameSectionName) {}
- Error EHFrameNullTerminator::operator()(LinkGraph &G) {
- auto *EHFrame = G.findSectionByName(EHFrameSectionName);
- if (!EHFrame)
- return Error::success();
- LLVM_DEBUG({
- dbgs() << "EHFrameNullTerminator adding null terminator to "
- << EHFrameSectionName << "\n";
- });
- auto &NullTerminatorBlock =
- G.createContentBlock(*EHFrame, NullTerminatorBlockContent,
- orc::ExecutorAddr(~uint64_t(4)), 1, 0);
- G.addAnonymousSymbol(NullTerminatorBlock, 0, 4, false, true);
- return Error::success();
- }
- EHFrameRegistrar::~EHFrameRegistrar() {}
- Error InProcessEHFrameRegistrar::registerEHFrames(
- orc::ExecutorAddrRange EHFrameSection) {
- return orc::registerEHFrameSection(EHFrameSection.Start.toPtr<void *>(),
- EHFrameSection.size());
- }
- Error InProcessEHFrameRegistrar::deregisterEHFrames(
- orc::ExecutorAddrRange EHFrameSection) {
- return orc::deregisterEHFrameSection(EHFrameSection.Start.toPtr<void *>(),
- EHFrameSection.size());
- }
- LinkGraphPassFunction
- createEHFrameRecorderPass(const Triple &TT,
- StoreFrameRangeFunction StoreRangeAddress) {
- const char *EHFrameSectionName = nullptr;
- if (TT.getObjectFormat() == Triple::MachO)
- EHFrameSectionName = "__TEXT,__eh_frame";
- else
- EHFrameSectionName = ".eh_frame";
- auto RecordEHFrame =
- [EHFrameSectionName,
- StoreFrameRange = std::move(StoreRangeAddress)](LinkGraph &G) -> Error {
- // Search for a non-empty eh-frame and record the address of the first
- // symbol in it.
- orc::ExecutorAddr Addr;
- size_t Size = 0;
- if (auto *S = G.findSectionByName(EHFrameSectionName)) {
- auto R = SectionRange(*S);
- Addr = R.getStart();
- Size = R.getSize();
- }
- if (!Addr && Size != 0)
- return make_error<JITLinkError>(
- StringRef(EHFrameSectionName) +
- " section can not have zero address with non-zero size");
- StoreFrameRange(Addr, Size);
- return Error::success();
- };
- return RecordEHFrame;
- }
- } // end namespace jitlink
- } // end namespace llvm
|