mirror of
https://github.com/LSPosed/LSPlant.git
synced 2025-05-04 20:42:02 +08:00
Refactor symbol define and use static operator() (#142)
This commit is contained in:
parent
4a2293e222
commit
c54fb307f2
@ -6,5 +6,5 @@ val androidTargetSdkVersion by extra(35)
|
|||||||
val androidMinSdkVersion by extra(21)
|
val androidMinSdkVersion by extra(21)
|
||||||
val androidBuildToolsVersion by extra("35.0.0")
|
val androidBuildToolsVersion by extra("35.0.0")
|
||||||
val androidCompileSdkVersion by extra(35)
|
val androidCompileSdkVersion by extra(35)
|
||||||
val androidNdkVersion by extra("27.0.12077973")
|
val androidNdkVersion by extra("28.0.13004108")
|
||||||
val androidCmakeVersion by extra("3.28.0+")
|
val androidCmakeVersion by extra("3.28.0+")
|
||||||
|
@ -16,14 +16,11 @@ namespace lsplant::art::mirror {
|
|||||||
|
|
||||||
export class Class {
|
export class Class {
|
||||||
private:
|
private:
|
||||||
inline static MemberFunction<
|
inline static auto GetDescriptor_ =
|
||||||
"_ZN3art6mirror5Class13GetDescriptorEPNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE",
|
"_ZN3art6mirror5Class13GetDescriptorEPNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE"_sym.as<const char *(Class::*)(std::string *)>;
|
||||||
Class, const char *(std::string *)>
|
|
||||||
GetDescriptor_;
|
|
||||||
|
|
||||||
inline static MemberFunction<"_ZN3art6mirror5Class11GetClassDefEv", Class,
|
inline static auto GetClassDef_ =
|
||||||
const dex::ClassDef *()>
|
"_ZN3art6mirror5Class11GetClassDefEv"_sym.as<const dex::ClassDef *(Class::*)()>;
|
||||||
GetClassDef_;
|
|
||||||
|
|
||||||
using BackupMethods = phmap::flat_hash_map<art::ArtMethod *, void *>;
|
using BackupMethods = phmap::flat_hash_map<art::ArtMethod *, void *>;
|
||||||
inline static phmap::flat_hash_map<const art::Thread *,
|
inline static phmap::flat_hash_map<const art::Thread *,
|
||||||
@ -62,41 +59,44 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static Hooker<
|
inline static auto SetClassStatus_ =
|
||||||
"_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS_11ClassStatusEPNS_6ThreadE",
|
"_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS_11ClassStatusEPNS_6ThreadE"_sym.hook->*[]
|
||||||
void(TrivialHandle<Class>, uint8_t, Thread *)>
|
<Backup auto backup>
|
||||||
SetClassStatus_ = +[](TrivialHandle<Class> h, uint8_t new_status, Thread *self) {
|
(TrivialHandle<Class> h, uint8_t new_status, Thread *self) static -> void {
|
||||||
if (new_status == initialized_status) {
|
if (new_status == initialized_status) {
|
||||||
BackupClassMethods(GetClassDef_(h.Get()), self);
|
BackupClassMethods(GetClassDef_(h.Get()), self);
|
||||||
}
|
}
|
||||||
return SetClassStatus_(h, new_status, self);
|
return backup(h, new_status, self);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static Hooker<"_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS1_6StatusEPNS_6ThreadE",
|
inline static auto SetStatus_ =
|
||||||
void(Handle<Class>, int, Thread *)>
|
"_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS1_6StatusEPNS_6ThreadE"_sym.hook->*[]
|
||||||
SetStatus_ = +[](Handle<Class> h, int new_status, Thread *self) {
|
<Backup auto backup>
|
||||||
|
(Handle<Class> h, int new_status, Thread *self) static -> void {
|
||||||
if (new_status == static_cast<int>(initialized_status)) {
|
if (new_status == static_cast<int>(initialized_status)) {
|
||||||
BackupClassMethods(GetClassDef_(h.Get()), self);
|
BackupClassMethods(GetClassDef_(h.Get()), self);
|
||||||
}
|
}
|
||||||
return SetStatus_(h, new_status, self);
|
return backup(h, new_status, self);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static Hooker<"_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS1_6StatusEPNS_6ThreadE",
|
inline static auto TrivialSetStatus_ =
|
||||||
void(TrivialHandle<Class>, uint32_t, Thread *)>
|
"_ZN3art6mirror5Class9SetStatusENS_6HandleIS1_EENS1_6StatusEPNS_6ThreadE"_sym.hook->*[]
|
||||||
TrivialSetStatus_ = +[](TrivialHandle<Class> h, uint32_t new_status, Thread *self) {
|
<Backup auto backup>
|
||||||
|
(TrivialHandle<Class> h, uint32_t new_status, Thread *self) static -> void {
|
||||||
if (new_status == initialized_status) {
|
if (new_status == initialized_status) {
|
||||||
BackupClassMethods(GetClassDef_(h.Get()), self);
|
BackupClassMethods(GetClassDef_(h.Get()), self);
|
||||||
}
|
}
|
||||||
return TrivialSetStatus_(h, new_status, self);
|
return backup(h, new_status, self);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static Hooker<"_ZN3art6mirror5Class9SetStatusENS1_6StatusEPNS_6ThreadE",
|
inline static auto ClassSetStatus_ =
|
||||||
void(Class *, int, Thread *)>
|
"_ZN3art6mirror5Class9SetStatusENS1_6StatusEPNS_6ThreadE"_sym.hook->*[]
|
||||||
ClassSetStatus_ = +[](Class *thiz, int new_status, Thread *self) {
|
<MemBackup auto backup>
|
||||||
|
(Class *thiz, int new_status, Thread *self) static -> void {
|
||||||
if (new_status == static_cast<int>(initialized_status)) {
|
if (new_status == static_cast<int>(initialized_status)) {
|
||||||
BackupClassMethods(GetClassDef_(thiz), self);
|
BackupClassMethods(GetClassDef_(thiz), self);
|
||||||
}
|
}
|
||||||
return ClassSetStatus_(thiz, new_status, self);
|
return backup(thiz, new_status, self);
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -17,30 +17,26 @@ class Class;
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ArtMethod {
|
export class ArtMethod {
|
||||||
inline static MemberFunction<"_ZN3art9ArtMethod12PrettyMethodEPS0_b", ArtMethod,
|
inline static auto PrettyMethod_ =
|
||||||
std::string(bool)>
|
"_ZN3art9ArtMethod12PrettyMethodEPS0_b"_sym.as<std::string(ArtMethod::*)(bool)>;
|
||||||
PrettyMethod_;
|
|
||||||
|
|
||||||
inline static Function<"_ZN3art12PrettyMethodEPNS_9ArtMethodEb",
|
inline static auto PrettyMethodStatic_ =
|
||||||
std::string(ArtMethod *thiz, bool with_signature)>
|
"_ZN3art12PrettyMethodEPNS_9ArtMethodEb"_sym.as<std::string(ArtMethod *thiz, bool with_signature)>;
|
||||||
PrettyMethodStatic_;
|
|
||||||
|
|
||||||
inline static Function<"_ZN3art12PrettyMethodEPNS_6mirror9ArtMethodEb",
|
inline static auto PrettyMethodMirror_ =
|
||||||
std::string(ArtMethod *thiz, bool with_signature)>
|
"_ZN3art12PrettyMethodEPNS_6mirror9ArtMethodEb"_sym.as<std::string(ArtMethod *thiz, bool with_signature)>;
|
||||||
PrettyMethodMirror_;
|
|
||||||
|
|
||||||
inline static Function<"_ZN3artL15GetMethodShortyEP7_JNIEnvP10_jmethodID",
|
inline static auto GetMethodShortyL_ =
|
||||||
const char *(JNIEnv *env, jmethodID method)>
|
"_ZN3artL15GetMethodShortyEP7_JNIEnvP10_jmethodID"_sym.as<const char *(JNIEnv *env, jmethodID method)>;
|
||||||
GetMethodShortyL_;
|
|
||||||
inline static Function<"_ZN3art15GetMethodShortyEP7_JNIEnvP10_jmethodID",
|
|
||||||
const char *(JNIEnv *env, jmethodID mid)>
|
|
||||||
GetMethodShorty_;
|
|
||||||
|
|
||||||
inline static MemberFunction<"_ZN3art9ArtMethod24ThrowInvocationTimeErrorEv", ArtMethod, void()>
|
inline static auto GetMethodShorty_ =
|
||||||
ThrowInvocationTimeError_;
|
"_ZN3art15GetMethodShortyEP7_JNIEnvP10_jmethodID"_sym.as<const char *(JNIEnv *env, jmethodID mid)>;
|
||||||
|
|
||||||
inline static Function<"artInterpreterToCompiledCodeBridge", void()>
|
inline static auto ThrowInvocationTimeError_ =
|
||||||
art_interpreter_to_compiled_code_bridge_;
|
"_ZN3art9ArtMethod24ThrowInvocationTimeErrorEv"_sym.as<void(ArtMethod::*)()>;
|
||||||
|
|
||||||
|
inline static auto art_interpreter_to_compiled_code_bridge_ =
|
||||||
|
"artInterpreterToCompiledCodeBridge"_sym.as<void()>;
|
||||||
|
|
||||||
inline void ThrowInvocationTimeError() {
|
inline void ThrowInvocationTimeError() {
|
||||||
if (ThrowInvocationTimeError_) {
|
if (ThrowInvocationTimeError_) {
|
||||||
|
@ -17,28 +17,27 @@ import runtime;
|
|||||||
namespace lsplant::art {
|
namespace lsplant::art {
|
||||||
export class ClassLinker {
|
export class ClassLinker {
|
||||||
private:
|
private:
|
||||||
inline static MemberFunction<
|
inline static auto SetEntryPointsToInterpreter_ =
|
||||||
"_ZNK3art11ClassLinker27SetEntryPointsToInterpreterEPNS_9ArtMethodE", ClassLinker,
|
"_ZNK3art11ClassLinker27SetEntryPointsToInterpreterEPNS_9ArtMethodE"_sym.as<void(ClassLinker::*)(ArtMethod *)>;
|
||||||
void(ArtMethod *)>
|
|
||||||
SetEntryPointsToInterpreter_;
|
|
||||||
|
|
||||||
inline static Hooker<"_ZN3art11ClassLinker30ShouldUseInterpreterEntrypointEPNS_9ArtMethodEPKv",
|
inline static auto ShouldUseInterpreterEntrypoint_ =
|
||||||
bool(ArtMethod *, const void *)>
|
"_ZN3art11ClassLinker30ShouldUseInterpreterEntrypointEPNS_9ArtMethodEPKv"_sym.hook->*[]
|
||||||
ShouldUseInterpreterEntrypoint_ = +[](ArtMethod *art_method, const void *quick_code) {
|
<Backup auto backup>
|
||||||
|
(ArtMethod *art_method, const void *quick_code)static -> bool {
|
||||||
if (quick_code != nullptr && IsHooked(art_method)) [[unlikely]] {
|
if (quick_code != nullptr && IsHooked(art_method)) [[unlikely]] {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return ShouldUseInterpreterEntrypoint_(art_method, quick_code);
|
return backup(art_method, quick_code);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static Function<"art_quick_to_interpreter_bridge", void(void *)>
|
inline static auto art_quick_to_interpreter_bridge_ =
|
||||||
art_quick_to_interpreter_bridge_;
|
"art_quick_to_interpreter_bridge"_sym.as<void(void *)>;
|
||||||
|
|
||||||
inline static Function<"_ZN3art15instrumentationL19GetOptimizedCodeForEPNS_9ArtMethodE",
|
inline static auto GetOptimizedCodeFor_ =
|
||||||
void *(ArtMethod *)> GetOptimizedCodeFor_;
|
"_ZN3art15instrumentationL19GetOptimizedCodeForEPNS_9ArtMethodE"_sym.as<void *(ArtMethod *)>;
|
||||||
|
|
||||||
inline static MemberFunction<"_ZNK3art11ClassLinker29GetRuntimeQuickGenericJniStubEv",
|
inline static auto GetRuntimeQuickGenericJniStub_=
|
||||||
ClassLinker, void *()> GetRuntimeQuickGenericJniStub_;
|
"_ZNK3art11ClassLinker29GetRuntimeQuickGenericJniStubEv"_sym.as<void *(ClassLinker::*)()>;
|
||||||
|
|
||||||
inline static art::ArtMethod *MayGetBackup(art::ArtMethod *method) {
|
inline static art::ArtMethod *MayGetBackup(art::ArtMethod *method) {
|
||||||
if (auto backup = IsHooked(method); backup) [[unlikely]] {
|
if (auto backup = IsHooked(method); backup) [[unlikely]] {
|
||||||
@ -48,57 +47,60 @@ private:
|
|||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static MemberHooker<"_ZN3art6mirror9ArtMethod14RegisterNativeEPNS_6ThreadEPKvb",
|
inline static auto RegisterNativeThread_ =
|
||||||
ClassLinker, void(ArtMethod *, Thread *, const void *, bool)>
|
"_ZN3art6mirror9ArtMethod14RegisterNativeEPNS_6ThreadEPKvb"_sym.hook->*[]
|
||||||
RegisterNativeThread_ = +[](ClassLinker *thiz, ArtMethod *method, Thread *thread,
|
<MemBackup auto backup>
|
||||||
const void *native_method, bool is_fast) {
|
(ClassLinker *thiz, ArtMethod *method, Thread *thread, const void *native_method, bool is_fast) static -> void {
|
||||||
return RegisterNativeThread_(thiz, MayGetBackup(method), thread, native_method,
|
return backup(thiz, MayGetBackup(method), thread, native_method, is_fast);
|
||||||
is_fast);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static MemberHooker<"_ZN3art6mirror9ArtMethod16UnregisterNativeEPNS_6ThreadE",
|
inline static auto UnregisterNativeThread_ =
|
||||||
ClassLinker, void(ArtMethod *, Thread *)>
|
"_ZN3art6mirror9ArtMethod16UnregisterNativeEPNS_6ThreadE"_sym.hook->*[]
|
||||||
UnregisterNativeThread_ = +[](ClassLinker *thiz, ArtMethod *method, Thread *thread) {
|
<MemBackup auto backup>
|
||||||
return UnregisterNativeThread_(thiz, MayGetBackup(method), thread);
|
(ClassLinker *thiz, ArtMethod *method, Thread *thread) static -> void {
|
||||||
|
return backup(thiz, MayGetBackup(method), thread);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static MemberHooker<"_ZN3art9ArtMethod14RegisterNativeEPKvb", ClassLinker,
|
inline static auto RegisterNativeFast_ =
|
||||||
void(ArtMethod *, const void *, bool)>
|
"_ZN3art9ArtMethod14RegisterNativeEPKvb"_sym.hook->*[]
|
||||||
RegisterNativeFast_ =
|
<MemBackup auto backup>
|
||||||
+[](ClassLinker *thiz, ArtMethod *method, const void *native_method, bool is_fast) {
|
(ClassLinker *thiz, ArtMethod *method, const void *native_method, bool is_fast) static -> void {
|
||||||
return RegisterNativeFast_(thiz, MayGetBackup(method), native_method, is_fast);
|
return backup(thiz, MayGetBackup(method), native_method, is_fast);
|
||||||
};
|
|
||||||
|
|
||||||
inline static MemberHooker<"_ZN3art9ArtMethod16UnregisterNativeEv", ClassLinker,
|
|
||||||
void(ArtMethod *)>
|
|
||||||
UnregisterNativeFast_ = +[](ClassLinker *thiz, ArtMethod *method) {
|
|
||||||
return UnregisterNativeFast_(thiz, MayGetBackup(method));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static MemberHooker<"_ZN3art9ArtMethod14RegisterNativeEPKv", ClassLinker,
|
inline static auto UnregisterNativeFast_ =
|
||||||
const void *(ArtMethod *, const void *)>
|
"_ZN3art9ArtMethod16UnregisterNativeEv"_sym.hook->*[]
|
||||||
RegisterNative_ = +[](ClassLinker *thiz, ArtMethod *method, const void *native_method) {
|
<MemBackup auto backup>
|
||||||
return RegisterNative_(thiz, MayGetBackup(method), native_method);
|
(ClassLinker *thiz, ArtMethod *method) static -> void{
|
||||||
|
return backup(thiz, MayGetBackup(method));
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static MemberHooker<"_ZN3art9ArtMethod16UnregisterNativeEv", ClassLinker,
|
inline static auto RegisterNative_ =
|
||||||
const void *(ArtMethod *)>
|
"_ZN3art9ArtMethod14RegisterNativeEPKv"_sym.hook->*[]
|
||||||
UnregisterNative_ = +[](ClassLinker *thiz, ArtMethod *method) {
|
<MemBackup auto backup>
|
||||||
return UnregisterNative_(thiz, MayGetBackup(method));
|
(ClassLinker *thiz, ArtMethod *method, const void *native_method) static -> const void * {
|
||||||
|
return backup(thiz, MayGetBackup(method), native_method);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static MemberHooker<
|
inline static auto UnregisterNative_ =
|
||||||
"_ZN3art11ClassLinker14RegisterNativeEPNS_6ThreadEPNS_9ArtMethodEPKv", ClassLinker,
|
"_ZN3art9ArtMethod16UnregisterNativeEv"_sym.hook->*[]
|
||||||
const void *(Thread *, ArtMethod *, const void *)>
|
<MemBackup auto backup>
|
||||||
RegisterNativeClassLinker_ =
|
(ClassLinker *thiz, ArtMethod *method) static -> const void * {
|
||||||
+[](ClassLinker *thiz, Thread *self, ArtMethod *method, const void *native_method) {
|
return backup(thiz, MayGetBackup(method));
|
||||||
return RegisterNativeClassLinker_(thiz, self, MayGetBackup(method), native_method);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
inline static MemberHooker<"_ZN3art11ClassLinker16UnregisterNativeEPNS_6ThreadEPNS_9ArtMethodE",
|
inline static auto RegisterNativeClassLinker_ =
|
||||||
ClassLinker, const void *(Thread *, ArtMethod *)>
|
"_ZN3art11ClassLinker14RegisterNativeEPNS_6ThreadEPNS_9ArtMethodEPKv"_sym.hook->*[]
|
||||||
UnregisterNativeClassLinker_ = +[](ClassLinker *thiz, Thread *self, ArtMethod *method) {
|
<MemBackup auto backup>
|
||||||
return UnregisterNativeClassLinker_(thiz, self, MayGetBackup(method));
|
(ClassLinker *thiz, Thread *self, ArtMethod *method, const void *native_method) static -> const void *{
|
||||||
|
return backup(thiz, self, MayGetBackup(method), native_method);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline static auto UnregisterNativeClassLinker_ =
|
||||||
|
"_ZN3art11ClassLinker16UnregisterNativeEPNS_6ThreadEPNS_9ArtMethodE"_sym.hook->*[]
|
||||||
|
<MemBackup auto backup>
|
||||||
|
(ClassLinker *thiz, Thread *self, ArtMethod *method) static -> const void * {
|
||||||
|
return backup(thiz, self, MayGetBackup(method));
|
||||||
};
|
};
|
||||||
|
|
||||||
static void RestoreBackup(const dex::ClassDef *class_def, art::Thread *self) {
|
static void RestoreBackup(const dex::ClassDef *class_def, art::Thread *self) {
|
||||||
@ -123,44 +125,44 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static MemberHooker<
|
inline static auto FixupStaticTrampolines_ =
|
||||||
"_ZN3art11ClassLinker22FixupStaticTrampolinesENS_6ObjPtrINS_6mirror5ClassEEE", ClassLinker,
|
"_ZN3art11ClassLinker22FixupStaticTrampolinesENS_6ObjPtrINS_6mirror5ClassEEE"_sym.hook->*[]
|
||||||
void(ObjPtr<mirror::Class>)>
|
<MemBackup auto backup>
|
||||||
FixupStaticTrampolines_ = +[](ClassLinker *thiz, ObjPtr<mirror::Class> mirror_class) {
|
(ClassLinker *thiz, ObjPtr<mirror::Class> mirror_class) static -> void {
|
||||||
FixupStaticTrampolines_(thiz, mirror_class);
|
backup(thiz, mirror_class);
|
||||||
RestoreBackup(mirror_class->GetClassDef(), nullptr);
|
RestoreBackup(mirror_class->GetClassDef(), nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static MemberHooker<
|
inline static auto FixupStaticTrampolinesWithThread_ =
|
||||||
"_ZN3art11ClassLinker22FixupStaticTrampolinesEPNS_6ThreadENS_6ObjPtrINS_6mirror5ClassEEE",
|
"_ZN3art11ClassLinker22FixupStaticTrampolinesEPNS_6ThreadENS_6ObjPtrINS_6mirror5ClassEEE"_sym.hook->*[]
|
||||||
ClassLinker, void(Thread *, ObjPtr<mirror::Class>)>
|
<MemBackup auto backup>
|
||||||
FixupStaticTrampolinesWithThread_ =
|
(ClassLinker *thiz, Thread *self, ObjPtr<mirror::Class> mirror_class) static -> void {
|
||||||
+[](ClassLinker *thiz, Thread *self, ObjPtr<mirror::Class> mirror_class) {
|
backup(thiz, self, mirror_class);
|
||||||
FixupStaticTrampolinesWithThread_(thiz, self, mirror_class);
|
RestoreBackup(mirror_class->GetClassDef(), self);
|
||||||
RestoreBackup(mirror_class->GetClassDef(), self);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
inline static MemberHooker<"_ZN3art11ClassLinker22FixupStaticTrampolinesEPNS_6mirror5ClassE",
|
inline static auto FixupStaticTrampolinesRaw_ =
|
||||||
ClassLinker, void(mirror::Class *)>
|
"_ZN3art11ClassLinker22FixupStaticTrampolinesEPNS_6mirror5ClassE"_sym.hook->*[]
|
||||||
FixupStaticTrampolinesRaw_ = +[](ClassLinker *thiz, mirror::Class *mirror_class) {
|
<MemBackup auto backup>
|
||||||
FixupStaticTrampolinesRaw_(thiz, mirror_class);
|
(ClassLinker *thiz, mirror::Class *mirror_class)static -> void {
|
||||||
|
backup(thiz, mirror_class);
|
||||||
RestoreBackup(mirror_class->GetClassDef(), nullptr);
|
RestoreBackup(mirror_class->GetClassDef(), nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static MemberHooker<
|
inline static auto AdjustThreadVisibilityCounter_ =
|
||||||
{"_ZN3art11ClassLinker26VisiblyInitializedCallback29AdjustThreadVisibilityCounterEPNS_6ThreadEi",
|
("_ZN3art11ClassLinker26VisiblyInitializedCallback29AdjustThreadVisibilityCounterEPNS_6ThreadEi"_sym |
|
||||||
"_ZN3art11ClassLinker26VisiblyInitializedCallback29AdjustThreadVisibilityCounterEPNS_6ThreadEl"},
|
"_ZN3art11ClassLinker26VisiblyInitializedCallback29AdjustThreadVisibilityCounterEPNS_6ThreadEl"_sym).hook->*[]
|
||||||
ClassLinker, void(Thread *, ssize_t)>
|
<MemBackup auto backup>
|
||||||
AdjustThreadVisibilityCounter_ = +[](ClassLinker *thiz, Thread *self, ssize_t adjustment) {
|
(ClassLinker *thiz, Thread *self, ssize_t adjustment) static -> void {
|
||||||
AdjustThreadVisibilityCounter_(thiz, self, adjustment);
|
backup(thiz, self, adjustment);
|
||||||
RestoreBackup(nullptr, self);
|
RestoreBackup(nullptr, self);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static MemberHooker<
|
inline static auto MarkVisiblyInitialized_ =
|
||||||
"_ZN3art11ClassLinker26VisiblyInitializedCallback22MarkVisiblyInitializedEPNS_6ThreadE",
|
"_ZN3art11ClassLinker26VisiblyInitializedCallback22MarkVisiblyInitializedEPNS_6ThreadE"_sym.hook->*[]
|
||||||
ClassLinker, void(Thread *)>
|
<MemBackup auto backup>
|
||||||
MarkVisiblyInitialized_ = +[](ClassLinker *thiz, Thread *self) {
|
(ClassLinker *thiz, Thread *self) static -> void {
|
||||||
MarkVisiblyInitialized_(thiz, self);
|
backup(thiz, self);
|
||||||
RestoreBackup(nullptr, self);
|
RestoreBackup(nullptr, self);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,32 +18,28 @@ export class DexFile {
|
|||||||
uint32_t checksum_; // See also location_checksum_
|
uint32_t checksum_; // See also location_checksum_
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static Function<
|
inline static auto OpenMemory_ =
|
||||||
{"_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_",
|
("_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_"_sym |
|
||||||
"_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_"},
|
"_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_"_sym).as<
|
||||||
std::unique_ptr<DexFile>(const uint8_t* dex_file, size_t size, const std::string& location,
|
std::unique_ptr<DexFile>(const uint8_t* dex_file, size_t size, const std::string& location,
|
||||||
uint32_t location_checksum, void* mem_map,
|
uint32_t location_checksum, void* mem_map,
|
||||||
const void* oat_dex_file, std::string* error_msg)>
|
const void* oat_dex_file, std::string* error_msg)>;
|
||||||
OpenMemory_;
|
|
||||||
|
|
||||||
inline static Function<
|
inline static auto OpenMemoryRaw_ =
|
||||||
{"_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_7OatFileEPS9_",
|
("_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_7OatFileEPS9_"_sym |
|
||||||
"_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_7OatFileEPS9_"},
|
"_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_7OatFileEPS9_"_sym).as<
|
||||||
const DexFile*(const uint8_t* dex_file, size_t size, const std::string& location,
|
const DexFile*(const uint8_t* dex_file, size_t size, const std::string& location,
|
||||||
uint32_t location_checksum, void* mem_map, const void* oat_dex_file,
|
uint32_t location_checksum, void* mem_map, const void* oat_dex_file,
|
||||||
std::string* error_msg)>
|
std::string* error_msg)>;
|
||||||
OpenMemoryRaw_;
|
|
||||||
|
|
||||||
inline static Function<
|
inline static auto OpenMemoryWithoutOdex_ =
|
||||||
{"_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPS9_",
|
("_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPS9_"_sym |
|
||||||
"_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPS9_"},
|
"_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPS9_"_sym).as<
|
||||||
const DexFile*(const uint8_t* dex_file, size_t size, const std::string& location,
|
const DexFile*(const uint8_t* dex_file, size_t size, const std::string& location,
|
||||||
uint32_t location_checksum, void* mem_map, std::string* error_msg)>
|
uint32_t location_checksum, void* mem_map, std::string* error_msg)>;
|
||||||
OpenMemoryWithoutOdex_;
|
|
||||||
|
|
||||||
inline static Function<"_ZN3artL18DexFile_setTrustedEP7_JNIEnvP7_jclassP8_jobject",
|
inline static auto DexFile_setTrusted_ =
|
||||||
void(JNIEnv* env, jclass clazz, jobject j_cookie)>
|
"_ZN3artL18DexFile_setTrustedEP7_JNIEnvP7_jclassP8_jobject"_sym.as<void(JNIEnv* env, jclass clazz, jobject j_cookie)>;
|
||||||
DexFile_setTrusted_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const DexFile* OpenMemory(const uint8_t* dex_file, size_t size, std::string location,
|
static const DexFile* OpenMemory(const uint8_t* dex_file, size_t size, std::string location,
|
||||||
|
@ -98,13 +98,10 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
export class ScopedGCCriticalSection {
|
export class ScopedGCCriticalSection {
|
||||||
inline static MemberFunction<
|
inline static auto constructor_ =
|
||||||
"_ZN3art2gc23ScopedGCCriticalSectionC2EPNS_6ThreadENS0_7GcCauseENS0_13CollectorTypeE",
|
"_ZN3art2gc23ScopedGCCriticalSectionC2EPNS_6ThreadENS0_7GcCauseENS0_13CollectorTypeE"_sym.as<void(ScopedGCCriticalSection::*)(Thread *, GcCause, CollectorType)>;
|
||||||
ScopedGCCriticalSection, void(Thread *, GcCause, CollectorType)>
|
inline static auto destructor_ =
|
||||||
constructor_;
|
"_ZN3art2gc23ScopedGCCriticalSectionD2Ev"_sym.as<void(ScopedGCCriticalSection::*)()>;
|
||||||
inline static MemberFunction<"_ZN3art2gc23ScopedGCCriticalSectionD2Ev", ScopedGCCriticalSection,
|
|
||||||
void()>
|
|
||||||
destructor_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScopedGCCriticalSection(Thread *self, GcCause cause, CollectorType collector_type) {
|
ScopedGCCriticalSection(Thread *self, GcCause cause, CollectorType collector_type) {
|
||||||
|
@ -21,31 +21,28 @@ export class Instrumentation {
|
|||||||
return art_method;
|
return art_method;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static MemberHooker<
|
inline static auto UpdateMethodsCodeToInterpreterEntryPoint_ =
|
||||||
"_ZN3art15instrumentation15Instrumentation40UpdateMethodsCodeToInterpreterEntryPointEPNS_9ArtMethodE",
|
"_ZN3art15instrumentation15Instrumentation40UpdateMethodsCodeToInterpreterEntryPointEPNS_9ArtMethodE"_sym.hook->*[]
|
||||||
Instrumentation, void(ArtMethod *)>
|
<MemBackup auto backup>
|
||||||
UpdateMethodsCodeToInterpreterEntryPoint_ =
|
(Instrumentation *thiz, ArtMethod *art_method) static -> void {
|
||||||
+[](Instrumentation *thiz, ArtMethod *art_method) {
|
|
||||||
if (IsDeoptimized(art_method)) {
|
|
||||||
LOGV("skip update entrypoint on deoptimized method %s",
|
|
||||||
art_method->PrettyMethod(true).c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UpdateMethodsCodeToInterpreterEntryPoint_(
|
|
||||||
thiz, MaybeUseBackupMethod(art_method, nullptr));
|
|
||||||
};
|
|
||||||
|
|
||||||
inline static MemberHooker<
|
|
||||||
"_ZN3art15instrumentation15Instrumentation21InitializeMethodsCodeEPNS_9ArtMethodEPKv",
|
|
||||||
Instrumentation, void(ArtMethod *, const void *)>
|
|
||||||
InitializeMethodsCode_ = +[](Instrumentation *thiz, ArtMethod *art_method,
|
|
||||||
const void *quick_code) {
|
|
||||||
if (IsDeoptimized(art_method)) {
|
if (IsDeoptimized(art_method)) {
|
||||||
LOGV("skip update entrypoint on deoptimized method %s",
|
LOGV("skip update entrypoint on deoptimized method %s",
|
||||||
art_method->PrettyMethod(true).c_str());
|
art_method->PrettyMethod(true).c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
InitializeMethodsCode_(thiz, MaybeUseBackupMethod(art_method, quick_code), quick_code);
|
backup(thiz, MaybeUseBackupMethod(art_method, nullptr));
|
||||||
|
};
|
||||||
|
|
||||||
|
inline static auto InitializeMethodsCode_ =
|
||||||
|
"_ZN3art15instrumentation15Instrumentation21InitializeMethodsCodeEPNS_9ArtMethodEPKv"_sym.hook->*[]
|
||||||
|
<MemBackup auto backup>
|
||||||
|
(Instrumentation *thiz, ArtMethod *art_method, const void *quick_code) static -> void {
|
||||||
|
if (IsDeoptimized(art_method)) {
|
||||||
|
LOGV("skip update entrypoint on deoptimized method %s",
|
||||||
|
art_method->PrettyMethod(true).c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
backup(thiz, MaybeUseBackupMethod(art_method, quick_code), quick_code);
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -17,29 +17,28 @@ enum class CompilationKind {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export class Jit {
|
export class Jit {
|
||||||
inline static MemberHooker<
|
inline static auto EnqueueOptimizedCompilation_ =
|
||||||
"_ZN3art3jit3Jit27EnqueueOptimizedCompilationEPNS_9ArtMethodEPNS_6ThreadE", Jit,
|
"_ZN3art3jit3Jit27EnqueueOptimizedCompilationEPNS_9ArtMethodEPNS_6ThreadE"_sym.hook->*[]
|
||||||
void(ArtMethod *, Thread *)>
|
<MemBackup auto backup>
|
||||||
EnqueueOptimizedCompilation_ = +[](Jit *thiz, ArtMethod *method, Thread *self) {
|
(Jit *thiz, ArtMethod *method, Thread *self) static -> void {
|
||||||
if (auto target = IsBackup(method); target) [[unlikely]] {
|
if (auto target = IsBackup(method); target) [[unlikely]] {
|
||||||
LOGD("Propagate enqueue compilation: %p -> %p", method, target);
|
LOGD("Propagate enqueue compilation: %p -> %p", method, target);
|
||||||
method = target;
|
method = target;
|
||||||
}
|
}
|
||||||
return EnqueueOptimizedCompilation_(thiz, method, self);
|
return backup(thiz, method, self);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static MemberHooker<
|
inline static auto AddCompileTask_ =
|
||||||
"_ZN3art3jit3Jit14AddCompileTaskEPNS_6ThreadEPNS_9ArtMethodENS_15CompilationKindEb", Jit,
|
"_ZN3art3jit3Jit14AddCompileTaskEPNS_6ThreadEPNS_9ArtMethodENS_15CompilationKindEb"_sym.hook->*[]
|
||||||
void(Thread *, ArtMethod *, CompilationKind, bool)>
|
<MemBackup auto backup>
|
||||||
AddCompileTask_ = +[](Jit *thiz, Thread *self, ArtMethod *method,
|
(Jit *thiz, Thread *self, ArtMethod *method, CompilationKind compilation_kind, bool precompile) static -> void {
|
||||||
CompilationKind compilation_kind, bool precompile) {
|
|
||||||
if (compilation_kind == CompilationKind::kOptimized && !precompile) {
|
if (compilation_kind == CompilationKind::kOptimized && !precompile) {
|
||||||
if (auto backup = IsHooked(method); backup) [[unlikely]] {
|
if (auto b = IsHooked(method); b) [[unlikely]] {
|
||||||
LOGD("Propagate compile task: %p -> %p", method, backup);
|
LOGD("Propagate compile task: %p -> %p", method, b);
|
||||||
method = backup;
|
method = b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return AddCompileTask_(thiz, self, method, compilation_kind, precompile);
|
return backup(thiz, self, method, compilation_kind, precompile);
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -11,9 +11,8 @@ import hook_helper;
|
|||||||
|
|
||||||
namespace lsplant::art::jit {
|
namespace lsplant::art::jit {
|
||||||
export class JitCodeCache {
|
export class JitCodeCache {
|
||||||
inline static MemberFunction<"_ZN3art3jit12JitCodeCache18MoveObsoleteMethodEPNS_9ArtMethodES3_",
|
inline static auto MoveObsoleteMethod_ =
|
||||||
JitCodeCache, void(ArtMethod *, ArtMethod *)>
|
"_ZN3art3jit12JitCodeCache18MoveObsoleteMethodEPNS_9ArtMethodES3_"_sym.as<void(JitCodeCache::*)(ArtMethod *, ArtMethod *)>;
|
||||||
MoveObsoleteMethod_;
|
|
||||||
|
|
||||||
static void MoveObsoleteMethods(JitCodeCache *thiz) {
|
static void MoveObsoleteMethods(JitCodeCache *thiz) {
|
||||||
auto movements = GetJitMovements();
|
auto movements = GetJitMovements();
|
||||||
@ -28,18 +27,20 @@ export class JitCodeCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static MemberHooker<"_ZN3art3jit12JitCodeCache19GarbageCollectCacheEPNS_6ThreadE",
|
inline static auto GarbageCollectCache_ =
|
||||||
JitCodeCache, void(Thread *)>
|
"_ZN3art3jit12JitCodeCache19GarbageCollectCacheEPNS_6ThreadE"_sym.hook->*[]
|
||||||
GarbageCollectCache_ = +[](JitCodeCache *thiz, Thread *self) {
|
<MemBackup auto backup>
|
||||||
|
(JitCodeCache *thiz, Thread *self) static -> void {
|
||||||
MoveObsoleteMethods(thiz);
|
MoveObsoleteMethods(thiz);
|
||||||
GarbageCollectCache_(thiz, self);
|
backup(thiz, self);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static MemberHooker<"_ZN3art3jit12JitCodeCache12DoCollectionEPNS_6ThreadE", JitCodeCache,
|
inline static auto DoCollection_ =
|
||||||
void(Thread *)>
|
"_ZN3art3jit12JitCodeCache12DoCollectionEPNS_6ThreadE"_sym.hook->*[]
|
||||||
DoCollection_ = +[](JitCodeCache *thiz, Thread *self) {
|
<MemBackup auto backup>
|
||||||
|
(JitCodeCache *thiz, Thread *self) static -> void {
|
||||||
MoveObsoleteMethods(thiz);
|
MoveObsoleteMethods(thiz);
|
||||||
DoCollection_(thiz, self);
|
backup(thiz, self);
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -13,16 +13,15 @@ namespace lsplant::art::jni {
|
|||||||
|
|
||||||
export class JniIdManager {
|
export class JniIdManager {
|
||||||
private:
|
private:
|
||||||
inline static MemberHooker<
|
inline static auto EncodeGenericId_ =
|
||||||
"_ZN3art3jni12JniIdManager15EncodeGenericIdINS_9ArtMethodEEEmNS_16ReflectiveHandleIT_EE",
|
"_ZN3art3jni12JniIdManager15EncodeGenericIdINS_9ArtMethodEEEmNS_16ReflectiveHandleIT_EE"_sym.hook->*[]
|
||||||
JniIdManager, uintptr_t(ReflectiveHandle<ArtMethod>)>
|
<MemBackup auto backup>
|
||||||
EncodeGenericId_ =
|
(JniIdManager *thiz, ReflectiveHandle<ArtMethod> method) static -> uintptr_t {
|
||||||
+[](JniIdManager *thiz, ReflectiveHandle<ArtMethod> method) -> uintptr_t {
|
|
||||||
if (auto target = IsBackup(method.Get()); target) {
|
if (auto target = IsBackup(method.Get()); target) {
|
||||||
LOGD("get generic id for %s", method.Get()->PrettyMethod().c_str());
|
LOGD("get generic id for %s", method.Get()->PrettyMethod().c_str());
|
||||||
method.Set(target);
|
method.Set(target);
|
||||||
}
|
}
|
||||||
return EncodeGenericId_(thiz, method);
|
return backup(thiz, method);
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -30,13 +30,13 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline static Field<"_ZN3art7Runtime9instance_E", Runtime *> instance_;
|
inline static auto instance_ = "_ZN3art7Runtime9instance_E"_sym.as<Runtime *>;
|
||||||
|
|
||||||
inline static MemberFunction<"_ZN3art7Runtime17SetJavaDebuggableEb", Runtime, void(bool)>
|
inline static auto SetJavaDebuggable_ =
|
||||||
SetJavaDebuggable_;
|
"_ZN3art7Runtime17SetJavaDebuggableEb"_sym.as<void (Runtime::*)(bool)>;
|
||||||
inline static MemberFunction<"_ZN3art7Runtime20SetRuntimeDebugStateENS0_17RuntimeDebugStateE",
|
|
||||||
Runtime, void(RuntimeDebugState)>
|
inline static auto SetRuntimeDebugState_ =
|
||||||
SetRuntimeDebugState_;
|
"_ZN3art7Runtime20SetRuntimeDebugStateENS0_17RuntimeDebugStateE"_sym.as<void (Runtime::*)(RuntimeDebugState)>;
|
||||||
|
|
||||||
inline static size_t debug_state_offset = 0U;
|
inline static size_t debug_state_offset = 0U;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import hook_helper;
|
|||||||
|
|
||||||
namespace lsplant::art {
|
namespace lsplant::art {
|
||||||
export class Thread {
|
export class Thread {
|
||||||
inline static Function<"_ZN3art6Thread14CurrentFromGdbEv", Thread *()> CurrentFromGdb_;
|
inline static auto CurrentFromGdb_ = "_ZN3art6Thread14CurrentFromGdbEv"_sym.as<Thread *()>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Thread *Current() {
|
static Thread *Current() {
|
||||||
|
@ -7,14 +7,14 @@ import hook_helper;
|
|||||||
namespace lsplant::art::thread_list {
|
namespace lsplant::art::thread_list {
|
||||||
|
|
||||||
export class ScopedSuspendAll {
|
export class ScopedSuspendAll {
|
||||||
inline static MemberFunction<"_ZN3art16ScopedSuspendAllC2EPKcb", ScopedSuspendAll,
|
inline static auto constructor_ =
|
||||||
void(const char *, bool)>
|
"_ZN3art16ScopedSuspendAllC2EPKcb"_sym.as<void(ScopedSuspendAll::*)(const char *, bool)>;
|
||||||
constructor_;
|
|
||||||
inline static MemberFunction<"_ZN3art16ScopedSuspendAllD2Ev", ScopedSuspendAll, void()>
|
|
||||||
destructor_;
|
|
||||||
|
|
||||||
inline static Function<"_ZN3art3Dbg9SuspendVMEv", void()> SuspendVM_;
|
inline static auto destructor_ =
|
||||||
inline static Function<"_ZN3art3Dbg8ResumeVMEv", void()> ResumeVM_;
|
"_ZN3art16ScopedSuspendAllD2Ev"_sym.as<void(ScopedSuspendAll::*)()>;
|
||||||
|
|
||||||
|
inline static auto SuspendVM_ = "_ZN3art3Dbg9SuspendVMEv"_sym.as<void()>;
|
||||||
|
inline static auto ResumeVM_ = "_ZN3art3Dbg8ResumeVMEv"_sym.as<void()>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScopedSuspendAll(const char *cause, bool long_suspend) {
|
ScopedSuspendAll(const char *cause, bool long_suspend) {
|
||||||
|
@ -22,79 +22,139 @@ struct FixedString {
|
|||||||
char data[N] = {};
|
char data[N] = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <FixedString, typename>
|
template<typename T>
|
||||||
|
concept FuncType = std::is_function_v<T> || std::is_member_function_pointer_v<T>;
|
||||||
|
|
||||||
|
template <FixedString, FuncType>
|
||||||
struct Function;
|
struct Function;
|
||||||
|
|
||||||
template <FixedString, typename, typename>
|
template <FixedString Sym, typename Ret, typename... Args>
|
||||||
struct MemberFunction;
|
struct Function<Sym, Ret(Args...)> {
|
||||||
|
[[gnu::always_inline]] static Ret operator()(Args... args) {
|
||||||
|
return inner_.function_(args...);
|
||||||
|
}
|
||||||
|
[[gnu::always_inline]] operator bool() { return inner_.raw_function_; }
|
||||||
|
[[gnu::always_inline]] auto operator&() const { return inner_.function_; }
|
||||||
|
[[gnu::always_inline]] Function &operator=(void *function) {
|
||||||
|
inner_.raw_function_ = function;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline static union {
|
||||||
|
Ret (*function_)(Args...);
|
||||||
|
void *raw_function_ = nullptr;
|
||||||
|
} inner_;
|
||||||
|
|
||||||
|
static_assert(sizeof(inner_.function_) == sizeof(inner_.raw_function_));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <FixedString Sym, class This, typename Ret, typename... Args>
|
||||||
|
struct Function<Sym, Ret(This::*)(Args...)> {
|
||||||
|
[[gnu::always_inline]] static Ret operator()(This *thiz, Args... args) {
|
||||||
|
return (reinterpret_cast<ThisType *>(thiz)->*inner_.function_)(args...);
|
||||||
|
}
|
||||||
|
[[gnu::always_inline]] operator bool() { return inner_.raw_function_; }
|
||||||
|
[[gnu::always_inline]] auto operator&() const { return inner_.function_; }
|
||||||
|
[[gnu::always_inline]] Function &operator=(void *function) {
|
||||||
|
inner_.raw_function_ = function;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
using ThisType = std::conditional_t<std::is_same_v<This, void>, Function, This>;
|
||||||
|
inline static union {
|
||||||
|
Ret (ThisType::*function_)(Args...) const;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
void *raw_function_ = nullptr;
|
||||||
|
[[maybe_unused]] std::ptrdiff_t adj = 0;
|
||||||
|
};
|
||||||
|
} inner_;
|
||||||
|
|
||||||
|
static_assert(sizeof(inner_.function_) == sizeof(inner_.raw_function_) + sizeof(inner_.adj));
|
||||||
|
};
|
||||||
|
|
||||||
template <FixedString, typename T>
|
template <FixedString, typename T>
|
||||||
struct Field {
|
struct Field {
|
||||||
[[gnu::always_inline]] T *operator->() { return field_; }
|
[[gnu::always_inline]] T *operator->() { return inner_.field_; }
|
||||||
[[gnu::always_inline]] T &operator*() { return *field_; }
|
[[gnu::always_inline]] T &operator*() { return *inner_.field_; }
|
||||||
[[gnu::always_inline]] operator bool() { return field_ != nullptr; }
|
[[gnu::always_inline]] operator bool() { return inner_.raw_field_ != nullptr; }
|
||||||
|
[[gnu::always_inline]] Field &operator=(void *field) {
|
||||||
|
inner_.raw_field_ = field;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
friend struct HookHandler;
|
inline static union {
|
||||||
T *field_;
|
void *raw_field_ = nullptr;
|
||||||
|
T *field_;
|
||||||
|
} inner_;
|
||||||
|
|
||||||
|
static_assert(sizeof(inner_.field_) == sizeof(inner_.raw_field_));
|
||||||
};
|
};
|
||||||
|
|
||||||
template <FixedString, typename>
|
template <FixedString, FuncType>
|
||||||
struct Hooker;
|
struct Hooker;
|
||||||
|
|
||||||
template <FixedString, typename, typename>
|
template <FixedString Sym, typename Ret, typename... Args>
|
||||||
struct MemberHooker;
|
struct Hooker<Sym, Ret(Args...)> : Function<Sym, Ret(Args...)> {
|
||||||
|
[[gnu::always_inline]] Hooker &operator=(void *function) {
|
||||||
|
Function<Sym, Ret(Args...)>::operator=(function);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
[[gnu::always_inline]] constexpr Hooker(Ret (*replace)(Args...)) {
|
||||||
|
replace_ = replace;
|
||||||
|
};
|
||||||
|
friend struct HookHandler;
|
||||||
|
template<FixedString S>
|
||||||
|
friend struct Symbol;
|
||||||
|
inline static Ret (*replace_)(Args...) = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Class, typename Return, typename T, typename... Args>
|
template <FixedString Sym, class This, typename Ret, typename... Args>
|
||||||
requires(std::is_same_v<T, void> || std::is_same_v<Class, T>)
|
struct Hooker<Sym, Ret(This::*)(Args...)> : Function<Sym, Ret(This::*)(Args...)> {
|
||||||
inline auto memfun_cast(Return (*func)(T *, Args...)) {
|
[[gnu::always_inline]] Hooker &operator=(void *function) {
|
||||||
union {
|
Function<Sym, Ret(This::*)(Args...)>::operator=(function);
|
||||||
Return (Class::*f)(Args...) const;
|
return *this;
|
||||||
|
}
|
||||||
struct {
|
private:
|
||||||
decltype(func) p;
|
[[gnu::always_inline]] constexpr Hooker(Ret (*replace)(This *, Args...)) {
|
||||||
std::ptrdiff_t adj;
|
replace_ = replace;
|
||||||
} data;
|
};
|
||||||
} u{.data = {func, 0}};
|
friend struct HookHandler;
|
||||||
static_assert(sizeof(u.f) == sizeof(u.data), "Try different T");
|
template<FixedString S>
|
||||||
return u.f;
|
friend struct Symbol;
|
||||||
}
|
inline static Ret (*replace_)(This *, Args...) = nullptr;
|
||||||
|
};
|
||||||
template <std::same_as<void> T, typename Return, typename... Args>
|
|
||||||
inline auto memfun_cast(Return (*func)(T *, Args...)) {
|
|
||||||
return memfun_cast<T>(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct HookHandler {
|
struct HookHandler {
|
||||||
HookHandler(const InitInfo &info) : info_(info) {}
|
HookHandler(const InitInfo &info) : info_(info) {}
|
||||||
template <FixedString Sym, typename This, typename Ret, typename... Args>
|
template <FixedString Sym, typename This, typename Ret, typename... Args>
|
||||||
[[gnu::always_inline]] bool dlsym(MemberFunction<Sym, This, Ret(Args...)> &function,
|
[[gnu::always_inline]] bool dlsym(Function<Sym, Ret(This::*)(Args...)> &function,
|
||||||
bool match_prefix = false) const {
|
bool match_prefix = false) const {
|
||||||
return function.function_ = memfun_cast<This>(
|
return function = dlsym<Sym>(match_prefix);
|
||||||
reinterpret_cast<Ret (*)(This *, Args...)>(dlsym<Sym>(match_prefix)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <FixedString Sym, typename Ret, typename... Args>
|
template <FixedString Sym, typename Ret, typename... Args>
|
||||||
[[gnu::always_inline]] bool dlsym(Function<Sym, Ret(Args...)> &function,
|
[[gnu::always_inline]] bool dlsym(Function<Sym, Ret(Args...)> &function,
|
||||||
bool match_prefix = false) const {
|
bool match_prefix = false) const {
|
||||||
return function.function_ = reinterpret_cast<Ret (*)(Args...)>(dlsym<Sym>(match_prefix));
|
return function = dlsym<Sym>(match_prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <FixedString Sym, typename T>
|
template <FixedString Sym, typename T>
|
||||||
[[gnu::always_inline]] bool dlsym(Field<Sym, T> &field, bool match_prefix = false) const {
|
[[gnu::always_inline]] bool dlsym(Field<Sym, T> &field, bool match_prefix = false) const {
|
||||||
return field.field_ = reinterpret_cast<T *>(dlsym<Sym>(match_prefix));
|
return field = dlsym<Sym>(match_prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <FixedString Sym, typename Ret, typename... Args>
|
template <FixedString Sym, typename Ret, typename... Args>
|
||||||
[[gnu::always_inline]] bool hook(Hooker<Sym, Ret(Args...)> &hooker) const {
|
[[gnu::always_inline]] bool hook(Hooker<Sym, Ret(Args...)> &hooker) const {
|
||||||
return hooker.function_ = reinterpret_cast<Ret (*)(Args...)>(
|
return hooker = hook(dlsym<Sym>(), reinterpret_cast<void *>(hooker.replace_));
|
||||||
hook(dlsym<Sym>(), reinterpret_cast<void *>(hooker.replace_)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <FixedString Sym, typename This, typename Ret, typename... Args>
|
template <FixedString Sym, typename This, typename Ret, typename... Args>
|
||||||
[[gnu::always_inline]] bool hook(MemberHooker<Sym, This, Ret(Args...)> &hooker) const {
|
[[gnu::always_inline]] bool hook(Hooker<Sym, Ret(This::*)(Args...)> &hooker) const {
|
||||||
return hooker.function_ = memfun_cast<This>(reinterpret_cast<Ret (*)(This *, Args...)>(
|
return hooker = hook(dlsym<Sym>(), reinterpret_cast<void *>(hooker.replace_));
|
||||||
hook(dlsym<Sym>(), reinterpret_cast<void *>(hooker.replace_))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T1, typename T2, typename... U>
|
template <typename T1, typename T2, typename... U>
|
||||||
@ -124,51 +184,77 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <FixedString Sym, typename Ret, typename... Args>
|
|
||||||
struct Function<Sym, Ret(Args...)> {
|
struct Dummy;
|
||||||
[[gnu::always_inline]] constexpr Ret operator()(Args... args) { return function_(args...); }
|
|
||||||
[[gnu::always_inline]] operator bool() { return function_ != nullptr; }
|
template<typename F>
|
||||||
auto operator&() const { return function_; }
|
concept Backup = std::is_function_v<std::remove_pointer_t<F>> || requires(F&& f) { { f(std::declval<Dummy*>()) } -> std::same_as<Dummy*>; };
|
||||||
Function &operator=(void *function) {
|
|
||||||
function_ = reinterpret_cast<decltype(function_)>(function);
|
template<typename F>
|
||||||
return *this;
|
concept MemBackup = std::is_function_v<std::remove_pointer_t<F>> || requires(F&& f) { { f(std::declval<Dummy*>()) } -> std::same_as<Dummy**>; };
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T return_t();
|
||||||
|
|
||||||
|
// for ndk 29+, use decltype(F::template operator()<&decltype([] static {})::operator()>)
|
||||||
|
// and remove Dummy, set MemBackup as std::is_member_function_pointer_v<F>
|
||||||
|
template<typename F, bool mem>
|
||||||
|
using Signature = decltype(F::template operator()<[](auto...a) static {
|
||||||
|
using D = std::conditional_t<mem, Dummy**, Dummy*>;
|
||||||
|
if constexpr ((false || ... || std::is_same_v<decltype(a), Dummy*>)) {
|
||||||
|
return return_t<D>();
|
||||||
|
} else {
|
||||||
|
return return_t<decltype(F::template operator()<[](auto...) -> D {}>(std::declval<decltype(a)>()...))>();
|
||||||
}
|
}
|
||||||
|
}>);
|
||||||
|
|
||||||
private:
|
template<FixedString S>
|
||||||
friend struct HookHandler;
|
struct Symbol {
|
||||||
Ret (*function_)(Args...) = nullptr;
|
template<typename T>
|
||||||
|
inline static decltype([]{
|
||||||
|
if constexpr (FuncType<T>) {
|
||||||
|
return Function<S, T>{};
|
||||||
|
} else {
|
||||||
|
return Field<S, T>{};
|
||||||
|
}
|
||||||
|
}()) as{};
|
||||||
|
|
||||||
|
[[no_unique_address]] struct Hook {
|
||||||
|
template<typename F>
|
||||||
|
requires(requires { std::declval<Signature<F, false>>(); })
|
||||||
|
auto operator->*(F&&) const {
|
||||||
|
using HookerType = Hooker<S, Signature<F, false>>;
|
||||||
|
return HookerType{static_cast<decltype(HookerType::replace_)>(&F::template operator()<HookerType::operator()>)};
|
||||||
|
};
|
||||||
|
template<typename F>
|
||||||
|
requires(requires { std::declval<Signature<F, true>>(); })
|
||||||
|
auto operator->*(F&&) const {
|
||||||
|
constexpr auto c = []<class This, typename Ret, typename... Args>(Ret(*f)(This*, Args...)) -> Ret(This::*)(Args...) {
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
using HookerType = Hooker<S, decltype(c.template operator()(std::declval<Signature<F, true>>()))>;
|
||||||
|
return HookerType{static_cast<decltype(HookerType::replace_)>(&F::template operator()<HookerType::operator()>)};
|
||||||
|
};
|
||||||
|
|
||||||
|
} hook;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <FixedString Sym, typename This, typename Ret, typename... Args>
|
template <FixedString S> constexpr Symbol<S> operator""_sym() {
|
||||||
struct MemberFunction<Sym, This, Ret(Args...)> {
|
return {};
|
||||||
[[gnu::always_inline]] constexpr Ret operator()(This *thiz, Args... args) {
|
}
|
||||||
return (reinterpret_cast<ThisType *>(thiz)->*function_)(args...);
|
|
||||||
}
|
|
||||||
[[gnu::always_inline]] operator bool() { return function_ != nullptr; }
|
|
||||||
|
|
||||||
private:
|
template<FixedString S, FixedString P>
|
||||||
friend struct HookHandler;
|
consteval auto operator|([[maybe_unused]] Symbol<S> a, [[maybe_unused]] Symbol<P> b) {
|
||||||
using ThisType = std::conditional_t<std::is_same_v<This, void>, MemberFunction, This>;
|
#if defined(__LP64__)
|
||||||
Ret (ThisType::*function_)(Args...) const = nullptr;
|
return b;
|
||||||
};
|
#else
|
||||||
|
return a;
|
||||||
template <FixedString Sym, typename Ret, typename... Args>
|
#endif
|
||||||
struct Hooker<Sym, Ret(Args...)> : Function<Sym, Ret(Args...)> {
|
}
|
||||||
[[gnu::always_inline]] constexpr Hooker(Ret (*replace)(Args...)) : replace_(replace) {};
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend struct HookHandler;
|
|
||||||
[[maybe_unused]] Ret (*replace_)(Args...) = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <FixedString Sym, typename This, typename Ret, typename... Args>
|
|
||||||
struct MemberHooker<Sym, This, Ret(Args...)> : MemberFunction<Sym, This, Ret(Args...)> {
|
|
||||||
[[gnu::always_inline]] constexpr MemberHooker(Ret (*replace)(This *, Args...))
|
|
||||||
: replace_(replace) {};
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend struct HookHandler;
|
|
||||||
[[maybe_unused]] Ret (*replace_)(This *, Args...) = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
"test"_sym.hook->*[]<MemBackup auto backup>(std::string *x) static -> char {
|
||||||
|
return backup(x);
|
||||||
|
};
|
||||||
|
}
|
||||||
} // namespace lsplant
|
} // namespace lsplant
|
||||||
|
@ -5,12 +5,10 @@ module;
|
|||||||
export module hook_helper;
|
export module hook_helper;
|
||||||
|
|
||||||
export namespace lsplant {
|
export namespace lsplant {
|
||||||
using lsplant::Field;
|
|
||||||
using lsplant::FixedString;
|
using lsplant::FixedString;
|
||||||
using lsplant::Function;
|
|
||||||
using lsplant::Hooker;
|
|
||||||
using lsplant::HookHandler;
|
using lsplant::HookHandler;
|
||||||
using lsplant::MemberFunction;
|
using lsplant::operator""_sym;
|
||||||
using lsplant::MemberHooker;
|
using lsplant::Backup;
|
||||||
using lsplant::memfun_cast;
|
using lsplant::MemBackup;
|
||||||
|
using lsplant::operator|;
|
||||||
} // namespace lsplant
|
} // namespace lsplant
|
||||||
|
Loading…
x
Reference in New Issue
Block a user