/* 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 #include #include #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 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 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(dex_data_memory_); if (event == ArtJvmtiEvent::kStructuralDexFileLoadHook) { structural_transform_update_ = true; } } } } bool HasStructuralChanges() const { return structural_transform_update_; } art::ArrayRef GetNewOriginalDexFile() const { DCHECK(IsInitialized()); if (redefined_) { return current_dex_file_; } else { return art::ArrayRef(); } } bool ContainsAddress(uintptr_t ptr) const { return dex_data_mmap_.IsValid() && reinterpret_cast(dex_data_mmap_.Begin()) <= ptr && reinterpret_cast(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 GetDexData() const { DCHECK(IsInitialized()); return dex_data_; } void InitializeMemory() const; private: jvmtiError InitCommon(art::Thread* self, jclass klass); template 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 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 dex_data_; // This is only used if we failed to create a mmap to store the dequickened data std::vector 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 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_