Refactor symbol define and use static operator() (#142)

This commit is contained in:
LoveSy 2025-03-05 14:49:47 +08:00 committed by GitHub
parent 4a2293e222
commit c54fb307f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 375 additions and 304 deletions

View File

@ -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+")

View File

@ -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:

View File

@ -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_) {

View File

@ -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);
}; };

View File

@ -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,

View File

@ -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) {

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -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;

View File

@ -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() {

View File

@ -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) {

View File

@ -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

View File

@ -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