Fix art_quick_* not found

Close #136
This commit is contained in:
LoveSy 2025-02-26 20:58:24 +08:00
parent 8c3c6e6b2c
commit ce08314ca3
No known key found for this signature in database
5 changed files with 106 additions and 61 deletions

View File

@ -2,6 +2,7 @@ module;
#include <atomic>
#include <string>
#include <memory>
#include "logging.hpp"
@ -98,6 +99,18 @@ public:
SetAccessFlags(access_flags);
}
void SetNative() {
auto access_flags = GetAccessFlags();
access_flags |= kAccNative;
SetAccessFlags(access_flags);
}
void SetNonNative() {
auto access_flags = GetAccessFlags();
access_flags &= ~kAccNative;
SetAccessFlags(access_flags);
}
bool IsPrivate() { return GetAccessFlags() & kAccPrivate; }
bool IsProtected() { return GetAccessFlags() & kAccProtected; }
bool IsPublic() { return GetAccessFlags() & kAccPublic; }
@ -155,6 +168,12 @@ public:
reinterpret_cast<uintptr_t>(this) + declaring_class_offset));
}
std::unique_ptr<ArtMethod> Clone() {
auto *method = reinterpret_cast<ArtMethod*>(::operator new(art_method_size));
method->CopyFrom(this);
return std::unique_ptr<ArtMethod>(method);
}
void BackupTo(ArtMethod *backup) {
SetNonCompilable();

View File

@ -12,6 +12,7 @@ import common;
import clazz;
import handle;
import hook_helper;
import runtime;
namespace lsplant::art {
export class ClassLinker {
@ -35,6 +36,9 @@ private:
inline static Function<"art_quick_generic_jni_trampoline", void(void *)>
art_quick_generic_jni_trampoline_;
inline static Function<"_ZN3art15instrumentationL19GetOptimizedCodeForEPNS_9ArtMethodE",
void *(ArtMethod *)> GetOptimizedCodeFor_;
inline static art::ArtMethod *MayGetBackup(art::ArtMethod *method) {
if (auto backup = IsHooked(method); backup) [[unlikely]] {
method = backup;
@ -161,7 +165,7 @@ private:
};
public:
static bool Init(const HookHandler &handler) {
static bool Init(JNIEnv *env, const HookHandler &handler) {
int sdk_int = GetAndroidApiLevel();
if (sdk_int >= __ANDROID_API_N__ && sdk_int < __ANDROID_API_T__) {
@ -187,16 +191,32 @@ public:
}
}
if (!handler.dlsym(SetEntryPointsToInterpreter_)) [[unlikely]] {
if (handler.dlsym(GetOptimizedCodeFor_, true)) [[likely]] {
auto obj = JNI_FindClass(env, "java/lang/Object");
if (!obj) {
return false;
}
auto method = JNI_GetMethodID(env, obj, "equals", "(Ljava/lang/Object;)Z");
if (!method) {
return false;
}
auto dummy = ArtMethod::FromReflectedMethod(
env, JNI_ToReflectedMethod(env, obj, method, false).get())->Clone();
JavaDebuggableGuard guard;
dummy->SetNonNative();
art_quick_to_interpreter_bridge_ = GetOptimizedCodeFor_(dummy.get());
dummy->SetNative();
art_quick_generic_jni_trampoline_ = GetOptimizedCodeFor_(dummy.get());
} else if (!handler.dlsym(SetEntryPointsToInterpreter_)) [[unlikely]] {
if (!handler.dlsym(art_quick_to_interpreter_bridge_)) [[unlikely]] {
return false;
}
if (!handler.dlsym(art_quick_generic_jni_trampoline_)) [[unlikely]] {
return false;
}
LOGD("art_quick_to_interpreter_bridge = %p", &art_quick_to_interpreter_bridge_);
LOGD("art_quick_generic_jni_trampoline = %p", &art_quick_generic_jni_trampoline_);
}
LOGD("art_quick_to_interpreter_bridge = %p", &art_quick_to_interpreter_bridge_);
LOGD("art_quick_generic_jni_trampoline = %p", &art_quick_generic_jni_trampoline_);
return true;
}

View File

@ -1,6 +1,7 @@
module;
#include <array>
#include <atomic>
#include "logging.hpp"
@ -87,4 +88,56 @@ public:
return true;
}
};
export struct JavaDebuggableGuard {
JavaDebuggableGuard() {
while (true) {
size_t expected = 0;
if (count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel,
std::memory_order_acquire)) {
Runtime::Current()->SetJavaDebuggable(
Runtime::RuntimeDebugState::kJavaDebuggableAtInit);
count.fetch_add(1, std::memory_order_release);
count.notify_all();
break;
}
if (expected == 1) {
count.wait(expected, std::memory_order_acquire);
continue;
}
if (count.compare_exchange_strong(expected, expected + 1, std::memory_order_acq_rel,
std::memory_order_relaxed)) {
break;
}
}
}
~JavaDebuggableGuard() {
while (true) {
size_t expected = 2;
if (count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel,
std::memory_order_acquire)) {
Runtime::Current()->SetJavaDebuggable(
Runtime::RuntimeDebugState::kNonJavaDebuggable);
count.fetch_sub(1, std::memory_order_release);
count.notify_all();
break;
}
if (expected == 1) {
count.wait(expected, std::memory_order_acquire);
continue;
}
if (count.compare_exchange_strong(expected, expected - 1, std::memory_order_acq_rel,
std::memory_order_relaxed)) {
break;
}
}
}
private:
inline static std::atomic_size_t count{0};
static_assert(std::atomic_size_t::is_always_lock_free, "Unsupported architecture");
static_assert(std::is_same_v<std::atomic_size_t::value_type, size_t>,
"Unsupported architecture");
};
} // namespace lsplant::art

View File

@ -129,6 +129,10 @@ struct Function<Sym, Ret(Args...)> {
[[gnu::always_inline]] constexpr Ret operator()(Args... args) { return function_(args...); }
[[gnu::always_inline]] operator bool() { return function_ != nullptr; }
auto operator&() const { return function_; }
Function &operator=(void *function) {
function_ = reinterpret_cast<decltype(function_)>(function);
return *this;
}
private:
friend struct HookHandler;

View File

@ -50,6 +50,7 @@ using art::jit::JitCodeCache;
using art::jni::JniIdManager;
using art::mirror::Class;
using art::thread_list::ScopedSuspendAll;
using art::JavaDebuggableGuard;
using namespace std::string_view_literals;
@ -272,7 +273,11 @@ bool InitNative(JNIEnv *env, const HookHandler &handler) {
LOGE("Failed to init mirror class");
return false;
}
if (!ClassLinker::Init(handler)) {
if (!Runtime::Init(handler)) {
LOGE("Failed to init runtime");
return false;
}
if (!ClassLinker::Init(env, handler)) {
LOGE("Failed to init class linker");
return false;
}
@ -304,10 +309,6 @@ bool InitNative(JNIEnv *env, const HookHandler &handler) {
LOGE("Failed to init jni id manager");
return false;
}
if (!Runtime::Init(handler)) {
LOGE("Failed to init runtime");
return false;
}
// This should always be the last one
if (IsJavaDebuggable(env)) {
@ -318,58 +319,6 @@ bool InitNative(JNIEnv *env, const HookHandler &handler) {
return true;
}
struct JavaDebuggableGuard {
JavaDebuggableGuard() {
while (true) {
size_t expected = 0;
if (count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel,
std::memory_order_acquire)) {
Runtime::Current()->SetJavaDebuggable(
Runtime::RuntimeDebugState::kJavaDebuggableAtInit);
count.fetch_add(1, std::memory_order_release);
count.notify_all();
break;
}
if (expected == 1) {
count.wait(expected, std::memory_order_acquire);
continue;
}
if (count.compare_exchange_strong(expected, expected + 1, std::memory_order_acq_rel,
std::memory_order_relaxed)) {
break;
}
}
}
~JavaDebuggableGuard() {
while (true) {
size_t expected = 2;
if (count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel,
std::memory_order_acquire)) {
Runtime::Current()->SetJavaDebuggable(
Runtime::RuntimeDebugState::kNonJavaDebuggable);
count.fetch_sub(1, std::memory_order_release);
count.notify_all();
break;
}
if (expected == 1) {
count.wait(expected, std::memory_order_acquire);
continue;
}
if (count.compare_exchange_strong(expected, expected - 1, std::memory_order_acq_rel,
std::memory_order_relaxed)) {
break;
}
}
}
private:
inline static std::atomic_size_t count{0};
static_assert(std::atomic_size_t::is_always_lock_free, "Unsupported architecture");
static_assert(std::is_same_v<std::atomic_size_t::value_type, size_t>,
"Unsupported architecture");
};
std::tuple<jclass, jfieldID, jmethodID, jmethodID> BuildDex(JNIEnv *env, jobject class_loader,
std::string_view shorty, bool is_static,
std::string_view method_name,