diff --git a/jni/art/art_9_0.h b/jni/art/art_9_0.h new file mode 100644 index 0000000..206f17b --- /dev/null +++ b/jni/art/art_9_0.h @@ -0,0 +1,269 @@ +/* + * + * 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. + */ + +/** + * Created by Tanck 11/14/2020 11:31PM + * + * http://androidxref.com/9.0.0_r3/xref/art/runtime/mirror/class.h + * http://androidxref.com/9.0.0_r3/xref/art/runtime/art_field.h + * http://androidxref.com/9.0.0_r3/xref/art/runtime/art_method.h + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include /* C99 */ + +namespace art { + namespace mirror { + class Object { + public: + // The number of vtable entries in java.lang.Object. + static constexpr size_t kVTableLength = 11; + static uint32_t hash_code_seed; + uint32_t klass_; + uint32_t monitor_; + }; + + class Class : public Object { + public: + enum { + kDumpClassFullDetail = 1, + kDumpClassClassLoader = (1 << 1), + kDumpClassInitialized = (1 << 2), + }; + + // A magic value for reference_instance_offsets_. Ignore the bits and walk the super chain when + // this is the value. + // [This is an unlikely "natural" value, since it would be 30 non-ref instance fields followed by + // 2 ref instance fields.] + static constexpr uint32_t kClassWalkSuper = 0xC0000000; + // Shift primitive type by kPrimitiveTypeSizeShiftShift to get the component type size shift + // Used for computing array size as follows: + // array_bytes = header_size + (elements << (primitive_type >> kPrimitiveTypeSizeShiftShift)) + static constexpr uint32_t kPrimitiveTypeSizeShiftShift = 16; + static constexpr uint32_t kPrimitiveTypeMask = (1u << kPrimitiveTypeSizeShiftShift) - 1; + + // 'Class' Object Fields + // Order governed by java field ordering. See art::ClassLinker::LinkFields. + + // Defining class loader, or null for the "bootstrap" system loader. + uint32_t class_loader_; + // For array classes, the component class object for instanceof/checkcast + // (for String[][][], this will be String[][]). null for non-array classes. + uint32_t component_type_; + // DexCache of resolved constant pool entries (will be null for classes generated by the + // runtime such as arrays and primitive classes). + uint32_t dex_cache_; + // Extraneous class data that is not always needed. This field is allocated lazily and may + // only be set with 'this' locked. This is synchronized on 'this'. + // TODO(allight) We should probably synchronize it on something external or handle allocation in + // some other (safe) way to prevent possible deadlocks. + uint32_t ext_data_; + + // The interface table (iftable_) contains pairs of a interface class and an array of the + // interface methods. There is one pair per interface supported by this class. That means one + // pair for each interface we support directly, indirectly via superclass, or indirectly via a + // superinterface. This will be null if neither we nor our superclass implement any interfaces. + // + // Why we need this: given "class Foo implements Face", declare "Face faceObj = new Foo()". + // Invoke faceObj.blah(), where "blah" is part of the Face interface. We can't easily use a + // single vtable. + // + // For every interface a concrete class implements, we create an array of the concrete vtable_ + // methods for the methods in the interface. + uint32_t iftable_; + // Descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName + uint32_t name_; + // The superclass, or null if this is java.lang.Object or a primitive type. + // + // Note that interfaces have java.lang.Object as their + // superclass. This doesn't match the expectations in JNI + // GetSuperClass or java.lang.Class.getSuperClass() which need to + // check for interfaces and return null. + uint32_t super_class_; + // Virtual method table (vtable), for use by "invoke-virtual". The vtable from the superclass is + // copied in, and virtual methods from our class either replace those from the super or are + // appended. For abstract classes, methods may be created in the vtable that aren't in + // virtual_ methods_ for miranda methods. + uint32_t vtable_; + // instance fields + // + // These describe the layout of the contents of an Object. + // Note that only the fields directly declared by this class are + // listed in ifields; fields declared by a superclass are listed in + // the superclass's Class.ifields. + // + // ArtFields are allocated as a length prefixed ArtField array, and not an array of pointers to + // ArtFields. + uint64_t ifields_; + // Pointer to an ArtMethod length-prefixed array. All the methods where this class is the place + // where they are logically defined. This includes all private, static, final and virtual methods + // as well as inherited default methods and miranda methods. + // + // The slice methods_ [0, virtual_methods_offset_) are the direct (static, private, init) methods + // declared by this class. + // + // The slice methods_ [virtual_methods_offset_, copied_methods_offset_) are the virtual methods + // declared by this class. + // + // The slice methods_ [copied_methods_offset_, |methods_|) are the methods that are copied from + // interfaces such as miranda or default methods. These are copied for resolution purposes as this + // class is where they are (logically) declared as far as the virtual dispatch is concerned. + // + // Note that this field is used by the native debugger as the unique identifier for the type. + uint64_t methods_; + // Static fields length-prefixed array. + uint64_t sfields_; + // Access flags; low 16 bits are defined by VM spec. + uint32_t access_flags_; + // Class flags to help speed up visiting object references. + uint32_t class_flags_; + + // Total size of the Class instance; used when allocating storage on gc heap. + // See also object_size_. + uint32_t class_size_; + + // Tid used to check for recursive invocation. + pid_t clinit_thread_id_; + + // ClassDef index in dex file, -1 if no class definition such as an array. + // TODO: really 16bits + int32_t dex_class_def_idx_; + + // Type index in dex file. + // TODO: really 16bits + int32_t dex_type_idx_; + + // Number of instance fields that are object refs. + uint32_t num_reference_instance_fields_; + + // Number of static fields that are object refs, + uint32_t num_reference_static_fields_; + + // Total object size; used when allocating storage on gc heap. + // (For interfaces and abstract classes this will be zero.) + // See also class_size_. + uint32_t object_size_; + + // Aligned object size for allocation fast path. The value is max uint32_t if the object is + // uninitialized or finalizable. Not currently used for variable sized objects. + uint32_t object_size_alloc_fast_path_; + + // The lower 16 bits contains a Primitive::Type value. The upper 16 + // bits contains the size shift of the primitive type. + uint32_t primitive_type_; + + // Bitmap of offsets of ifields. + uint32_t reference_instance_offsets_; + + // See the real definition in subtype_check_bits_and_status.h + // typeof(status_) is actually SubtypeCheckBitsAndStatus. + uint32_t status_; + + // The offset of the first virtual method that is copied from an interface. This includes miranda, + // default, and default-conflict methods. Having a hard limit of ((2 << 16) - 1) for methods + // defined on a single class is well established in Java so we will use only uint16_t's here. + uint16_t copied_methods_offset_; + + // The offset of the first declared virtual methods in the methods_ array. + uint16_t virtual_methods_offset_; + + // TODO: ? + // initiating class loader list + // NOTE: for classes with low serialNumber, these are unused, and the + // values are kept in a table in gDvm. + // InitiatingLoaderList initiating_loader_list_; + + // The following data exist in real class objects. + // Embedded Imtable, for class object that's not an interface, fixed size. + // ImTableEntry embedded_imtable_[0]; + // Embedded Vtable, for class object that's not an interface, variable size. + // VTableEntry embedded_vtable_[0]; + // Static fields, variable size. + // uint32_t fields_[0]; + + // java.lang.Class + static uint32_t java_lang_Class_; + + }; + + class ArtField { + public: + uint32_t declaring_class_; + uint32_t access_flags_; + uint32_t field_dex_idx_; + uint32_t offset_; + }; + + class ArtMethod { + public: + + // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". + // The class we are a part of. + uint32_t declaring_class_; + + // Access flags; low 16 bits are defined by spec. + // Getting and setting this flag needs to be atomic when concurrency is + // possible, e.g. after this method's class is linked. Such as when setting + // verifier flags and single-implementation flag. + uint32_t access_flags_; + + /* Dex file fields. The defining dex file is available via declaring_class_->dex_cache_ */ + + // Offset to the CodeItem. + uint32_t dex_code_item_offset_; + + // Index into method_ids of the dex file associated with this method. + uint32_t dex_method_index_; + + /* End of dex file fields. */ + + // Entry within a dispatch table for this method. For static/direct methods the index is into + // the declaringClass.directMethods, for virtual methods the vtable and for interface methods the + // ifTable. + uint16_t method_index_; + + // The hotness we measure for this method. Not atomic, as we allow + // missing increments: if the method is hot, we will see it eventually. + uint16_t hotness_count_; + struct PtrSizedFields { + // Depending on the method type, the data is + // - native method: pointer to the JNI function registered to this method + // or a function to resolve the JNI function, + // - conflict method: ImtConflictTable, + // - abstract/interface method: the single-implementation if any, + // - proxy method: the original interface method or constructor, + // - other methods: the profiling data. + void *data_; + + // Method dispatch from quick compiled code invokes this pointer which may cause bridging into + // the interpreter. + void *entry_point_from_quick_compiled_code_; + } ptr_sized_fields_; + + }; + + } + +} diff --git a/jni/art/art_method_replace.cpp b/jni/art/art_method_replace.cpp index d4ee96d..f20d7ce 100644 --- a/jni/art/art_method_replace.cpp +++ b/jni/art/art_method_replace.cpp @@ -52,7 +52,9 @@ extern jboolean __attribute__ ((visibility ("hidden"))) art_setup(JNIEnv* env, extern void __attribute__ ((visibility ("hidden"))) art_replaceMethod( JNIEnv* env, jobject src, jobject dest) { - if (apilevel > 23) { + if (apilevel == 28) { + replace_9_0(env, src, dest); + } else if (apilevel == 24) { replace_7_0(env, src, dest); } else if (apilevel > 22) { replace_6_0(env, src, dest); @@ -67,8 +69,10 @@ extern void __attribute__ ((visibility ("hidden"))) art_replaceMethod( extern void __attribute__ ((visibility ("hidden"))) art_setFieldFlag( JNIEnv* env, jobject field) { - if (apilevel > 23) { - setFieldFlag_7_0(env, field); + if (apilevel == 28) { + setFieldFlag_9_0(env, field); + } else if (apilevel == 24) { + setFieldFlag_7_0(env, field); } else if (apilevel > 22) { setFieldFlag_6_0(env, field); } else if (apilevel > 21) { diff --git a/jni/art/art_method_replace_9_0.cpp b/jni/art/art_method_replace_9_0.cpp new file mode 100644 index 0000000..e6d32d5 --- /dev/null +++ b/jni/art/art_method_replace_9_0.cpp @@ -0,0 +1,74 @@ +/* + * + * 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. + */ + +/** + * art_method_replace_9_0.cpp + * Created by Tanck 11/14/2020 11:31PM + */ + +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "art.h" +#include "art_9_0.h" +#include "../common.h" + +/** + * Replace the method on android9 + * @param env the native env + * @param src the bug method + * @param dest the fixed method + */ +void replace_9_0(JNIEnv *env, jobject src, jobject dest) { + auto *source_method = (art::mirror::ArtMethod *) env->FromReflectedMethod(src); + auto *dest_method = (art::mirror::ArtMethod *) env->FromReflectedMethod(dest); + + reinterpret_cast(dest_method->declaring_class_)->clinit_thread_id_ = reinterpret_cast(source_method->declaring_class_)->clinit_thread_id_; + reinterpret_cast(dest_method->declaring_class_)->status_ = reinterpret_cast(source_method->declaring_class_)->status_ - 1; + reinterpret_cast(dest_method->declaring_class_)->super_class_ = 0; + + source_method->declaring_class_ = dest_method->declaring_class_; + source_method->access_flags_ = dest_method->access_flags_ | 0x0001; + source_method->dex_code_item_offset_ = dest_method->dex_code_item_offset_; + source_method->dex_method_index_ = dest_method->dex_method_index_; + source_method->method_index_ = dest_method->method_index_; + source_method->hotness_count_ = dest_method->hotness_count_; + source_method->ptr_sized_fields_.data_ = dest_method->ptr_sized_fields_.data_; + source_method->ptr_sized_fields_.entry_point_from_quick_compiled_code_ = dest_method->ptr_sized_fields_.entry_point_from_quick_compiled_code_; + + LOGD("replace_9_0: %d , %d", + source_method->ptr_sized_fields_.entry_point_from_quick_compiled_code_, + dest_method->ptr_sized_fields_.entry_point_from_quick_compiled_code_); + +} + +void setFieldFlag_9_0(JNIEnv *env, jobject field) { + auto *artField = (art::mirror::ArtField *) env->FromReflectedField(field); + artField->access_flags_ = artField->access_flags_ & (~0x0002) | 0x0001; + LOGD("setFieldFlag_9_0: %d ", artField->access_flags_); +} \ No newline at end of file