Home | History | Annotate | Download | only in openjdkjvmti
      1 /* Copyright (C) 2017 The Android Open Source Project
      2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      3  *
      4  * This file implements interfaces from the file jvmti.h. This implementation
      5  * is licensed under the same terms as the file jvmti.h.  The
      6  * copyright and license information for the file jvmti.h follows.
      7  *
      8  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
      9  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     10  *
     11  * This code is free software; you can redistribute it and/or modify it
     12  * under the terms of the GNU General Public License version 2 only, as
     13  * published by the Free Software Foundation.  Oracle designates this
     14  * particular file as subject to the "Classpath" exception as provided
     15  * by Oracle in the LICENSE file that accompanied this code.
     16  *
     17  * This code is distributed in the hope that it will be useful, but WITHOUT
     18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     20  * version 2 for more details (a copy is included in the LICENSE file that
     21  * accompanied this code).
     22  *
     23  * You should have received a copy of the GNU General Public License version
     24  * 2 along with this work; if not, write to the Free Software Foundation,
     25  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     26  *
     27  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     28  * or visit www.oracle.com if you need additional information or have any
     29  * questions.
     30  */
     31 
     32 #include <functional>
     33 
     34 #include "ti_breakpoint.h"
     35 
     36 #include "art_jvmti.h"
     37 #include "art_method-inl.h"
     38 #include "base/enums.h"
     39 #include "base/mutex-inl.h"
     40 #include "deopt_manager.h"
     41 #include "dex/dex_file_annotations.h"
     42 #include "dex/modifiers.h"
     43 #include "events-inl.h"
     44 #include "jni_internal.h"
     45 #include "mirror/class-inl.h"
     46 #include "mirror/object_array-inl.h"
     47 #include "nativehelper/scoped_local_ref.h"
     48 #include "runtime_callbacks.h"
     49 #include "scoped_thread_state_change-inl.h"
     50 #include "thread-current-inl.h"
     51 #include "thread_list.h"
     52 #include "ti_phase.h"
     53 
     54 namespace openjdkjvmti {
     55 
     56 size_t Breakpoint::hash() const {
     57   return std::hash<uintptr_t> {}(reinterpret_cast<uintptr_t>(method_))
     58       ^ std::hash<jlocation> {}(location_);
     59 }
     60 
     61 Breakpoint::Breakpoint(art::ArtMethod* m, jlocation loc) : method_(m), location_(loc) {
     62   DCHECK(!m->IsDefault() || !m->IsCopied() || !m->IsInvokable())
     63       << "Flags are: 0x" << std::hex << m->GetAccessFlags();
     64 }
     65 
     66 void BreakpointUtil::RemoveBreakpointsInClass(ArtJvmTiEnv* env, art::mirror::Class* klass) {
     67   std::vector<Breakpoint> to_remove;
     68   {
     69     art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
     70     for (const Breakpoint& b : env->breakpoints) {
     71       if (b.GetMethod()->GetDeclaringClass() == klass) {
     72         to_remove.push_back(b);
     73       }
     74     }
     75     for (const Breakpoint& b : to_remove) {
     76       auto it = env->breakpoints.find(b);
     77       DCHECK(it != env->breakpoints.end());
     78       env->breakpoints.erase(it);
     79     }
     80   }
     81   DeoptManager* deopt = DeoptManager::Get();
     82   for (const Breakpoint& b : to_remove) {
     83     // TODO It might be good to send these all at once instead.
     84     deopt->RemoveMethodBreakpoint(b.GetMethod());
     85   }
     86 }
     87 
     88 jvmtiError BreakpointUtil::SetBreakpoint(jvmtiEnv* jenv, jmethodID method, jlocation location) {
     89   ArtJvmTiEnv* env = ArtJvmTiEnv::AsArtJvmTiEnv(jenv);
     90   if (method == nullptr) {
     91     return ERR(INVALID_METHODID);
     92   }
     93   art::ScopedObjectAccess soa(art::Thread::Current());
     94   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method)->GetCanonicalMethod();
     95   if (location < 0 || static_cast<uint32_t>(location) >=
     96       art_method->DexInstructions().InsnsSizeInCodeUnits()) {
     97     return ERR(INVALID_LOCATION);
     98   }
     99   DeoptManager::Get()->AddMethodBreakpoint(art_method);
    100   {
    101     art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
    102     auto res_pair = env->breakpoints.insert(/* Breakpoint */ {art_method, location});
    103     if (LIKELY(res_pair.second)) {
    104       return OK;
    105     }
    106   }
    107   // Didn't get inserted because it's already present!
    108   DeoptManager::Get()->RemoveMethodBreakpoint(art_method);
    109   return ERR(DUPLICATE);
    110 }
    111 
    112 jvmtiError BreakpointUtil::ClearBreakpoint(jvmtiEnv* jenv, jmethodID method, jlocation location) {
    113   ArtJvmTiEnv* env = ArtJvmTiEnv::AsArtJvmTiEnv(jenv);
    114   if (method == nullptr) {
    115     return ERR(INVALID_METHODID);
    116   }
    117   art::ScopedObjectAccess soa(art::Thread::Current());
    118   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method)->GetCanonicalMethod();
    119   {
    120     art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
    121     auto pos = env->breakpoints.find(/* Breakpoint */ {art_method, location});
    122     if (pos == env->breakpoints.end()) {
    123       return ERR(NOT_FOUND);
    124     }
    125     env->breakpoints.erase(pos);
    126   }
    127   DeoptManager::Get()->RemoveMethodBreakpoint(art_method);
    128   return OK;
    129 }
    130 
    131 }  // namespace openjdkjvmti
    132