Workaround for UpdateMethodsCode inlined (#1754)
This commit is contained in:
parent
b311556b41
commit
2a258e3323
|
|
@ -34,9 +34,58 @@
|
||||||
namespace art {
|
namespace art {
|
||||||
|
|
||||||
class ClassLinker : public lspd::HookedObject {
|
class ClassLinker : public lspd::HookedObject {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline static ClassLinker *instance_;
|
[[gnu::always_inline]]
|
||||||
|
static auto MaybeDelayHook(void *clazz_ptr) {
|
||||||
|
std::vector<std::tuple<void*, void*>> out;
|
||||||
|
art::mirror::Class mirror_class(clazz_ptr);
|
||||||
|
auto class_def = mirror_class.GetClassDef();
|
||||||
|
if (!class_def) return out;
|
||||||
|
auto set = lspd::isClassHooked(class_def);
|
||||||
|
if (!set.empty()) [[unlikely]] {
|
||||||
|
LOGD("Pending hook for %p (%s)", clazz_ptr,
|
||||||
|
art::mirror::Class(clazz_ptr).GetDescriptor().c_str());
|
||||||
|
for (auto art_method : set) {
|
||||||
|
out.emplace_back(art_method, yahfa::getEntryPoint(art_method));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[gnu::always_inline]]
|
||||||
|
static void FixTrampoline(const std::vector<std::tuple<void*, void*>>& methods) {
|
||||||
|
for (const auto &[art_method, old_trampoline] : methods) {
|
||||||
|
auto *new_trampoline = yahfa::getEntryPoint(art_method);
|
||||||
|
auto *backup = lspd::isHooked(art_method);
|
||||||
|
if (backup && new_trampoline != old_trampoline) {
|
||||||
|
yahfa::setEntryPoint(backup, new_trampoline);
|
||||||
|
yahfa::setEntryPoint(art_method, old_trampoline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CREATE_MEM_HOOK_STUB_ENTRIES(
|
||||||
|
"_ZN3art11ClassLinker22FixupStaticTrampolinesENS_6ObjPtrINS_6mirror5ClassEEE",
|
||||||
|
void, FixupStaticTrampolines, (void * thiz, void * clazz_ptr), {
|
||||||
|
auto b = MaybeDelayHook(clazz_ptr);
|
||||||
|
backup(thiz, clazz_ptr);
|
||||||
|
FixTrampoline(b);
|
||||||
|
});
|
||||||
|
|
||||||
|
CREATE_MEM_HOOK_STUB_ENTRIES(
|
||||||
|
"_ZN3art11ClassLinker22FixupStaticTrampolinesEPNS_6ThreadENS_6ObjPtrINS_6mirror5ClassEEE",
|
||||||
|
void, FixupStaticTrampolinesWithThread,
|
||||||
|
(void * thiz, void * self, void * clazz_ptr), {
|
||||||
|
auto b = MaybeDelayHook(clazz_ptr);
|
||||||
|
backup(thiz, self, clazz_ptr);
|
||||||
|
FixTrampoline(b);
|
||||||
|
});
|
||||||
|
|
||||||
|
CREATE_MEM_FUNC_SYMBOL_ENTRY(void, MakeInitializedClassesVisiblyInitialized, void *thiz,
|
||||||
|
void *self, bool wait) {
|
||||||
|
if (MakeInitializedClassesVisiblyInitializedSym) [[likely]]
|
||||||
|
MakeInitializedClassesVisiblyInitializedSym(thiz, self, wait);
|
||||||
|
}
|
||||||
|
|
||||||
CREATE_MEM_FUNC_SYMBOL_ENTRY(void, SetEntryPointsToInterpreter, void *thiz,
|
CREATE_MEM_FUNC_SYMBOL_ENTRY(void, SetEntryPointsToInterpreter, void *thiz,
|
||||||
void *art_method) {
|
void *art_method) {
|
||||||
|
|
@ -66,21 +115,15 @@ namespace art {
|
||||||
});
|
});
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ClassLinker(void *thiz) : HookedObject(thiz) {}
|
|
||||||
|
|
||||||
inline static ClassLinker *Current() {
|
|
||||||
return instance_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ApiSensitive(Level.MIDDLE)
|
// @ApiSensitive(Level.MIDDLE)
|
||||||
inline static void Setup(const SandHook::ElfImg &handle) {
|
inline static void Setup(const SandHook::ElfImg &handle) {
|
||||||
instance_ = new ClassLinker(nullptr); // make it nullptr
|
|
||||||
|
|
||||||
RETRIEVE_MEM_FUNC_SYMBOL(SetEntryPointsToInterpreter,
|
RETRIEVE_MEM_FUNC_SYMBOL(SetEntryPointsToInterpreter,
|
||||||
"_ZNK3art11ClassLinker27SetEntryPointsToInterpreterEPNS_9ArtMethodE");
|
"_ZNK3art11ClassLinker27SetEntryPointsToInterpreterEPNS_9ArtMethodE");
|
||||||
|
|
||||||
lspd::HookSyms(handle, ShouldUseInterpreterEntrypoint, ShouldStayInSwitchInterpreter);
|
lspd::HookSyms(handle, ShouldUseInterpreterEntrypoint, ShouldStayInSwitchInterpreter);
|
||||||
|
|
||||||
|
lspd::HookSyms(handle, FixupStaticTrampolinesWithThread, FixupStaticTrampolines);
|
||||||
|
|
||||||
RETRIEVE_FUNC_SYMBOL(art_quick_to_interpreter_bridge, "art_quick_to_interpreter_bridge");
|
RETRIEVE_FUNC_SYMBOL(art_quick_to_interpreter_bridge, "art_quick_to_interpreter_bridge");
|
||||||
RETRIEVE_FUNC_SYMBOL(art_quick_generic_jni_trampoline, "art_quick_generic_jni_trampoline");
|
RETRIEVE_FUNC_SYMBOL(art_quick_generic_jni_trampoline, "art_quick_generic_jni_trampoline");
|
||||||
|
|
||||||
|
|
@ -89,7 +132,7 @@ namespace art {
|
||||||
}
|
}
|
||||||
|
|
||||||
[[gnu::always_inline]]
|
[[gnu::always_inline]]
|
||||||
void SetEntryPointsToInterpreter(void *art_method) const {
|
static void SetEntryPointsToInterpreter(void *art_method) {
|
||||||
if (art_quick_to_interpreter_bridgeSym && art_quick_generic_jni_trampolineSym) [[likely]] {
|
if (art_quick_to_interpreter_bridgeSym && art_quick_generic_jni_trampolineSym) [[likely]] {
|
||||||
if (yahfa::getAccessFlags(art_method) & yahfa::kAccNative) [[unlikely]] {
|
if (yahfa::getAccessFlags(art_method) & yahfa::kAccNative) [[unlikely]] {
|
||||||
yahfa::setEntryPoint(art_method,
|
yahfa::setEntryPoint(art_method,
|
||||||
|
|
@ -99,7 +142,7 @@ namespace art {
|
||||||
reinterpret_cast<void *>(art_quick_to_interpreter_bridgeSym));
|
reinterpret_cast<void *>(art_quick_to_interpreter_bridgeSym));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetEntryPointsToInterpreter(thiz_, art_method);
|
SetEntryPointsToInterpreter(nullptr, art_method);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of LSPosed.
|
|
||||||
*
|
|
||||||
* LSPosed is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* LSPosed is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LSPOSED_INSTRUMENTATION_H
|
|
||||||
#define LSPOSED_INSTRUMENTATION_H
|
|
||||||
|
|
||||||
#include "base/object.h"
|
|
||||||
|
|
||||||
namespace art {
|
|
||||||
namespace instrumentation {
|
|
||||||
|
|
||||||
CREATE_MEM_HOOK_STUB_ENTRIES(
|
|
||||||
"_ZN3art15instrumentation15Instrumentation21UpdateMethodsCodeImplEPNS_9ArtMethodEPKv",
|
|
||||||
void, UpdateMethodsCodeImpl, (void * thiz, void * art_method, const void *quick_code), {
|
|
||||||
if (auto backup = lspd::isHooked(art_method);
|
|
||||||
backup && yahfa::getEntryPoint(art_method) != quick_code) [[unlikely]] {
|
|
||||||
LOGD("redirect update method code for hooked method %s to its backup",
|
|
||||||
art_method::PrettyMethod(art_method).c_str());
|
|
||||||
art_method = backup;
|
|
||||||
}
|
|
||||||
backup(thiz, art_method, quick_code);
|
|
||||||
});
|
|
||||||
|
|
||||||
CREATE_MEM_HOOK_STUB_ENTRIES(
|
|
||||||
"_ZN3art15instrumentation15Instrumentation17UpdateMethodsCodeEPNS_9ArtMethodEPKv",
|
|
||||||
void, UpdateMethodsCode, (void * thiz, void * art_method, const void *quick_code), {
|
|
||||||
if (auto backup = lspd::isHooked(art_method);
|
|
||||||
backup && yahfa::getEntryPoint(art_method) != quick_code) [[unlikely]] {
|
|
||||||
LOGD("redirect update method code for hooked method %s to its backup",
|
|
||||||
art_method::PrettyMethod(art_method).c_str());
|
|
||||||
art_method = backup;
|
|
||||||
}
|
|
||||||
// avoid calling our hook again
|
|
||||||
if (UpdateMethodsCodeImpl.backup) {
|
|
||||||
UpdateMethodsCodeImpl.backup(thiz, art_method, quick_code);
|
|
||||||
} else {
|
|
||||||
backup(thiz, art_method, quick_code);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
inline void DisableUpdateHookedMethodsCode(const SandHook::ElfImg &handle) {
|
|
||||||
lspd::HookSym(handle, UpdateMethodsCode);
|
|
||||||
lspd::HookSym(handle, UpdateMethodsCodeImpl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif //LSPOSED_INSTRUMENTATION_H
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace lspd {
|
||||||
LSP_DEF_NATIVE_METHOD(void, ClassLinker, setEntryPointsToInterpreter, jobject method) {
|
LSP_DEF_NATIVE_METHOD(void, ClassLinker, setEntryPointsToInterpreter, jobject method) {
|
||||||
void *reflected_method = yahfa::getArtMethod(env, method);
|
void *reflected_method = yahfa::getArtMethod(env, method);
|
||||||
LOGD("deoptimizing method: %p", reflected_method);
|
LOGD("deoptimizing method: %p", reflected_method);
|
||||||
art::ClassLinker::Current()->SetEntryPointsToInterpreter(reflected_method);
|
art::ClassLinker::SetEntryPointsToInterpreter(reflected_method);
|
||||||
LOGD("method deoptimized: %p", reflected_method);
|
LOGD("method deoptimized: %p", reflected_method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,9 @@ namespace lspd {
|
||||||
|
|
||||||
std::vector<std::pair<void *, void *>> jit_movements_;
|
std::vector<std::pair<void *, void *>> jit_movements_;
|
||||||
std::shared_mutex jit_movements_lock_;
|
std::shared_mutex jit_movements_lock_;
|
||||||
|
|
||||||
|
std::unordered_map<const void *, std::unordered_set<void*>> hooked_classes_;
|
||||||
|
std::shared_mutex hooked_classes_lock_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* isHooked(void *art_method) {
|
void* isHooked(void *art_method) {
|
||||||
|
|
@ -48,10 +51,27 @@ namespace lspd {
|
||||||
}
|
}
|
||||||
|
|
||||||
void recordHooked(void *art_method, void *backup) {
|
void recordHooked(void *art_method, void *backup) {
|
||||||
std::unique_lock lk(hooked_methods_lock_);
|
{
|
||||||
hooked_methods_.emplace(art_method, backup);
|
std::unique_lock lk(hooked_methods_lock_);
|
||||||
|
hooked_methods_.emplace(art_method, backup);
|
||||||
|
}
|
||||||
|
auto clazz = art::mirror::Class(reinterpret_cast<void*>(*reinterpret_cast<uint32_t*>(art_method)));
|
||||||
|
{
|
||||||
|
std::unique_lock lk(hooked_classes_lock_);
|
||||||
|
hooked_classes_[clazz.GetClassDef()].emplace(art_method);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::unordered_set<void*> &isClassHooked(void *clazz) {
|
||||||
|
static std::unordered_set<void*> empty;
|
||||||
|
std::shared_lock lk(hooked_classes_lock_);
|
||||||
|
if (auto found = hooked_classes_.find(clazz); found != hooked_classes_.end()) {
|
||||||
|
return found->second;
|
||||||
|
}
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void recordJitMovement(void *target, void *backup) {
|
void recordJitMovement(void *target, void *backup) {
|
||||||
std::unique_lock lk(jit_movements_lock_);
|
std::unique_lock lk(jit_movements_lock_);
|
||||||
jit_movements_.emplace_back(target, backup);
|
jit_movements_.emplace_back(target, backup);
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "jni.h"
|
#include "jni.h"
|
||||||
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -30,6 +31,8 @@ namespace lspd {
|
||||||
|
|
||||||
std::vector<std::pair<void*, void*>> getJitMovements();
|
std::vector<std::pair<void*, void*>> getJitMovements();
|
||||||
|
|
||||||
|
const std::unordered_set<void*> &isClassHooked(void *clazz);
|
||||||
|
|
||||||
void RegisterYahfa(JNIEnv *);
|
void RegisterYahfa(JNIEnv *);
|
||||||
|
|
||||||
} // namespace lspd
|
} // namespace lspd
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@
|
||||||
#include "art/runtime/class_linker.h"
|
#include "art/runtime/class_linker.h"
|
||||||
#include "art/runtime/thread.h"
|
#include "art/runtime/thread.h"
|
||||||
#include "art/runtime/hidden_api.h"
|
#include "art/runtime/hidden_api.h"
|
||||||
#include "art/runtime/instrumentation.h"
|
|
||||||
#include "art/runtime/thread_list.h"
|
#include "art/runtime/thread_list.h"
|
||||||
#include "art/runtime/gc/scoped_gc_critical_section.h"
|
#include "art/runtime/gc/scoped_gc_critical_section.h"
|
||||||
#include "art/runtime/jit/jit_code_cache.h"
|
#include "art/runtime/jit/jit_code_cache.h"
|
||||||
|
|
@ -58,7 +57,6 @@ namespace lspd {
|
||||||
art::ClassLinker::Setup(handle_libart);
|
art::ClassLinker::Setup(handle_libart);
|
||||||
art::mirror::Class::Setup(handle_libart);
|
art::mirror::Class::Setup(handle_libart);
|
||||||
art::JNIEnvExt::Setup(handle_libart);
|
art::JNIEnvExt::Setup(handle_libart);
|
||||||
art::instrumentation::DisableUpdateHookedMethodsCode(handle_libart);
|
|
||||||
art::thread_list::ScopedSuspendAll::Setup(handle_libart);
|
art::thread_list::ScopedSuspendAll::Setup(handle_libart);
|
||||||
art::gc::ScopedGCCriticalSection::Setup(handle_libart);
|
art::gc::ScopedGCCriticalSection::Setup(handle_libart);
|
||||||
art::jit::jit_code_cache::Setup(handle_libart);
|
art::jit::jit_code_cache::Setup(handle_libart);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue