diff --git a/dex2oat/src/main/cpp/CMakeLists.txt b/dex2oat/src/main/cpp/CMakeLists.txt index bff9855f3..b181e3ffb 100644 --- a/dex2oat/src/main/cpp/CMakeLists.txt +++ b/dex2oat/src/main/cpp/CMakeLists.txt @@ -1,12 +1,14 @@ cmake_minimum_required(VERSION 3.10) project(dex2oat) -add_executable(dex2oat dex2oat.c) -add_library(oat_hook SHARED oat_hook.cpp) +add_executable(dex2oat dex2oat.cpp) +add_library(oat_hook SHARED oat_hook.cpp oat.cpp) OPTION(LSPLT_BUILD_SHARED OFF) add_subdirectory(${EXTERNAL_ROOT}/lsplt/lsplt/src/main/jni external) +target_include_directories(oat_hook PUBLIC include) +target_include_directories(dex2oat PUBLIC include) target_link_libraries(dex2oat log) target_link_libraries(oat_hook log lsplt_static) diff --git a/dex2oat/src/main/cpp/dex2oat.c b/dex2oat/src/main/cpp/dex2oat.cpp similarity index 100% rename from dex2oat/src/main/cpp/dex2oat.c rename to dex2oat/src/main/cpp/dex2oat.cpp diff --git a/dex2oat/src/main/cpp/include/base_macros.h b/dex2oat/src/main/cpp/include/base_macros.h new file mode 100644 index 000000000..3399f2fb8 --- /dev/null +++ b/dex2oat/src/main/cpp/include/base_macros.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include // for size_t +#include // for TEMP_FAILURE_RETRY + +#include + +// bionic and glibc both have TEMP_FAILURE_RETRY, but eg Mac OS' libc doesn't. +#ifndef TEMP_FAILURE_RETRY +#define TEMP_FAILURE_RETRY(exp) \ + ({ \ + decltype(exp) _rc; \ + do { \ + _rc = (exp); \ + } while (_rc == -1 && errno == EINTR); \ + _rc; \ + }) +#endif + +// A macro to disallow the copy constructor and operator= functions +// This must be placed in the private: declarations for a class. +// +// For disallowing only assign or copy, delete the relevant operator or +// constructor, for example: +// void operator=(const TypeName&) = delete; +// Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken +// semantically, one should either use disallow both or neither. Try to +// avoid these in new code. +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName &) = delete; \ + void operator=(const TypeName &) = delete + +// A macro to disallow all the implicit constructors, namely the +// default constructor, copy constructor and operator= functions. +// +// This should be used in the private: declarations for a class +// that wants to prevent anyone from instantiating it. This is +// especially useful for classes containing only static methods. +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName() = delete; \ + DISALLOW_COPY_AND_ASSIGN(TypeName) + +// The arraysize(arr) macro returns the # of elements in an array arr. +// The expression is a compile-time constant, and therefore can be +// used in defining new arrays, for example. If you use arraysize on +// a pointer by mistake, you will get a compile-time error. +// +// One caveat is that arraysize() doesn't accept any array of an +// anonymous type or a type defined inside a function. In these rare +// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is +// due to a limitation in C++'s template system. The limitation might +// eventually be removed, but it hasn't happened yet. + +// This template function declaration is used in defining arraysize. +// Note that the function doesn't need an implementation, as we only +// use its type. +template +char (&ArraySizeHelper(T (&array)[N]))[N]; // NOLINT(readability/casting) + +#define arraysize(array) (sizeof(ArraySizeHelper(array))) + +#define SIZEOF_MEMBER(t, f) sizeof(std::declval().f) + +// Changing this definition will cause you a lot of pain. A majority of +// vendor code defines LIKELY and UNLIKELY this way, and includes +// this header through an indirect path. +#define LIKELY(exp) (__builtin_expect((exp) != 0, true)) +#define UNLIKELY(exp) (__builtin_expect((exp) != 0, false)) + +#define WARN_UNUSED __attribute__((warn_unused_result)) + +// A deprecated function to call to create a false use of the parameter, for +// example: +// int foo(int x) { UNUSED(x); return 10; } +// to avoid compiler warnings. Going forward we prefer ATTRIBUTE_UNUSED. +template +void UNUSED(const T &...) {} + +// An attribute to place on a parameter to a function, for example: +// int foo(int x ATTRIBUTE_UNUSED) { return 10; } +// to avoid compiler warnings. +#define ATTRIBUTE_UNUSED __attribute__((__unused__)) + +// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through +// between switch labels: +// switch (x) { +// case 40: +// case 41: +// if (truth_is_out_there) { +// ++x; +// FALLTHROUGH_INTENDED; // Use instead of/along with annotations in +// // comments. +// } else { +// return x; +// } +// case 42: +// ... +// +// As shown in the example above, the FALLTHROUGH_INTENDED macro should be +// followed by a semicolon. It is designed to mimic control-flow statements +// like 'break;', so it can be placed in most places where 'break;' can, but +// only if there are no statements on the execution path between it and the +// next switch label. +// +// When compiled with clang, the FALLTHROUGH_INTENDED macro is expanded to +// [[clang::fallthrough]] attribute, which is analysed when performing switch +// labels fall-through diagnostic ('-Wimplicit-fallthrough'). See clang +// documentation on language extensions for details: +// http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough +// +// When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no +// effect on diagnostics. +// +// In either case this macro has no effect on runtime behavior and performance +// of code. +#ifndef FALLTHROUGH_INTENDED +#define FALLTHROUGH_INTENDED [[fallthrough]] // NOLINT +#endif + +// Current ABI string +#if defined(__arm__) +#define ABI_STRING "arm" +#elif defined(__aarch64__) +#define ABI_STRING "arm64" +#elif defined(__i386__) +#define ABI_STRING "x86" +#elif defined(__riscv) +#define ABI_STRING "riscv64" +#elif defined(__x86_64__) +#define ABI_STRING "x86_64" +#endif diff --git a/dex2oat/src/main/cpp/logging.h b/dex2oat/src/main/cpp/include/logging.h similarity index 100% rename from dex2oat/src/main/cpp/logging.h rename to dex2oat/src/main/cpp/include/logging.h diff --git a/dex2oat/src/main/cpp/include/macros.h b/dex2oat/src/main/cpp/include/macros.h new file mode 100644 index 000000000..f025b6105 --- /dev/null +++ b/dex2oat/src/main/cpp/include/macros.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_LIBARTBASE_BASE_MACROS_H_ +#define ART_LIBARTBASE_BASE_MACROS_H_ + +#include // for size_t +#include // for TEMP_FAILURE_RETRY + +// Declare a friend relationship in a class with a test. Used rather that FRIEND_TEST to avoid +// globally importing gtest/gtest.h into the main ART header files. +#define ART_FRIEND_TEST(test_set_name, individual_test) \ + friend class test_set_name##_##individual_test##_Test + +// Declare a friend relationship in a class with a typed test. +#define ART_FRIEND_TYPED_TEST(test_set_name, individual_test) \ + template \ + ART_FRIEND_TEST(test_set_name, individual_test) + +// Shorthand for formatting with compile time checking of the format string +#define ART_FORMAT(str, ...) ::fmt::format(FMT_STRING(str), __VA_ARGS__) + +// A macro to disallow new and delete operators for a class. It goes in the private: declarations. +// NOTE: Providing placement new (and matching delete) for constructing container elements. +#define DISALLOW_ALLOCATION() \ +public: \ + NO_RETURN ALWAYS_INLINE void operator delete(void*, size_t) { UNREACHABLE(); } \ + ALWAYS_INLINE void* operator new(size_t, void* ptr) noexcept { return ptr; } \ + ALWAYS_INLINE void operator delete(void*, void*) noexcept {} \ + \ +private: \ + void* operator new(size_t) = delete // NOLINT + +// offsetof is not defined by the spec on types with non-standard layout, +// however it is implemented by compilers in practice. +// (note that reinterpret_cast is not valid constexpr) +// +// Alternative approach would be something like: +// #define OFFSETOF_HELPER(t, f) \ +// (reinterpret_cast(&reinterpret_cast(16)->f) - static_cast(16u)) +// #define OFFSETOF_MEMBER(t, f) \ +// (__builtin_constant_p(OFFSETOF_HELPER(t,f)) ? OFFSETOF_HELPER(t,f) : OFFSETOF_HELPER(t,f)) +#define OFFSETOF_MEMBER(t, f) offsetof(t, f) + +#define OFFSETOF_MEMBERPTR(t, f) \ + (reinterpret_cast(&(reinterpret_cast(16)->*f)) - \ + static_cast(16)) // NOLINT + +#define ALIGNED(x) __attribute__((__aligned__(x))) +#define PACKED(x) __attribute__((__aligned__(x), __packed__)) + +// Stringify the argument. +#define QUOTE(x) #x +#define STRINGIFY(x) QUOTE(x) + +// Append tokens after evaluating. +#define APPEND_TOKENS_AFTER_EVAL_2(a, b) a##b +#define APPEND_TOKENS_AFTER_EVAL(a, b) APPEND_TOKENS_AFTER_EVAL_2(a, b) + +#ifndef NDEBUG +#define ALWAYS_INLINE +#define FLATTEN +#else +#define ALWAYS_INLINE __attribute__((always_inline)) +#define FLATTEN __attribute__((flatten)) +#endif + +#define NO_STACK_PROTECTOR __attribute__((no_stack_protector)) + +// clang doesn't like attributes on lambda functions. It would be nice to say: +// #define ALWAYS_INLINE_LAMBDA ALWAYS_INLINE +#define ALWAYS_INLINE_LAMBDA + +#define NO_INLINE __attribute__((noinline)) + +#if defined(__APPLE__) +#define HOT_ATTR +#define COLD_ATTR +#else +#define HOT_ATTR __attribute__((hot)) +#define COLD_ATTR __attribute__((cold)) +#endif + +#define PURE __attribute__((__pure__)) + +// Define that a position within code is unreachable, for example: +// int foo () { LOG(FATAL) << "Don't call me"; UNREACHABLE(); } +// without the UNREACHABLE a return statement would be necessary. +#define UNREACHABLE __builtin_unreachable + +// Add the C++11 noreturn attribute. +#define NO_RETURN [[noreturn]] // NOLINT[whitespace/braces] [5] + +// Annotalysis thread-safety analysis support. Things that are not in base. + +#define LOCKABLE CAPABILITY("mutex") +#define SHARED_LOCKABLE SHARED_CAPABILITY("mutex") + +// Some of the libs (e.g. libarttest(d)) require more public symbols when built +// in debug configuration. +// Using symbol visibility only for release builds allows to reduce the list of +// exported symbols and eliminates the need to check debug build configurations +// when changing the exported symbols. +#ifdef NDEBUG +#define HIDDEN __attribute__((visibility("hidden"))) +#define PROTECTED __attribute__((visibility("protected"))) +#define EXPORT __attribute__((visibility("default"))) +#else +#define HIDDEN +#define PROTECTED +#define EXPORT +#endif + +// Protected symbols must be declared with "protected" visibility attribute when +// building the library and "default" visibility when referred to from external +// libraries/binaries. Otherwise, the external code will expect the symbol to be +// defined locally and fail to link. +#ifdef BUILDING_LIBART +#define LIBART_PROTECTED PROTECTED +#else +#define LIBART_PROTECTED EXPORT +#endif + +// Some global variables shouldn't be visible outside libraries declaring them. +// The attribute allows hiding them, so preventing direct access. +#define ALWAYS_HIDDEN __attribute__((visibility("hidden"))) + +#endif // ART_LIBARTBASE_BASE_MACROS_H_ diff --git a/dex2oat/src/main/cpp/include/oat.h b/dex2oat/src/main/cpp/include/oat.h new file mode 100644 index 000000000..375e90299 --- /dev/null +++ b/dex2oat/src/main/cpp/include/oat.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_OAT_OAT_H_ +#define ART_RUNTIME_OAT_OAT_H_ + +#include +#include +#include +#include + +#include "base_macros.h" +#include "macros.h" + +namespace art { + +enum class InstructionSet; + +class EXPORT PACKED(4) OatHeader { +public: + static constexpr std::array kOatMagic{{'o', 'a', 't', '\n'}}; + // Last oat version changed reason: Ensure oat checksum determinism across hosts and devices. + static constexpr std::array kOatVersion{{'2', '5', '9', '\0'}}; + + static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; + static constexpr const char* kDebuggableKey = "debuggable"; + static constexpr const char* kNativeDebuggableKey = "native-debuggable"; + static constexpr const char* kCompilerFilter = "compiler-filter"; + static constexpr const char* kClassPathKey = "classpath"; + static constexpr const char* kBootClassPathKey = "bootclasspath"; + static constexpr const char* kBootClassPathChecksumsKey = "bootclasspath-checksums"; + static constexpr const char* kApexVersionsKey = "apex-versions"; + static constexpr const char* kConcurrentCopying = "concurrent-copying"; + static constexpr const char* kCompilationReasonKey = "compilation-reason"; + static constexpr const char* kRequiresImage = "requires-image"; + + // Fields listed here are key value store fields that are deterministic across hosts and + // devices, meaning they should have exactly the same value when the oat file is generated on + // different hosts and devices for the same app / boot image and for the same device model with + // the same compiler options. If you are adding a new field that doesn't hold this property, put + // it in `kNonDeterministicFieldsAndLengths` and assign a length limit. + // + // When writing the oat header, the non-deterministic fields are padded to their length limits + // and excluded from the oat checksum computation. This makes the oat checksum deterministic + // across hosts and devices, which is important for Cloud Compilation, where we generate an oat + // file on a host and use it on a device. + static constexpr std::array kDeterministicFields{ + kDebuggableKey, kNativeDebuggableKey, kCompilerFilter, + kClassPathKey, kBootClassPathKey, kBootClassPathChecksumsKey, + kConcurrentCopying, kCompilationReasonKey, kRequiresImage, + }; + + static constexpr std::array, 2> + kNonDeterministicFieldsAndLengths{ + std::make_pair(kDex2OatCmdLineKey, 2048), + std::make_pair(kApexVersionsKey, 1024), + }; + + static constexpr const char kTrueValue[] = "true"; + static constexpr const char kFalseValue[] = "false"; + + static constexpr size_t Get_key_value_store_size_Offset() { + return offsetof(OatHeader, key_value_store_size_); + } + static constexpr size_t Get_key_value_store_Offset() { + return offsetof(OatHeader, key_value_store_); + } + + uint32_t GetKeyValueStoreSize() const; + const uint8_t* GetKeyValueStore() const; + + void SetKeyValueStoreSize(uint32_t new_size); + + void ComputeChecksum(/*inout*/ uint32_t* checksum) const; + +private: + std::array magic_; + std::array version_; + uint32_t oat_checksum_; + + InstructionSet instruction_set_; + uint32_t instruction_set_features_bitmap_; + uint32_t dex_file_count_; + uint32_t oat_dex_files_offset_; + uint32_t bcp_bss_info_offset_; + // Offset of the oat header (i.e. start of the oat data) in the ELF file. + // It is used to additional validation of the oat header as it is not + // page-aligned in the memory. + uint32_t base_oat_offset_; + uint32_t executable_offset_; + uint32_t jni_dlsym_lookup_trampoline_offset_; + uint32_t jni_dlsym_lookup_critical_trampoline_offset_; + uint32_t quick_generic_jni_trampoline_offset_; + uint32_t quick_imt_conflict_trampoline_offset_; + uint32_t quick_resolution_trampoline_offset_; + uint32_t quick_to_interpreter_bridge_offset_; + uint32_t nterp_trampoline_offset_; + + uint32_t key_value_store_size_; + uint8_t key_value_store_[0]; // note variable width data at end + + DISALLOW_COPY_AND_ASSIGN(OatHeader); +}; +} // namespace art +#endif // ART_RUNTIME_OAT_OAT_H_ diff --git a/dex2oat/src/main/cpp/oat.cpp b/dex2oat/src/main/cpp/oat.cpp new file mode 100644 index 000000000..c50bb65fd --- /dev/null +++ b/dex2oat/src/main/cpp/oat.cpp @@ -0,0 +1,17 @@ +#include "oat.h" + +namespace art { + +uint32_t OatHeader::GetKeyValueStoreSize() const { + return *(uint32_t*)((uintptr_t)this + OatHeader::Get_key_value_store_size_Offset()); +} + +const uint8_t* OatHeader::GetKeyValueStore() const { + return (const uint8_t*)((uintptr_t)this + OatHeader::Get_key_value_store_Offset()); +} + +void OatHeader::SetKeyValueStoreSize(uint32_t new_size) { + *reinterpret_cast((uintptr_t)this + Get_key_value_store_size_Offset()) = new_size; +} + +} // namespace art diff --git a/dex2oat/src/main/cpp/oat_hook.cpp b/dex2oat/src/main/cpp/oat_hook.cpp index d3944a18b..9913abe09 100644 --- a/dex2oat/src/main/cpp/oat_hook.cpp +++ b/dex2oat/src/main/cpp/oat_hook.cpp @@ -1,43 +1,88 @@ #include +#include +#include #include -#include #include #include -#include #include "logging.h" +#include "oat.h" -const std::string_view parameter_to_remove = " --inline-max-code-units=0"; +const std::string_view param_to_remove = " --inline-max-code-units=0"; #define DCL_HOOK_FUNC(ret, func, ...) \ ret (*old_##func)(__VA_ARGS__); \ ret new_##func(__VA_ARGS__) -bool store_updated = false; - -void UpdateKeyValueStore(std::map* key_value, uint8_t* store) { - LOGD("updating KeyValueStore"); - char* data_ptr = reinterpret_cast(store); - if (key_value != nullptr) { - auto it = key_value->begin(); - auto end = key_value->end(); - for (; it != end; ++it) { - strlcpy(data_ptr, it->first.c_str(), it->first.length() + 1); - data_ptr += it->first.length() + 1; - strlcpy(data_ptr, it->second.c_str(), it->second.length() + 1); - data_ptr += it->second.length() + 1; +bool store_resized = false; + +bool ModifyStoreInPlace(uint8_t* store, uint32_t store_size) { + if (store == nullptr || store_size == 0) { + return false; + } + + // Define the search space + uint8_t* const store_begin = store; + uint8_t* const store_end = store + store_size; + + // 1. Search for the parameter in the memory buffer + auto it = std::search(store_begin, store_end, param_to_remove.begin(), param_to_remove.end()); + + // Check if the parameter was found + if (it == store_end) { + LOGD("Parameter '%.*s' not found.", (int)param_to_remove.size(), param_to_remove.data()); + return false; + } + + uint8_t* location_of_param = it; + LOGD("Parameter found at offset %td.", location_of_param - store_begin); + + // 2. Check if there is padding immediately after the string + uint8_t* const byte_after_param = location_of_param + param_to_remove.size(); + bool has_padding = false; + + // Boundary check: ensure the byte after the parameter is within the buffer + if (byte_after_param + 1 < store_end) { + if (*(byte_after_param + 1) == '\0') { + has_padding = true; + } + } + + // 3. Perform the conditional action + if (has_padding) { + // CASE A: Padding exists. Overwrite the parameter with zeros. + LOGD("Padding found. Overwriting parameter with zeros."); + memset(location_of_param, 0, param_to_remove.size()); + return false; // Size did not change + } else { + // CASE B: No padding exists (or parameter is at the very end). + // Remove the parameter by shifting the rest of the memory forward. + LOGD("No padding found. Removing parameter and shifting memory."); + + // Calculate what to move + uint8_t* source = byte_after_param; + uint8_t* destination = location_of_param; + size_t bytes_to_move = store_end - source; + + // memmove is required because the source and destination buffers overlap + if (bytes_to_move > 0) { + memmove(destination, source, bytes_to_move); } + + // 4. Update the total size of the store + store_size -= param_to_remove.size(); + LOGD("Store size changed. New size: %u", store_size); + + return true; // Size changed } - LOGD("KeyValueStore updated"); - store_updated = true; } DCL_HOOK_FUNC(uint32_t, _ZNK3art9OatHeader20GetKeyValueStoreSizeEv, void* header) { uint32_t size = old__ZNK3art9OatHeader20GetKeyValueStoreSizeEv(header); - if (store_updated) { + if (store_resized) { LOGD("OatHeader::GetKeyValueStoreSize() called on object at %p\n", header); - size = size - parameter_to_remove.size(); + size = size - param_to_remove.size(); } return size; } @@ -46,47 +91,32 @@ DCL_HOOK_FUNC(uint8_t*, _ZNK3art9OatHeader16GetKeyValueStoreEv, void* header) { LOGD("OatHeader::GetKeyValueStore() called on object at %p\n", header); uint8_t* key_value_store_ = old__ZNK3art9OatHeader16GetKeyValueStoreEv(header); uint32_t key_value_store_size_ = old__ZNK3art9OatHeader20GetKeyValueStoreSizeEv(header); - const char* ptr = reinterpret_cast(key_value_store_); - const char* end = ptr + key_value_store_size_; - std::map new_store = {}; - - LOGD("scanning [%p-%p] for oat headers", ptr, end); - while (ptr < end) { - // Scan for a closing zero. - const char* str_end = reinterpret_cast(memchr(ptr, 0, end - ptr)); - if (str_end == nullptr) [[unlikely]] { - LOGE("failed to find str_end"); - return key_value_store_; - } - std::string_view key = std::string_view(ptr, str_end - ptr); - const char* value_start = str_end + 1; - const char* value_end = - reinterpret_cast(memchr(value_start, 0, end - value_start)); - if (value_end == nullptr) [[unlikely]] { - LOGE("failed to find value_end"); - return key_value_store_; - } - std::string_view value = std::string_view(value_start, value_end - value_start); - LOGV("header %s:%s", key.data(), value.data()); - if (key == "dex2oat-cmdline") { - value = value.substr(0, value.size() - parameter_to_remove.size()); - } - new_store.insert(std::make_pair(std::string(key), std::string(value))); - // Different from key. Advance over the value. - ptr = value_end + 1; - } - UpdateKeyValueStore(&new_store, key_value_store_); + LOGD("KeyValueStore via hook: [addr: %p, size: %u]", key_value_store_, key_value_store_size_); + store_resized = ModifyStoreInPlace(key_value_store_, key_value_store_size_); return key_value_store_; } +DCL_HOOK_FUNC(void, _ZNK3art9OatHeader15ComputeChecksumEPj, void* header, uint32_t* checksum) { + art::OatHeader* oat_header = reinterpret_cast(header); + const uint8_t* key_value_store_ = oat_header->GetKeyValueStore(); + uint32_t key_value_store_size_ = oat_header->GetKeyValueStoreSize(); + LOGD("KeyValueStore via offset: [addr: %p, size: %u]", key_value_store_, key_value_store_size_); + store_resized = + ModifyStoreInPlace(const_cast(key_value_store_), key_value_store_size_); + if (store_resized) { + oat_header->SetKeyValueStoreSize(key_value_store_size_ - param_to_remove.size()); + } + old__ZNK3art9OatHeader15ComputeChecksumEPj(header, checksum); + LOGD("ComputeChecksum called: %" PRIu32, *checksum); +} + #undef DCL_HOOK_FUNC void register_hook(dev_t dev, ino_t inode, const char* symbol, void* new_func, void** old_func) { LOGD("RegisterHook: %s, %p, %p", symbol, new_func, old_func); if (!lsplt::RegisterHook(dev, inode, symbol, new_func, old_func)) { LOGE("Failed to register plt_hook \"%s\"\n", symbol); - return; } } @@ -109,7 +139,8 @@ __attribute__((constructor)) static void initialize() { PLT_HOOK_REGISTER(dev, inode, _ZNK3art9OatHeader20GetKeyValueStoreSizeEv); PLT_HOOK_REGISTER(dev, inode, _ZNK3art9OatHeader16GetKeyValueStoreEv); - if (lsplt::CommitHook()) { - LOGD("lsplt hooks done"); - }; + if (!lsplt::CommitHook()) { + PLT_HOOK_REGISTER(dev, inode, _ZNK3art9OatHeader15ComputeChecksumEPj); + lsplt::CommitHook(); + } } diff --git a/external/lsplt b/external/lsplt index 2efebed64..e3db00035 160000 --- a/external/lsplt +++ b/external/lsplt @@ -1 +1 @@ -Subproject commit 2efebed64ecce060530c6959b8654019aa796f52 +Subproject commit e3db0003526b1e5be3fb9323ff5ff128a59f9ffb