| /* Copyright (C) 2017 The Android Open Source Project |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This file implements interfaces from the file jvmti.h. This implementation |
| * is licensed under the same terms as the file jvmti.h. The |
| * copyright and license information for the file jvmti.h follows. |
| * |
| * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code 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 |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| #ifndef ART_OPENJDKJVMTI_TI_CLASS_DEFINITION_H_ |
| #define ART_OPENJDKJVMTI_TI_CLASS_DEFINITION_H_ |
| |
| #include <stddef.h> |
| #include <sys/mman.h> |
| #include <sys/types.h> |
| |
| #include "art_jvmti.h" |
| |
| #include "base/array_ref.h" |
| #include "base/mem_map.h" |
| #include "events.h" |
| |
| namespace openjdkjvmti { |
| |
| // A struct that stores data needed for redefining/transforming classes. This structure should only |
| // even be accessed from a single thread and must not survive past the completion of the |
| // redefinition/retransformation function that created it. |
| class ArtClassDefinition { |
| public: |
| // If we support doing a on-demand dex-dequickening using signal handlers. |
| static constexpr bool kEnableOnDemandDexDequicken = true; |
| |
| ArtClassDefinition() |
| : klass_(nullptr), |
| loader_(nullptr), |
| name_(), |
| protection_domain_(nullptr), |
| dex_data_mmap_(), |
| temp_mmap_(), |
| dex_data_memory_(), |
| initial_dex_file_unquickened_(nullptr), |
| dex_data_(), |
| current_dex_memory_(), |
| current_dex_file_(), |
| redefined_(false), |
| from_class_ext_(false), |
| initialized_(false), |
| structural_transform_update_(false) {} |
| |
| void InitFirstLoad(const char* descriptor, |
| art::Handle<art::mirror::ClassLoader> klass_loader, |
| const art::DexFile& dex_file); |
| jvmtiError Init(art::Thread* self, jclass klass); |
| jvmtiError Init(art::Thread* self, const jvmtiClassDefinition& def); |
| |
| ArtClassDefinition(ArtClassDefinition&& o) = default; |
| ArtClassDefinition& operator=(ArtClassDefinition&& o) = default; |
| |
| void SetNewDexData(jint new_dex_len, unsigned char* new_dex_data, ArtJvmtiEvent event) { |
| DCHECK(IsInitialized()); |
| if (new_dex_data == nullptr) { |
| return; |
| } else { |
| art::ArrayRef<const unsigned char> new_data(new_dex_data, new_dex_len); |
| if (new_data != dex_data_) { |
| dex_data_memory_.resize(new_dex_len); |
| memcpy(dex_data_memory_.data(), new_dex_data, new_dex_len); |
| dex_data_ = art::ArrayRef<const unsigned char>(dex_data_memory_); |
| if (event == ArtJvmtiEvent::kStructuralDexFileLoadHook) { |
| structural_transform_update_ = true; |
| } |
| } |
| } |
| } |
| |
| bool HasStructuralChanges() const { |
| return structural_transform_update_; |
| } |
| |
| art::ArrayRef<const unsigned char> GetNewOriginalDexFile() const { |
| DCHECK(IsInitialized()); |
| if (redefined_) { |
| return current_dex_file_; |
| } else { |
| return art::ArrayRef<const unsigned char>(); |
| } |
| } |
| |
| bool ContainsAddress(uintptr_t ptr) const { |
| return dex_data_mmap_.IsValid() && |
| reinterpret_cast<uintptr_t>(dex_data_mmap_.Begin()) <= ptr && |
| reinterpret_cast<uintptr_t>(dex_data_mmap_.End()) > ptr; |
| } |
| |
| bool IsModified() const REQUIRES_SHARED(art::Locks::mutator_lock_); |
| |
| bool IsInitialized() const { |
| return initialized_; |
| } |
| |
| jclass GetClass() const { |
| DCHECK(IsInitialized()); |
| return klass_; |
| } |
| |
| jobject GetLoader() const { |
| DCHECK(IsInitialized()); |
| return loader_; |
| } |
| |
| const std::string& GetName() const { |
| DCHECK(IsInitialized()); |
| return name_; |
| } |
| |
| bool IsLazyDefinition() const { |
| DCHECK(IsInitialized()); |
| return dex_data_mmap_.IsValid() && |
| dex_data_.data() == dex_data_mmap_.Begin() && |
| dex_data_mmap_.GetProtect() == PROT_NONE; |
| } |
| |
| jobject GetProtectionDomain() const { |
| DCHECK(IsInitialized()); |
| return protection_domain_; |
| } |
| |
| art::ArrayRef<const unsigned char> GetDexData() const { |
| DCHECK(IsInitialized()); |
| return dex_data_; |
| } |
| |
| void InitializeMemory() const; |
| |
| private: |
| jvmtiError InitCommon(art::Thread* self, jclass klass); |
| |
| template<typename GetOriginalDexFile> |
| void InitWithDex(GetOriginalDexFile get_original, const art::DexFile* quick_dex) |
| REQUIRES_SHARED(art::Locks::mutator_lock_); |
| |
| jclass klass_; |
| jobject loader_; |
| std::string name_; |
| jobject protection_domain_; |
| |
| // Mmap that will be filled with the original-dex-file lazily if it needs to be de-quickened or |
| // de-compact-dex'd |
| mutable art::MemMap dex_data_mmap_; |
| // This is a temporary mmap we will use to be able to fill the dex file data atomically. |
| mutable art::MemMap temp_mmap_; |
| |
| // A unique_ptr to the current dex_data if it needs to be cleaned up. |
| std::vector<unsigned char> dex_data_memory_; |
| |
| const art::DexFile* initial_dex_file_unquickened_; |
| |
| // A ref to the current dex data. This is either dex_data_memory_, or current_dex_file_. This is |
| // what the dex file will be turned into. |
| art::ArrayRef<const unsigned char> dex_data_; |
| |
| // This is only used if we failed to create a mmap to store the dequickened data |
| std::vector<unsigned char> current_dex_memory_; |
| |
| // This is a dequickened version of what is loaded right now. It is either current_dex_memory_ (if |
| // no other redefinition has ever happened to this) or the current dex_file_ directly (if this |
| // class has been redefined, thus it cannot have any quickened stuff). |
| art::ArrayRef<const unsigned char> current_dex_file_; |
| |
| bool redefined_; |
| |
| // If we got the initial dex_data_ from a class_ext |
| bool from_class_ext_; |
| |
| bool initialized_; |
| |
| // Set if we had a new dex from the given transform type. |
| bool structural_transform_update_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ArtClassDefinition); |
| }; |
| |
| } // namespace openjdkjvmti |
| |
| #endif // ART_OPENJDKJVMTI_TI_CLASS_DEFINITION_H_ |