forked from OSchip/llvm-project
[JITLink][ORC] Track eh-frame section size for registration/deregistration.
On MachO, processing of the eh-frame section should stop if the end of the __eh_frame section is reached, regardless of whether or not there is a null CFI length field at the end of the section. This patch tracks the eh-frame section size and threads it through the appropriate APIs so that processing can be terminated correctly. No testcase yet: This patch is all API plumbing (rather than modification of linked memory) which the existing infrastructure does not provide a way of testing. Committing without a testcase until I have an idea of how to write one. llvm-svn: 370074
This commit is contained in:
parent
f260630e8f
commit
c48f1f6da6
|
@ -22,17 +22,21 @@ namespace llvm {
|
|||
namespace jitlink {
|
||||
|
||||
/// Registers all FDEs in the given eh-frame section with the current process.
|
||||
Error registerEHFrameSection(const void *EHFrameSectionAddr);
|
||||
Error registerEHFrameSection(const void *EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize);
|
||||
|
||||
/// Deregisters all FDEs in the given eh-frame section with the current process.
|
||||
Error deregisterEHFrameSection(const void *EHFrameSectionAddr);
|
||||
Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize);
|
||||
|
||||
/// Supports registration/deregistration of EH-frames in a target process.
|
||||
class EHFrameRegistrar {
|
||||
public:
|
||||
virtual ~EHFrameRegistrar();
|
||||
virtual Error registerEHFrames(JITTargetAddress EHFrameSectionAddr) = 0;
|
||||
virtual Error deregisterEHFrames(JITTargetAddress EHFrameSectionAddr) = 0;
|
||||
virtual Error registerEHFrames(JITTargetAddress EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) = 0;
|
||||
virtual Error deregisterEHFrames(JITTargetAddress EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) = 0;
|
||||
};
|
||||
|
||||
/// Registers / Deregisters EH-frames in the current process.
|
||||
|
@ -48,31 +52,38 @@ public:
|
|||
InProcessEHFrameRegistrar(InProcessEHFrameRegistrar &&) = delete;
|
||||
InProcessEHFrameRegistrar &operator=(InProcessEHFrameRegistrar &&) = delete;
|
||||
|
||||
Error registerEHFrames(JITTargetAddress EHFrameSectionAddr) override {
|
||||
Error registerEHFrames(JITTargetAddress EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) override {
|
||||
return registerEHFrameSection(
|
||||
jitTargetAddressToPointer<void *>(EHFrameSectionAddr));
|
||||
jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
|
||||
EHFrameSectionSize);
|
||||
}
|
||||
|
||||
Error deregisterEHFrames(JITTargetAddress EHFrameSectionAddr) override {
|
||||
Error deregisterEHFrames(JITTargetAddress EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) override {
|
||||
return deregisterEHFrameSection(
|
||||
jitTargetAddressToPointer<void *>(EHFrameSectionAddr));
|
||||
jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
|
||||
EHFrameSectionSize);
|
||||
}
|
||||
|
||||
private:
|
||||
InProcessEHFrameRegistrar();
|
||||
};
|
||||
|
||||
using StoreFrameAddressFunction = std::function<void(JITTargetAddress)>;
|
||||
using StoreFrameRangeFunction =
|
||||
std::function<void(JITTargetAddress EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize)>;
|
||||
|
||||
/// Creates a pass that records the address of the EH frame section. If no
|
||||
/// eh-frame section is found, it will set EHFrameAddr to zero.
|
||||
/// Creates a pass that records the address and size of the EH frame section.
|
||||
/// If no eh-frame section is found then the address and size will both be given
|
||||
/// as zero.
|
||||
///
|
||||
/// Authors of JITLinkContexts can use this function to register a post-fixup
|
||||
/// pass that records the address of the eh-frame section. This address can
|
||||
/// pass that records the range of the eh-frame section. This range can
|
||||
/// be used after finalization to register and deregister the frame.
|
||||
AtomGraphPassFunction
|
||||
createEHFrameRecorderPass(const Triple &TT,
|
||||
StoreFrameAddressFunction StoreFrameAddress);
|
||||
StoreFrameRangeFunction StoreFrameRange);
|
||||
|
||||
} // end namespace jitlink
|
||||
} // end namespace llvm
|
||||
|
|
|
@ -153,10 +153,16 @@ public:
|
|||
Error notifyRemovingAllModules() override;
|
||||
|
||||
private:
|
||||
|
||||
struct EHFrameRange {
|
||||
JITTargetAddress Addr = 0;
|
||||
size_t Size;
|
||||
};
|
||||
|
||||
jitlink::EHFrameRegistrar &Registrar;
|
||||
DenseMap<MaterializationResponsibility *, JITTargetAddress> InProcessLinks;
|
||||
DenseMap<VModuleKey, JITTargetAddress> TrackedEHFrameAddrs;
|
||||
std::vector<JITTargetAddress> UntrackedEHFrameAddrs;
|
||||
DenseMap<MaterializationResponsibility *, EHFrameRange> InProcessLinks;
|
||||
DenseMap<VModuleKey, EHFrameRange> TrackedEHFrameRanges;
|
||||
std::vector<EHFrameRange> UntrackedEHFrameRanges;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
|
|
|
@ -451,11 +451,13 @@ static Error deregisterFrameWrapper(const void *P) {
|
|||
|
||||
template <typename HandleFDEFn>
|
||||
Error walkAppleEHFrameSection(const char *const SectionStart,
|
||||
size_t SectionSize,
|
||||
HandleFDEFn HandleFDE) {
|
||||
const char *CurCFIRecord = SectionStart;
|
||||
const char *End = SectionStart + SectionSize;
|
||||
uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
|
||||
|
||||
while (Size != 0) {
|
||||
while (CurCFIRecord != End && Size != 0) {
|
||||
const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
|
||||
if (Size == 0xffffffff)
|
||||
Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
|
||||
|
@ -484,10 +486,12 @@ Error walkAppleEHFrameSection(const char *const SectionStart,
|
|||
|
||||
#endif // __APPLE__
|
||||
|
||||
Error registerEHFrameSection(const void *EHFrameSectionAddr) {
|
||||
Error registerEHFrameSection(const void *EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) {
|
||||
#ifdef __APPLE__
|
||||
// On Darwin __register_frame has to be called for each FDE entry.
|
||||
return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
|
||||
EHFrameSectionSize,
|
||||
registerFrameWrapper);
|
||||
#else
|
||||
// On Linux __register_frame takes a single argument:
|
||||
|
@ -499,9 +503,11 @@ Error registerEHFrameSection(const void *EHFrameSectionAddr) {
|
|||
#endif
|
||||
}
|
||||
|
||||
Error deregisterEHFrameSection(const void *EHFrameSectionAddr) {
|
||||
Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) {
|
||||
#ifdef __APPLE__
|
||||
return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
|
||||
EHFrameSectionSize,
|
||||
deregisterFrameWrapper);
|
||||
#else
|
||||
return deregisterFrameWrapper(EHFrameSectionAddr);
|
||||
|
@ -519,21 +525,29 @@ InProcessEHFrameRegistrar::InProcessEHFrameRegistrar() {}
|
|||
|
||||
AtomGraphPassFunction
|
||||
createEHFrameRecorderPass(const Triple &TT,
|
||||
StoreFrameAddressFunction StoreFrameAddress) {
|
||||
StoreFrameRangeFunction StoreRangeAddress) {
|
||||
const char *EHFrameSectionName = nullptr;
|
||||
if (TT.getObjectFormat() == Triple::MachO)
|
||||
EHFrameSectionName = "__eh_frame";
|
||||
else
|
||||
EHFrameSectionName = ".eh_frame";
|
||||
|
||||
auto RecordEHFrame = [EHFrameSectionName,
|
||||
StoreFrameAddress](AtomGraph &G) -> Error {
|
||||
auto RecordEHFrame =
|
||||
[EHFrameSectionName,
|
||||
StoreFrameRange = std::move(StoreRangeAddress)](AtomGraph &G) -> Error {
|
||||
// Search for a non-empty eh-frame and record the address of the first atom
|
||||
// in it.
|
||||
JITTargetAddress Addr = 0;
|
||||
if (auto *S = G.findSectionByName(EHFrameSectionName))
|
||||
Addr = S->getRange().getStart();
|
||||
StoreFrameAddress(Addr);
|
||||
size_t Size = 0;
|
||||
if (auto *S = G.findSectionByName(EHFrameSectionName)) {
|
||||
auto R = S->getRange();
|
||||
Addr = R.getStart();
|
||||
Size = R.getSize();
|
||||
}
|
||||
if (Addr == 0 && Size != 0)
|
||||
return make_error<JITLinkError>("__eh_frame section can not have zero "
|
||||
"address with non-zero size");
|
||||
StoreFrameRange(Addr, Size);
|
||||
return Error::success();
|
||||
};
|
||||
|
||||
|
|
|
@ -58,7 +58,8 @@ public:
|
|||
auto SharedLookupContinuation =
|
||||
std::make_shared<JITLinkAsyncLookupContinuation>(
|
||||
std::move(LookupContinuation));
|
||||
auto OnResolve = [SharedLookupContinuation](Expected<SymbolMap> Result) {
|
||||
auto OnResolve = [this, SharedLookupContinuation](Expected<SymbolMap> Result) {
|
||||
auto Main = Layer.getExecutionSession().intern("_main");
|
||||
if (!Result)
|
||||
(*SharedLookupContinuation)(Result.takeError());
|
||||
else {
|
||||
|
@ -126,19 +127,16 @@ public:
|
|||
if (!ExtraSymbolsToClaim.empty())
|
||||
if (auto Err = MR.defineMaterializing(ExtraSymbolsToClaim))
|
||||
return notifyFailed(std::move(Err));
|
||||
|
||||
if (auto Err = MR.notifyResolved(InternedResult)) {
|
||||
Layer.getExecutionSession().reportError(std::move(Err));
|
||||
MR.failMaterialization();
|
||||
return;
|
||||
}
|
||||
|
||||
Layer.notifyLoaded(MR);
|
||||
}
|
||||
|
||||
void notifyFinalized(
|
||||
std::unique_ptr<JITLinkMemoryManager::Allocation> A) override {
|
||||
|
||||
if (auto Err = Layer.notifyEmitted(MR, std::move(A))) {
|
||||
Layer.getExecutionSession().reportError(std::move(Err));
|
||||
MR.failMaterialization();
|
||||
|
@ -425,61 +423,66 @@ void EHFrameRegistrationPlugin::modifyPassConfig(
|
|||
assert(!InProcessLinks.count(&MR) && "Link for MR already being tracked?");
|
||||
|
||||
PassConfig.PostFixupPasses.push_back(
|
||||
createEHFrameRecorderPass(TT, [this, &MR](JITTargetAddress Addr) {
|
||||
createEHFrameRecorderPass(TT, [this, &MR](JITTargetAddress Addr,
|
||||
size_t Size) {
|
||||
if (Addr)
|
||||
InProcessLinks[&MR] = Addr;
|
||||
InProcessLinks[&MR] = { Addr, Size };
|
||||
}));
|
||||
}
|
||||
|
||||
Error EHFrameRegistrationPlugin::notifyEmitted(
|
||||
MaterializationResponsibility &MR) {
|
||||
|
||||
auto EHFrameAddrItr = InProcessLinks.find(&MR);
|
||||
if (EHFrameAddrItr == InProcessLinks.end())
|
||||
auto EHFrameRangeItr = InProcessLinks.find(&MR);
|
||||
if (EHFrameRangeItr == InProcessLinks.end())
|
||||
return Error::success();
|
||||
|
||||
auto EHFrameAddr = EHFrameAddrItr->second;
|
||||
assert(EHFrameAddr && "eh-frame addr to register can not be null");
|
||||
auto EHFrameRange = EHFrameRangeItr->second;
|
||||
assert(EHFrameRange.Addr &&
|
||||
"eh-frame addr to register can not be null");
|
||||
|
||||
InProcessLinks.erase(EHFrameAddrItr);
|
||||
InProcessLinks.erase(EHFrameRangeItr);
|
||||
if (auto Key = MR.getVModuleKey())
|
||||
TrackedEHFrameAddrs[Key] = EHFrameAddr;
|
||||
TrackedEHFrameRanges[Key] = EHFrameRange;
|
||||
else
|
||||
UntrackedEHFrameAddrs.push_back(EHFrameAddr);
|
||||
UntrackedEHFrameRanges.push_back(EHFrameRange);
|
||||
|
||||
return Registrar.registerEHFrames(EHFrameAddr);
|
||||
return Registrar.registerEHFrames(EHFrameRange.Addr, EHFrameRange.Size);
|
||||
}
|
||||
|
||||
Error EHFrameRegistrationPlugin::notifyRemovingModule(VModuleKey K) {
|
||||
auto EHFrameAddrItr = TrackedEHFrameAddrs.find(K);
|
||||
if (EHFrameAddrItr == TrackedEHFrameAddrs.end())
|
||||
auto EHFrameRangeItr = TrackedEHFrameRanges.find(K);
|
||||
if (EHFrameRangeItr == TrackedEHFrameRanges.end())
|
||||
return Error::success();
|
||||
|
||||
auto EHFrameAddr = EHFrameAddrItr->second;
|
||||
assert(EHFrameAddr && "Tracked eh-frame addr must not be null");
|
||||
auto EHFrameRange = EHFrameRangeItr->second;
|
||||
assert(EHFrameRange.Addr && "Tracked eh-frame range must not be null");
|
||||
|
||||
TrackedEHFrameAddrs.erase(EHFrameAddrItr);
|
||||
TrackedEHFrameRanges.erase(EHFrameRangeItr);
|
||||
|
||||
return Registrar.deregisterEHFrames(EHFrameAddr);
|
||||
return Registrar.deregisterEHFrames(EHFrameRange.Addr, EHFrameRange.Size);
|
||||
}
|
||||
|
||||
Error EHFrameRegistrationPlugin::notifyRemovingAllModules() {
|
||||
|
||||
std::vector<JITTargetAddress> EHFrameAddrs = std::move(UntrackedEHFrameAddrs);
|
||||
EHFrameAddrs.reserve(EHFrameAddrs.size() + TrackedEHFrameAddrs.size());
|
||||
std::vector<EHFrameRange> EHFrameRanges =
|
||||
std::move(UntrackedEHFrameRanges);
|
||||
EHFrameRanges.reserve(EHFrameRanges.size() + TrackedEHFrameRanges.size());
|
||||
|
||||
for (auto &KV : TrackedEHFrameAddrs)
|
||||
EHFrameAddrs.push_back(KV.second);
|
||||
for (auto &KV : TrackedEHFrameRanges)
|
||||
EHFrameRanges.push_back(KV.second);
|
||||
|
||||
TrackedEHFrameAddrs.clear();
|
||||
TrackedEHFrameRanges.clear();
|
||||
|
||||
Error Err = Error::success();
|
||||
|
||||
while (!EHFrameAddrs.empty()) {
|
||||
auto EHFrameAddr = EHFrameAddrs.back();
|
||||
assert(EHFrameAddr && "Untracked eh-frame addr must not be null");
|
||||
EHFrameAddrs.pop_back();
|
||||
Err = joinErrors(std::move(Err), Registrar.deregisterEHFrames(EHFrameAddr));
|
||||
while (!EHFrameRanges.empty()) {
|
||||
auto EHFrameRange = EHFrameRanges.back();
|
||||
assert(EHFrameRange.Addr && "Untracked eh-frame range must not be null");
|
||||
EHFrameRanges.pop_back();
|
||||
Err = joinErrors(std::move(Err),
|
||||
Registrar.deregisterEHFrames(EHFrameRange.Addr,
|
||||
EHFrameRange.Size));
|
||||
}
|
||||
|
||||
return Err;
|
||||
|
|
Loading…
Reference in New Issue