forked from OSchip/llvm-project
[ORC] Flesh out ExecutorAddress, rename CommonOrcRuntimeTypes header.
Renames CommonOrcRuntimeTypes.h to ExecutorAddress.h and moves ExecutorAddress into the 'orc' namespace (rather than orc::shared). Also makes ExecutorAddress a class, adds an ExecutorAddrDiff type and some arithmetic operations on the pair (subtracting two addresses yields an addrdiff, adding an addrdiff and an address yields an address).
This commit is contained in:
parent
3822e3d5b0
commit
b8e5f91816
|
@ -17,7 +17,7 @@
|
|||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/CommonOrcRuntimeTypes.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
|
||||
|
||||
#include <future>
|
||||
#include <thread>
|
||||
|
@ -32,13 +32,13 @@ bool objCRegistrationEnabled();
|
|||
|
||||
class MachOJITDylibInitializers {
|
||||
public:
|
||||
using RawPointerSectionList = std::vector<shared::ExecutorAddressRange>;
|
||||
using RawPointerSectionList = std::vector<ExecutorAddressRange>;
|
||||
|
||||
void setObjCImageInfoAddr(JITTargetAddress ObjCImageInfoAddr) {
|
||||
this->ObjCImageInfoAddr = ObjCImageInfoAddr;
|
||||
}
|
||||
|
||||
void addModInitsSection(shared::ExecutorAddressRange ModInit) {
|
||||
void addModInitsSection(ExecutorAddressRange ModInit) {
|
||||
ModInitSections.push_back(std::move(ModInit));
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ public:
|
|||
return ModInitSections;
|
||||
}
|
||||
|
||||
void addObjCSelRefsSection(shared::ExecutorAddressRange ObjCSelRefs) {
|
||||
void addObjCSelRefsSection(ExecutorAddressRange ObjCSelRefs) {
|
||||
ObjCSelRefsSections.push_back(std::move(ObjCSelRefs));
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ public:
|
|||
return ObjCSelRefsSections;
|
||||
}
|
||||
|
||||
void addObjCClassListSection(shared::ExecutorAddressRange ObjCClassList) {
|
||||
void addObjCClassListSection(ExecutorAddressRange ObjCClassList) {
|
||||
ObjCClassListSections.push_back(std::move(ObjCClassList));
|
||||
}
|
||||
|
||||
|
@ -145,9 +145,9 @@ private:
|
|||
};
|
||||
|
||||
void registerInitInfo(JITDylib &JD, JITTargetAddress ObjCImageInfoAddr,
|
||||
shared::ExecutorAddressRange ModInits,
|
||||
shared::ExecutorAddressRange ObjCSelRefs,
|
||||
shared::ExecutorAddressRange ObjCClassList);
|
||||
ExecutorAddressRange ModInits,
|
||||
ExecutorAddressRange ObjCSelRefs,
|
||||
ExecutorAddressRange ObjCClassList);
|
||||
|
||||
ExecutionSession &ES;
|
||||
ObjectLinkingLayer &ObjLinkingLayer;
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
//===------------------- CommonOrcRuntimeTypes.h ----------------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Generic types usable with SPS and the ORC runtime.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_COMMONORCRUNTIMETYPES_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_SHARED_COMMONORCRUNTIMETYPES_H
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace shared {
|
||||
|
||||
// Placeholder for future replacement for JITTargetAddress.
|
||||
using ExecutorAddress = uint64_t;
|
||||
|
||||
/// Represents an address range in the exceutor process.
|
||||
struct ExecutorAddressRange {
|
||||
ExecutorAddressRange() = default;
|
||||
ExecutorAddressRange(ExecutorAddress StartAddress, ExecutorAddress EndAddress)
|
||||
: StartAddress(StartAddress), EndAddress(EndAddress) {}
|
||||
|
||||
bool empty() const { return StartAddress == EndAddress; }
|
||||
size_t size() const { return EndAddress - StartAddress; }
|
||||
|
||||
ExecutorAddress StartAddress = 0;
|
||||
ExecutorAddress EndAddress = 0;
|
||||
};
|
||||
|
||||
using SPSExecutorAddressRange =
|
||||
SPSTuple<SPSExecutorAddress, SPSExecutorAddress>;
|
||||
|
||||
/// Serialization traits for address ranges.
|
||||
template <>
|
||||
class SPSSerializationTraits<SPSExecutorAddressRange, ExecutorAddressRange> {
|
||||
public:
|
||||
static size_t size(const ExecutorAddressRange &Value) {
|
||||
return SPSArgList<SPSExecutorAddress, SPSExecutorAddress>::size(
|
||||
Value.StartAddress, Value.EndAddress);
|
||||
}
|
||||
|
||||
static bool serialize(SPSOutputBuffer &BOB,
|
||||
const ExecutorAddressRange &Value) {
|
||||
return SPSArgList<SPSExecutorAddress, SPSExecutorAddress>::serialize(
|
||||
BOB, Value.StartAddress, Value.EndAddress);
|
||||
}
|
||||
|
||||
static bool deserialize(SPSInputBuffer &BIB, ExecutorAddressRange &Value) {
|
||||
return SPSArgList<SPSExecutorAddress, SPSExecutorAddress>::deserialize(
|
||||
BIB, Value.StartAddress, Value.EndAddress);
|
||||
}
|
||||
};
|
||||
|
||||
using SPSExecutorAddressRangeSequence = SPSSequence<SPSExecutorAddressRange>;
|
||||
|
||||
} // End namespace shared.
|
||||
} // End namespace orc.
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_COMMONORCRUNTIMETYPES_H
|
|
@ -0,0 +1,203 @@
|
|||
//===------ ExecutorAddress.h - Executing process address -------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Represents an address in the executing program.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_EXECUTORADDRESS_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_SHARED_EXECUTORADDRESS_H
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// Represents the difference between two addresses in the executor process.
|
||||
class ExecutorAddrDiff {
|
||||
public:
|
||||
ExecutorAddrDiff() = default;
|
||||
explicit ExecutorAddrDiff(uint64_t Value) : Value(Value) {}
|
||||
|
||||
uint64_t getValue() const { return Value; }
|
||||
|
||||
private:
|
||||
int64_t Value = 0;
|
||||
};
|
||||
|
||||
/// Represents an address in the executor process.
|
||||
class ExecutorAddress {
|
||||
public:
|
||||
ExecutorAddress() = default;
|
||||
explicit ExecutorAddress(uint64_t Addr) : Addr(Addr) {}
|
||||
|
||||
/// Create an ExecutorAddress from the given pointer.
|
||||
/// Warning: This should only be used when JITing in-process.
|
||||
template <typename T> static ExecutorAddress fromPtr(T *Value) {
|
||||
return ExecutorAddress(
|
||||
static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Value)));
|
||||
}
|
||||
|
||||
/// Cast this ExecutorAddress to a pointer of the given type.
|
||||
/// Warning: This should only be esude when JITing in-process.
|
||||
template <typename T> T toPtr() const {
|
||||
static_assert(std::is_pointer<T>::value, "T must be a pointer type");
|
||||
uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
|
||||
assert(IntPtr == Addr &&
|
||||
"JITTargetAddress value out of range for uintptr_t");
|
||||
return reinterpret_cast<T>(IntPtr);
|
||||
}
|
||||
|
||||
uint64_t getValue() const { return Addr; }
|
||||
void setValue(uint64_t Addr) { this->Addr = Addr; }
|
||||
bool isNull() const { return Addr == 0; }
|
||||
|
||||
explicit operator bool() const { return Addr != 0; }
|
||||
|
||||
friend bool operator==(const ExecutorAddress &LHS,
|
||||
const ExecutorAddress &RHS) {
|
||||
return LHS.Addr == RHS.Addr;
|
||||
}
|
||||
|
||||
friend bool operator!=(const ExecutorAddress &LHS,
|
||||
const ExecutorAddress &RHS) {
|
||||
return LHS.Addr != RHS.Addr;
|
||||
}
|
||||
|
||||
friend bool operator<(const ExecutorAddress &LHS,
|
||||
const ExecutorAddress &RHS) {
|
||||
return LHS.Addr < RHS.Addr;
|
||||
}
|
||||
|
||||
friend bool operator<=(const ExecutorAddress &LHS,
|
||||
const ExecutorAddress &RHS) {
|
||||
return LHS.Addr <= RHS.Addr;
|
||||
}
|
||||
|
||||
friend bool operator>(const ExecutorAddress &LHS,
|
||||
const ExecutorAddress &RHS) {
|
||||
return LHS.Addr > RHS.Addr;
|
||||
}
|
||||
|
||||
friend bool operator>=(const ExecutorAddress &LHS,
|
||||
const ExecutorAddress &RHS) {
|
||||
return LHS.Addr >= RHS.Addr;
|
||||
}
|
||||
|
||||
ExecutorAddress &operator++() {
|
||||
++Addr;
|
||||
return *this;
|
||||
}
|
||||
ExecutorAddress &operator--() {
|
||||
--Addr;
|
||||
return *this;
|
||||
}
|
||||
ExecutorAddress operator++(int) { return ExecutorAddress(Addr++); }
|
||||
ExecutorAddress operator--(int) { return ExecutorAddress(Addr++); }
|
||||
|
||||
ExecutorAddress &operator+=(const ExecutorAddrDiff Delta) {
|
||||
Addr += Delta.getValue();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ExecutorAddress &operator-=(const ExecutorAddrDiff Delta) {
|
||||
Addr -= Delta.getValue();
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t Addr = 0;
|
||||
};
|
||||
|
||||
/// Subtracting two addresses yields an offset.
|
||||
inline ExecutorAddrDiff operator-(const ExecutorAddress &LHS,
|
||||
const ExecutorAddress &RHS) {
|
||||
return ExecutorAddrDiff(LHS.getValue() - RHS.getValue());
|
||||
}
|
||||
|
||||
/// Adding an offset and an address yields an address.
|
||||
inline ExecutorAddress operator+(const ExecutorAddress &LHS,
|
||||
const ExecutorAddrDiff &RHS) {
|
||||
return ExecutorAddress(LHS.getValue() + RHS.getValue());
|
||||
}
|
||||
|
||||
/// Adding an address and an offset yields an address.
|
||||
inline ExecutorAddress operator+(const ExecutorAddrDiff &LHS,
|
||||
const ExecutorAddress &RHS) {
|
||||
return ExecutorAddress(LHS.getValue() + RHS.getValue());
|
||||
}
|
||||
|
||||
/// Represents an address range in the exceutor process.
|
||||
struct ExecutorAddressRange {
|
||||
ExecutorAddressRange() = default;
|
||||
ExecutorAddressRange(ExecutorAddress StartAddress, ExecutorAddress EndAddress)
|
||||
: StartAddress(StartAddress), EndAddress(EndAddress) {}
|
||||
|
||||
bool empty() const { return StartAddress == EndAddress; }
|
||||
ExecutorAddrDiff size() const { return EndAddress - StartAddress; }
|
||||
|
||||
ExecutorAddress StartAddress;
|
||||
ExecutorAddress EndAddress;
|
||||
};
|
||||
|
||||
namespace shared {
|
||||
|
||||
/// SPS serializatior for ExecutorAddress.
|
||||
template <> class SPSSerializationTraits<SPSExecutorAddress, ExecutorAddress> {
|
||||
public:
|
||||
static size_t size(const ExecutorAddress &EA) {
|
||||
return SPSArgList<uint64_t>::size(EA.getValue());
|
||||
}
|
||||
|
||||
static bool serialize(SPSOutputBuffer &BOB, const ExecutorAddress &EA) {
|
||||
return SPSArgList<uint64_t>::serialize(BOB, EA.getValue());
|
||||
}
|
||||
|
||||
static bool deserialize(SPSInputBuffer &BIB, ExecutorAddress &EA) {
|
||||
uint64_t Tmp;
|
||||
if (!SPSArgList<uint64_t>::deserialize(BIB, Tmp))
|
||||
return false;
|
||||
EA = ExecutorAddress(Tmp);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
using SPSExecutorAddressRange =
|
||||
SPSTuple<SPSExecutorAddress, SPSExecutorAddress>;
|
||||
|
||||
/// Serialization traits for address ranges.
|
||||
template <>
|
||||
class SPSSerializationTraits<SPSExecutorAddressRange, ExecutorAddressRange> {
|
||||
public:
|
||||
static size_t size(const ExecutorAddressRange &Value) {
|
||||
return SPSArgList<SPSExecutorAddress, SPSExecutorAddress>::size(
|
||||
Value.StartAddress, Value.EndAddress);
|
||||
}
|
||||
|
||||
static bool serialize(SPSOutputBuffer &BOB,
|
||||
const ExecutorAddressRange &Value) {
|
||||
return SPSArgList<SPSExecutorAddress, SPSExecutorAddress>::serialize(
|
||||
BOB, Value.StartAddress, Value.EndAddress);
|
||||
}
|
||||
|
||||
static bool deserialize(SPSInputBuffer &BIB, ExecutorAddressRange &Value) {
|
||||
return SPSArgList<SPSExecutorAddress, SPSExecutorAddress>::deserialize(
|
||||
BIB, Value.StartAddress, Value.EndAddress);
|
||||
}
|
||||
};
|
||||
|
||||
using SPSExecutorAddressRangeSequence = SPSSequence<SPSExecutorAddressRange>;
|
||||
|
||||
} // End namespace shared.
|
||||
} // End namespace orc.
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_EXECUTORADDRESS_H
|
|
@ -88,13 +88,12 @@ bool objCRegistrationEnabled() {
|
|||
|
||||
void MachOJITDylibInitializers::runModInits() const {
|
||||
for (const auto &ModInit : ModInitSections) {
|
||||
assert(ModInit.size() % sizeof(uintptr_t) == 0 &&
|
||||
assert(ModInit.size().getValue() % sizeof(uintptr_t) == 0 &&
|
||||
"ModInit section size is not a pointer multiple?");
|
||||
for (uintptr_t *
|
||||
InitPtr =
|
||||
jitTargetAddressToPointer<uintptr_t *>(ModInit.StartAddress),
|
||||
*InitEnd =
|
||||
jitTargetAddressToPointer<uintptr_t *>(ModInit.EndAddress);
|
||||
for (uintptr_t *InitPtr = jitTargetAddressToPointer<uintptr_t *>(
|
||||
ModInit.StartAddress.getValue()),
|
||||
*InitEnd = jitTargetAddressToPointer<uintptr_t *>(
|
||||
ModInit.EndAddress.getValue());
|
||||
InitPtr != InitEnd; ++InitPtr) {
|
||||
auto *Initializer = reinterpret_cast<void (*)()>(*InitPtr);
|
||||
Initializer();
|
||||
|
@ -106,15 +105,15 @@ void MachOJITDylibInitializers::registerObjCSelectors() const {
|
|||
assert(objCRegistrationEnabled() && "ObjC registration not enabled.");
|
||||
|
||||
for (const auto &ObjCSelRefs : ObjCSelRefsSections) {
|
||||
assert(ObjCSelRefs.size() % sizeof(uintptr_t) == 0 &&
|
||||
assert(ObjCSelRefs.size().getValue() % sizeof(uintptr_t) == 0 &&
|
||||
"ObjCSelRefs section size is not a pointer multiple?");
|
||||
for (JITTargetAddress SelEntryAddr = ObjCSelRefs.StartAddress;
|
||||
for (auto SelEntryAddr = ObjCSelRefs.StartAddress;
|
||||
SelEntryAddr != ObjCSelRefs.EndAddress;
|
||||
SelEntryAddr += sizeof(uintptr_t)) {
|
||||
SelEntryAddr += ExecutorAddrDiff(sizeof(uintptr_t))) {
|
||||
const auto *SelName =
|
||||
*jitTargetAddressToPointer<const char **>(SelEntryAddr);
|
||||
*jitTargetAddressToPointer<const char **>(SelEntryAddr.getValue());
|
||||
auto Sel = sel_registerName(SelName);
|
||||
*jitTargetAddressToPointer<SEL *>(SelEntryAddr) = Sel;
|
||||
*jitTargetAddressToPointer<SEL *>(SelEntryAddr.getValue()) = Sel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -135,14 +134,13 @@ Error MachOJITDylibInitializers::registerObjCClasses() const {
|
|||
auto ClassSelector = sel_registerName("class");
|
||||
|
||||
for (const auto &ObjCClassList : ObjCClassListSections) {
|
||||
assert(ObjCClassList.size() % sizeof(uintptr_t) == 0 &&
|
||||
assert(ObjCClassList.size().getValue() % sizeof(uintptr_t) == 0 &&
|
||||
"ObjCClassList section size is not a pointer multiple?");
|
||||
for (JITTargetAddress ClassPtrAddr = ObjCClassList.StartAddress;
|
||||
for (auto ClassPtrAddr = ObjCClassList.StartAddress;
|
||||
ClassPtrAddr != ObjCClassList.EndAddress;
|
||||
ClassPtrAddr += sizeof(uintptr_t)) {
|
||||
auto Cls = *jitTargetAddressToPointer<Class *>(ClassPtrAddr);
|
||||
auto *ClassCompiled =
|
||||
*jitTargetAddressToPointer<ObjCClassCompiled **>(ClassPtrAddr);
|
||||
ClassPtrAddr += ExecutorAddrDiff(sizeof(uintptr_t))) {
|
||||
auto Cls = *ClassPtrAddr.toPtr<Class *>();
|
||||
auto *ClassCompiled = *ClassPtrAddr.toPtr<ObjCClassCompiled **>();
|
||||
objc_msgSend(reinterpret_cast<id>(ClassCompiled->Parent), ClassSelector);
|
||||
auto Registered = objc_readClassPair(Cls, ImageInfo);
|
||||
|
||||
|
@ -272,11 +270,11 @@ MachOPlatform::getDeinitializerSequence(JITDylib &JD) {
|
|||
return FullDeinitSeq;
|
||||
}
|
||||
|
||||
void MachOPlatform::registerInitInfo(
|
||||
JITDylib &JD, JITTargetAddress ObjCImageInfoAddr,
|
||||
shared::ExecutorAddressRange ModInits,
|
||||
shared::ExecutorAddressRange ObjCSelRefs,
|
||||
shared::ExecutorAddressRange ObjCClassList) {
|
||||
void MachOPlatform::registerInitInfo(JITDylib &JD,
|
||||
JITTargetAddress ObjCImageInfoAddr,
|
||||
ExecutorAddressRange ModInits,
|
||||
ExecutorAddressRange ObjCSelRefs,
|
||||
ExecutorAddressRange ObjCClassList) {
|
||||
std::lock_guard<std::mutex> Lock(InitSeqsMutex);
|
||||
|
||||
auto &InitSeq = InitSeqs[&JD];
|
||||
|
@ -293,17 +291,18 @@ void MachOPlatform::registerInitInfo(
|
|||
InitSeq.addObjCClassListSection(std::move(ObjCClassList));
|
||||
}
|
||||
|
||||
static Expected<shared::ExecutorAddressRange>
|
||||
getSectionExtent(jitlink::LinkGraph &G, StringRef SectionName) {
|
||||
static Expected<ExecutorAddressRange> getSectionExtent(jitlink::LinkGraph &G,
|
||||
StringRef SectionName) {
|
||||
auto *Sec = G.findSectionByName(SectionName);
|
||||
if (!Sec)
|
||||
return shared::ExecutorAddressRange();
|
||||
return ExecutorAddressRange();
|
||||
jitlink::SectionRange R(*Sec);
|
||||
if (R.getSize() % G.getPointerSize() != 0)
|
||||
return make_error<StringError>(SectionName + " section size is not a "
|
||||
"multiple of the pointer size",
|
||||
inconvertibleErrorCode());
|
||||
return shared::ExecutorAddressRange{R.getStart(), R.getEnd()};
|
||||
return ExecutorAddressRange(ExecutorAddress(R.getStart()),
|
||||
ExecutorAddress(R.getEnd()));
|
||||
}
|
||||
|
||||
void MachOPlatform::InitScraperPlugin::modifyPassConfig(
|
||||
|
@ -332,7 +331,7 @@ void MachOPlatform::InitScraperPlugin::modifyPassConfig(
|
|||
|
||||
Config.PostFixupPasses.push_back([this, &JD = MR.getTargetJITDylib()](
|
||||
jitlink::LinkGraph &G) -> Error {
|
||||
shared::ExecutorAddressRange ModInits, ObjCSelRefs, ObjCClassList;
|
||||
ExecutorAddressRange ModInits, ObjCSelRefs, ObjCClassList;
|
||||
|
||||
JITTargetAddress ObjCImageInfoAddr = 0;
|
||||
if (auto *ObjCImageInfoSec =
|
||||
|
@ -364,26 +363,28 @@ void MachOPlatform::InitScraperPlugin::modifyPassConfig(
|
|||
LLVM_DEBUG({
|
||||
dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n";
|
||||
dbgs() << " __objc_selrefs: ";
|
||||
auto NumObjCSelRefs = ObjCSelRefs.size() / sizeof(uintptr_t);
|
||||
auto NumObjCSelRefs = ObjCSelRefs.size().getValue() / sizeof(uintptr_t);
|
||||
if (NumObjCSelRefs)
|
||||
dbgs() << NumObjCSelRefs << " pointer(s) at "
|
||||
<< formatv("{0:x16}", ObjCSelRefs.StartAddress) << "\n";
|
||||
<< formatv("{0:x16}", ObjCSelRefs.StartAddress.getValue())
|
||||
<< "\n";
|
||||
else
|
||||
dbgs() << "none\n";
|
||||
|
||||
dbgs() << " __objc_classlist: ";
|
||||
auto NumObjCClasses = ObjCClassList.size() / sizeof(uintptr_t);
|
||||
auto NumObjCClasses = ObjCClassList.size().getValue() / sizeof(uintptr_t);
|
||||
if (NumObjCClasses)
|
||||
dbgs() << NumObjCClasses << " pointer(s) at "
|
||||
<< formatv("{0:x16}", ObjCClassList.StartAddress) << "\n";
|
||||
<< formatv("{0:x16}", ObjCClassList.StartAddress.getValue())
|
||||
<< "\n";
|
||||
else
|
||||
dbgs() << "none\n";
|
||||
|
||||
dbgs() << " __mod_init_func: ";
|
||||
auto NumModInits = ModInits.size() / sizeof(uintptr_t);
|
||||
auto NumModInits = ModInits.size().getValue() / sizeof(uintptr_t);
|
||||
if (NumModInits)
|
||||
dbgs() << NumModInits << " pointer(s) at "
|
||||
<< formatv("{0:x16}", ModInits.StartAddress) << "\n";
|
||||
<< formatv("{0:x16}", ModInits.StartAddress.getValue()) << "\n";
|
||||
else
|
||||
dbgs() << "none\n";
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue