blob: 26222015bf08d90a2f53bbb3b6de4f2b84695ac4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* @author Gregory Shimansky
*/
/*
* JVMTI capability API
*/
#include "port_mutex.h"
#include "jvmti_direct.h"
#include "jvmti_utils.h"
#include "jvmti_tags.h"
#include "cxxlog.h"
#include "suspend_checker.h"
#include "environment.h"
#include "interpreter_exports.h"
static const jvmtiCapabilities jvmti_supported_interpreter_capabilities =
{
1, // can_tag_objects
1, // can_generate_field_modification_events
1, // can_generate_field_access_events
1, // can_get_bytecodes
1, // can_get_synthetic_attribute
1, // can_get_owned_monitor_info
1, // can_get_current_contended_monitor
1, // can_get_monitor_info
1, // can_pop_frame
0, // can_redefine_classes
1, // can_signal_thread
1, // can_get_source_file_name
1, // can_get_line_numbers
1, // can_get_source_debug_extension
1, // can_access_local_variables
0, // can_maintain_original_method_order
1, // can_generate_single_step_events
1, // can_generate_exception_events
1, // can_generate_frame_pop_events
1, // can_generate_breakpoint_events
1, // can_suspend
0, // can_redefine_any_class
1, // can_get_current_thread_cpu_time
1, // can_get_thread_cpu_time
1, // can_generate_method_entry_events
1, // can_generate_method_exit_events
1, // can_generate_all_class_hook_events
1, // can_generate_compiled_method_load_events
1, // can_generate_monitor_events
1, // can_generate_vm_object_alloc_events
1, // can_generate_native_method_bind_events
1, // can_generate_garbage_collection_events
1 // can_generate_object_free_events
};
#if (defined _EM64T_) || (defined _IPF_)
static const jvmtiCapabilities jvmti_supported_jit_capabilities =
{
1, // can_tag_objects
1, // can_generate_field_modification_events
1, // can_generate_field_access_events
1, // can_get_bytecodes
1, // can_get_synthetic_attribute
1, // can_get_owned_monitor_info
1, // can_get_current_contended_monitor
1, // can_get_monitor_info
1, // can_pop_frame
0, // can_redefine_classes
1, // can_signal_thread
1, // can_get_source_file_name
1, // can_get_line_numbers
1, // can_get_source_debug_extension
1, // can_access_local_variables
0, // can_maintain_original_method_order
1, // can_generate_single_step_events
1, // can_generate_exception_events
1, // can_generate_frame_pop_events
1, // can_generate_breakpoint_events
1, // can_suspend
0, // can_redefine_any_class
1, // can_get_current_thread_cpu_time
1, // can_get_thread_cpu_time
1, // can_generate_method_entry_events
1, // can_generate_method_exit_events
1, // can_generate_all_class_hook_events
1, // can_generate_compiled_method_load_events
1, // can_generate_monitor_events
1, // can_generate_vm_object_alloc_events
1, // can_generate_native_method_bind_events
1, // can_generate_garbage_collection_events
1 // can_generate_object_free_events
};
#else
static const jvmtiCapabilities jvmti_supported_jit_capabilities =
{
1, // can_tag_objects
1, // can_generate_field_modification_events
1, // can_generate_field_access_events
1, // can_get_bytecodes
1, // can_get_synthetic_attribute
1, // can_get_owned_monitor_info
1, // can_get_current_contended_monitor
1, // can_get_monitor_info
1, // can_pop_frame
0, // can_redefine_classes
1, // can_signal_thread
1, // can_get_source_file_name
1, // can_get_line_numbers
1, // can_get_source_debug_extension
1, // can_access_local_variables
0, // can_maintain_original_method_order
1, // can_generate_single_step_events
1, // can_generate_exception_events
1, // can_generate_frame_pop_events
1, // can_generate_breakpoint_events
1, // can_suspend
0, // can_redefine_any_class
1, // can_get_current_thread_cpu_time
1, // can_get_thread_cpu_time
1, // can_generate_method_entry_events
1, // can_generate_method_exit_events
1, // can_generate_all_class_hook_events
1, // can_generate_compiled_method_load_events
1, // can_generate_monitor_events
1, // can_generate_vm_object_alloc_events
1, // can_generate_native_method_bind_events
1, // can_generate_garbage_collection_events
1 // can_generate_object_free_events
};
#endif
// 1 means that corresponding capability can be enabled
// on JVMTI_PHASE_LIVE
static const jvmtiCapabilities jvmti_enable_on_live_flags =
{
0, // can_tag_objects
0, // can_generate_field_modification_events
0, // can_generate_field_access_events
1, // can_get_bytecodes
1, // can_get_synthetic_attribute
1, // can_get_owned_monitor_info
1, // can_get_current_contended_monitor
1, // can_get_monitor_info
1, // can_pop_frame
0, // can_redefine_classes
1, // can_signal_thread
1, // can_get_source_file_name
1, // can_get_line_numbers
1, // can_get_source_debug_extension
0, // can_access_local_variables
0, // can_maintain_original_method_order
1, // can_generate_single_step_events
0, // can_generate_exception_events
0, // can_generate_frame_pop_events
0, // can_generate_breakpoint_events
1, // can_suspend
0, // can_redefine_any_class
1, // can_get_current_thread_cpu_time
1, // can_get_thread_cpu_time
0, // can_generate_method_entry_events
0, // can_generate_method_exit_events
1, // can_generate_all_class_hook_events
1, // can_generate_compiled_method_load_events
0, // can_generate_monitor_events
1, // can_generate_vm_object_alloc_events
1, // can_generate_native_method_bind_events
1, // can_generate_garbage_collection_events
1 // can_generate_object_free_events
};
// Implementation for jvmtiGetPotentialCapabilities()
void static get_available_caps(jvmtiEnv* env,
jvmtiPhase phase,
jvmtiCapabilities* capabilities_ptr)
{
TIEnv *ti_env = reinterpret_cast<TIEnv *>(env);
if (JVMTI_PHASE_ONLOAD == phase)
*capabilities_ptr = interpreter_enabled() ?
jvmti_supported_interpreter_capabilities : jvmti_supported_jit_capabilities;
else
{
// Add all capabilities from supported on live phase to already posessed capabilities
unsigned char* puchar_ptr = (unsigned char*)capabilities_ptr;
unsigned char* enable_ptr = (unsigned char*)&jvmti_enable_on_live_flags;
*capabilities_ptr = ti_env->posessed_capabilities;
for (int i = 0; i < int(sizeof(jvmtiCapabilities)); i++)
puchar_ptr[i] |= enable_ptr[i];
}
DebugUtilsTI* ti = VM_Global_State::loader_env->TI;
// can_tag_objects capability can only be possessed by one environment.
// The feature should be globally enabled in OnLoad phase. If not, it
// can't be possesed in live phase.
// Thus can_tag_objects is available IF
// ( we're in the OnLoad phase OR the feature is already enabled ) AND
// no other environment possesses this capability.
if ( (JVMTI_PHASE_ONLOAD == phase || ManagedObject::_tag_pointer) &&
(!ti->get_global_capability(DebugUtilsTI::TI_GC_ENABLE_TAG_OBJECTS) ||
ti_env->posessed_capabilities.can_tag_objects) )
capabilities_ptr->can_tag_objects = 1;
else
capabilities_ptr->can_tag_objects = 0;
}
/*
* Get Potential Capabilities
*
* Returns via capabilities_ptr the JVMTI features that can
* potentially be possessed by this environment at this time.
*
* @note REQUIRED Functionality.
*/
jvmtiError JNICALL
jvmtiGetPotentialCapabilities(jvmtiEnv* env,
jvmtiCapabilities* capabilities_ptr)
{
TRACE2("jvmti.capability", "GetPotentialCapabilities called");
SuspendEnabledChecker sec;
// Check given env & current phase.
jvmtiPhase phases[] = {JVMTI_PHASE_ONLOAD, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (NULL == capabilities_ptr)
return JVMTI_ERROR_NULL_POINTER;
jvmtiPhase phase;
jvmtiError errorCode = jvmtiGetPhase(env, &phase);
if (errorCode != JVMTI_ERROR_NONE)
return errorCode;
get_available_caps(env, phase, capabilities_ptr);
return JVMTI_ERROR_NONE;
}
/*
* Add Capabilities
*
* Set new capabilities by adding the capabilities pointed to by
* capabilities_ptr. All previous capabilities are retained.
* Typically this function is used in the OnLoad function.
*
* @note REQUIRED Functionality.
*/
jvmtiError JNICALL
jvmtiAddCapabilities(jvmtiEnv* env,
const jvmtiCapabilities* capabilities_ptr)
{
TRACE2("jvmti.capability", "AddCapabilities called");
SuspendEnabledChecker sec;
// Check given env & current phase.
jvmtiPhase phases[] = {JVMTI_PHASE_ONLOAD, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (NULL == capabilities_ptr)
return JVMTI_ERROR_NULL_POINTER;
jvmtiPhase phase;
jvmtiError errorCode = jvmtiGetPhase(env, &phase);
if (errorCode != JVMTI_ERROR_NONE)
return errorCode;
// make a copy of already possessed caps
TIEnv *ti_env = reinterpret_cast<TIEnv *>(env);
jvmtiCapabilities possessed_caps = ti_env->posessed_capabilities;
jvmtiCapabilities available_caps;
get_available_caps(env, phase, &available_caps);
unsigned char* p_requested = (unsigned char*) capabilities_ptr;
unsigned char* p_available = (unsigned char*) &available_caps;
unsigned char* p_possessed = (unsigned char*) &possessed_caps;
DebugUtilsTI *ti = ti_env->vm->vm_env->TI;
// Allow to turn on any capabilities that are listed in potential capabilities
for (int i = 0; i < int(sizeof(jvmtiCapabilities)); i++)
{
unsigned char adding_new = p_requested[i] & ~p_possessed[i];
if (adding_new & ~p_available[i])
return JVMTI_ERROR_NOT_AVAILABLE;
p_possessed[i] |= adding_new;
}
// Add new capabilities after checking was done
ti_env->posessed_capabilities = possessed_caps;
// Update global capabilities
if (capabilities_ptr->can_generate_method_entry_events)
ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_METHOD_ENTRY);
if (capabilities_ptr->can_generate_method_exit_events)
ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_METHOD_EXIT);
if (capabilities_ptr->can_generate_frame_pop_events)
{
ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_METHOD_EXIT);
ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_FRAME_POP_NOTIFICATION);
}
if (capabilities_ptr->can_generate_single_step_events)
ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_SINGLE_STEP);
if (capabilities_ptr->can_generate_exception_events)
ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT);
if (capabilities_ptr->can_generate_field_access_events)
ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_ACCESS_EVENT);
if (capabilities_ptr->can_generate_field_modification_events)
ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_MODIFICATION_EVENT);
if (capabilities_ptr->can_pop_frame)
ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_POP_FRAME);
if (capabilities_ptr->can_generate_monitor_events ||
capabilities_ptr->can_get_owned_monitor_info)
ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_MONITOR_EVENTS);
if (capabilities_ptr->can_tag_objects) {
ti->set_global_capability(DebugUtilsTI::TI_GC_ENABLE_TAG_OBJECTS);
// this flag could be set only once and mustn't be reset by
// RelinquishCapabilities.
ManagedObject::_tag_pointer = true;
}
return JVMTI_ERROR_NONE;
} // jvmtiAddCapabilities
/*
* Relinquish Capabilities
*
* Remove the capabilities pointed to by capabilities_ptr.
* Some implementations may allow only one environment to have
* capability (see the capability introduction).
*
* @note REQUIRED Functionality.
*/
jvmtiError JNICALL
jvmtiRelinquishCapabilities(jvmtiEnv* env,
const jvmtiCapabilities* capabilities_ptr)
{
TRACE2("jvmti.capability", "RelinquishCapabilities called");
SuspendEnabledChecker sec;
// Check given env & current phase.
jvmtiPhase phases[] = {JVMTI_PHASE_ONLOAD, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (NULL == capabilities_ptr)
return JVMTI_ERROR_NULL_POINTER;
TIEnv *ti_env = reinterpret_cast<TIEnv *>(env);
unsigned char* p_posessed = (unsigned char*)&ti_env->posessed_capabilities;
unsigned char* puchar_ptr = (unsigned char*)capabilities_ptr;
jvmtiCapabilities removed_caps;
unsigned char* removed_ptr = (unsigned char*)&removed_caps;
// Remove all bits set in capabilities_ptr
// FIXME: disable corresponding parts of VM according to removed capabilities
for (int i = 0; i < int(sizeof(jvmtiCapabilities)); i++)
{
removed_ptr[i] = (p_posessed[i] & puchar_ptr[i]);
p_posessed[i] &= ~removed_ptr[i];
}
DebugUtilsTI* ti = ti_env->vm->vm_env->TI;
ti->TIenvs_lock._lock();
ti_env = ti->getEnvironments();
while (NULL != ti_env)
{
TIEnv* next_env = ti_env->next;
unsigned char* p_posessed = (unsigned char*)&ti_env->posessed_capabilities;
// clear 'removed_caps' capabilities that posessed in any environment
for (int i = 0; i < int(sizeof(jvmtiCapabilities)); i++)
removed_ptr[i] &= ~p_posessed[i];
ti_env = next_env;
}
ti->TIenvs_lock._unlock();
// Now removed_ptr contains capabilities removed from all environments
if (removed_caps.can_generate_method_entry_events)
ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_METHOD_ENTRY);
if (removed_caps.can_generate_method_exit_events)
{
ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_METHOD_EXIT);
ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_FRAME_POP_NOTIFICATION);
}
if (removed_caps.can_generate_frame_pop_events)
ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_FRAME_POP_NOTIFICATION);
if (removed_caps.can_generate_single_step_events)
ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_SINGLE_STEP);
if (removed_caps.can_generate_exception_events)
ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_EXCEPTION_EVENT);
if (removed_caps.can_generate_field_access_events)
ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_ACCESS_EVENT);
if (removed_caps.can_generate_field_modification_events)
ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_FIELD_MODIFICATION_EVENT);
if (removed_caps.can_pop_frame)
ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_POP_FRAME);
if (removed_caps.can_tag_objects) {
// clear tags on relinquishing can_tag_objects capability
ti_env = reinterpret_cast<TIEnv *>(env);
port_mutex_lock(&ti_env->environment_data_lock);
if (ti_env->tags) {
ti_env->tags->clear();
delete ti_env->tags;
ti_env->tags = NULL;
}
port_mutex_unlock(&ti_env->environment_data_lock);
ti->reset_global_capability(DebugUtilsTI::TI_GC_ENABLE_TAG_OBJECTS);
}
// relinquishing following capabilities will not revert VM operation mode
// back to optimized, so we do not reset global capabilities
//
// TI_GC_ENABLE_MONITOR_EVENTS
return JVMTI_ERROR_NONE;
} // jvmtiRelinquishCapabilities
/*
* Get Capabilities
*
* Returns via capabilities_ptr the optional JVMTI features which
* this environment currently possesses. An environment does not
* possess a capability unless it has been successfully added with
* AddCapabilities. An environment only loses possession of a
* capability if it has been relinquished with
* RelinquishCapabilities. Thus, this function returns the net
* result of the AddCapabilities and RelinquishCapabilities calls
* which have been made.
*
* @note REQUIRED Functionality.
*/
jvmtiError JNICALL
jvmtiGetCapabilities(jvmtiEnv* env,
jvmtiCapabilities* capabilities_ptr)
{
TRACE2("jvmti.capability", "GetCapabilities called");
SuspendEnabledChecker sec;
// Can be called from any phase
// Check only given env.
jvmtiPhase* phases = NULL;
CHECK_EVERYTHING();
if (NULL == capabilities_ptr)
return JVMTI_ERROR_NULL_POINTER;
TIEnv *ti_env = reinterpret_cast<TIEnv *>(env);
*capabilities_ptr = ti_env->posessed_capabilities;
return JVMTI_ERROR_NONE;
} // jvmtiGetCapabilities