510336c210
Remove all cplusplus ifdefs from vmTestbase Reviewed-by: dholmes, iignatyev, cjplummer, sspitsyn
812 lines
26 KiB
C++
812 lines
26 KiB
C++
/*
|
|
* Copyright (c) 2003, 2018, 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.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "native_thread.h"
|
|
#include "jni_tools.h"
|
|
#include "jvmti_tools.h"
|
|
|
|
extern "C" {
|
|
|
|
/* ============================================================================= */
|
|
|
|
/* Be careful: do not build shared library which will be linked with different
|
|
* agent libs while global variables are used
|
|
* Now the same source is used to build different agent libs, so these
|
|
* variables are not shared between agents */
|
|
|
|
static jthread agentThread = NULL;
|
|
static jvmtiStartFunction agentThreadProc = NULL;
|
|
static void* agentThreadArg = NULL;
|
|
|
|
|
|
typedef enum {NEW, RUNNABLE, WAITING, SUSPENDED, TERMINATED} thread_state_t;
|
|
|
|
typedef struct agent_data_t {
|
|
volatile thread_state_t thread_state;
|
|
int last_debuggee_status;
|
|
jrawMonitorID monitor;
|
|
} agent_data_t;
|
|
|
|
static agent_data_t agent_data;
|
|
|
|
static jvmtiEnv* jvmti_env = NULL;
|
|
static JavaVM* jvm = NULL;
|
|
static JNIEnv* jni_env = NULL;
|
|
|
|
static volatile int currentAgentStatus = NSK_STATUS_PASSED;
|
|
|
|
/* ============================================================================= */
|
|
|
|
void nsk_jvmti_setFailStatus() {
|
|
currentAgentStatus = NSK_STATUS_FAILED;
|
|
}
|
|
|
|
int nsk_jvmti_isFailStatus() {
|
|
return (nsk_jvmti_getStatus() != NSK_STATUS_PASSED);
|
|
}
|
|
|
|
jint nsk_jvmti_getStatus() {
|
|
return currentAgentStatus;
|
|
}
|
|
|
|
/* ============================================================================= */
|
|
static jvmtiError init_agent_data(jvmtiEnv *jvmti_env, agent_data_t *data) {
|
|
data->thread_state = NEW;
|
|
data->last_debuggee_status = NSK_STATUS_PASSED;
|
|
|
|
return NSK_CPP_STUB3(CreateRawMonitor, jvmti_env, "agent_data_monitor", &data->monitor);
|
|
}
|
|
|
|
/** Reset agent data to prepare for another run. */
|
|
void nsk_jvmti_resetAgentData() {
|
|
rawMonitorEnter(jvmti_env, agent_data.monitor);
|
|
/* wait for agentThreadWrapper() to finish */
|
|
while (agent_data.thread_state != TERMINATED) {
|
|
rawMonitorWait(jvmti_env, agent_data.monitor, 10);
|
|
}
|
|
agent_data.thread_state = NEW;
|
|
agent_data.last_debuggee_status = NSK_STATUS_PASSED;
|
|
rawMonitorExit(jvmti_env, agent_data.monitor);
|
|
}
|
|
|
|
static jvmtiError free_agent_data(jvmtiEnv *jvmti_env, agent_data_t *data) {
|
|
return NSK_CPP_STUB2(DestroyRawMonitor, jvmti_env, data->monitor);
|
|
}
|
|
|
|
/** Create JVMTI environment. */
|
|
jvmtiEnv* nsk_jvmti_createJVMTIEnv(JavaVM* javaVM, void* reserved) {
|
|
jvm = javaVM;
|
|
if (!NSK_VERIFY(
|
|
NSK_CPP_STUB3(GetEnv, javaVM, (void **)&jvmti_env, JVMTI_VERSION_1_1) == JNI_OK)) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NULL;
|
|
}
|
|
|
|
if (!NSK_JVMTI_VERIFY(init_agent_data(jvmti_env, &agent_data))) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NULL;
|
|
}
|
|
|
|
return jvmti_env;
|
|
}
|
|
|
|
/** Dispose JVMTI environment */
|
|
static int nsk_jvmti_disposeJVMTIEnv(jvmtiEnv* jvmti_env) {
|
|
if (jvmti_env != NULL) {
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB1(DisposeEnvironment, jvmti_env))) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NSK_FALSE;
|
|
}
|
|
|
|
if (!NSK_JVMTI_VERIFY(free_agent_data(jvmti_env, &agent_data))) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NSK_FALSE;
|
|
}
|
|
}
|
|
return NSK_TRUE;
|
|
}
|
|
|
|
/** Get JNI environment for agent thread. */
|
|
JNIEnv* nsk_jvmti_getAgentJNIEnv() {
|
|
return jni_env;
|
|
}
|
|
|
|
/** Get JVMTI environment for agent */
|
|
jvmtiEnv* nsk_jvmti_getAgentJVMTIEnv() {
|
|
return jvmti_env;
|
|
}
|
|
|
|
/* ============================================================================= */
|
|
static void set_agent_thread_state(thread_state_t value) {
|
|
rawMonitorEnter(jvmti_env, agent_data.monitor);
|
|
agent_data.thread_state = value;
|
|
rawMonitorNotify(jvmti_env, agent_data.monitor);
|
|
rawMonitorExit(jvmti_env, agent_data.monitor);
|
|
}
|
|
|
|
/** Wrapper for user agent thread. */
|
|
static void JNICALL
|
|
agentThreadWrapper(jvmtiEnv* jvmti_env, JNIEnv* agentJNI, void* arg) {
|
|
jni_env = agentJNI;
|
|
|
|
/* run user agent proc */
|
|
{
|
|
set_agent_thread_state(RUNNABLE);
|
|
|
|
NSK_TRACE((*agentThreadProc)(jvmti_env, agentJNI, agentThreadArg));
|
|
|
|
set_agent_thread_state(TERMINATED);
|
|
}
|
|
|
|
/* finalize agent thread */
|
|
{
|
|
/* gelete global ref for agent thread */
|
|
NSK_CPP_STUB2(DeleteGlobalRef, agentJNI, agentThread);
|
|
agentThread = NULL;
|
|
}
|
|
}
|
|
|
|
/** Start wrapper for user agent thread. */
|
|
static jthread startAgentThreadWrapper(JNIEnv *jni_env, jvmtiEnv* jvmti_env) {
|
|
const jint THREAD_PRIORITY = JVMTI_THREAD_MAX_PRIORITY;
|
|
const char* THREAD_NAME = "JVMTI agent thread";
|
|
const char* THREAD_CLASS_NAME = "java/lang/Thread";
|
|
const char* THREAD_CTOR_NAME = "<init>";
|
|
const char* THREAD_CTOR_SIGNATURE = "(Ljava/lang/String;)V";
|
|
|
|
jobject threadName = NULL;
|
|
jclass threadClass = NULL;
|
|
jmethodID threadCtor = NULL;
|
|
jobject threadObject = NULL;
|
|
jobject threadGlobalRef = NULL;
|
|
|
|
if (!NSK_JNI_VERIFY(jni_env, (threadClass =
|
|
NSK_CPP_STUB2(FindClass, jni_env, THREAD_CLASS_NAME)) != NULL)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!NSK_JNI_VERIFY(jni_env, (threadCtor =
|
|
NSK_CPP_STUB4(GetMethodID, jni_env, threadClass, THREAD_CTOR_NAME, THREAD_CTOR_SIGNATURE)) != NULL))
|
|
return NULL;
|
|
|
|
if (!NSK_JNI_VERIFY(jni_env, (threadName =
|
|
NSK_CPP_STUB2(NewStringUTF, jni_env, THREAD_NAME)) != NULL))
|
|
return NULL;
|
|
|
|
if (!NSK_JNI_VERIFY(jni_env, (threadObject =
|
|
NSK_CPP_STUB4(NewObject, jni_env, threadClass, threadCtor, threadName)) != NULL))
|
|
return NULL;
|
|
|
|
if (!NSK_JNI_VERIFY(jni_env, (threadGlobalRef =
|
|
NSK_CPP_STUB2(NewGlobalRef, jni_env, threadObject)) != NULL)) {
|
|
NSK_CPP_STUB2(DeleteLocalRef, jni_env, threadObject);
|
|
return NULL;
|
|
}
|
|
agentThread = (jthread)threadGlobalRef;
|
|
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB5(RunAgentThread, jvmti_env, agentThread,
|
|
&agentThreadWrapper, agentThreadArg, THREAD_PRIORITY))) {
|
|
NSK_CPP_STUB2(DeleteGlobalRef, jni_env, threadGlobalRef);
|
|
NSK_CPP_STUB2(DeleteLocalRef, jni_env, threadObject);
|
|
return NULL;
|
|
}
|
|
return agentThread;
|
|
}
|
|
|
|
/** Register user agent thread with arg. */
|
|
int nsk_jvmti_setAgentProc(jvmtiStartFunction proc, void* arg) {
|
|
agentThreadProc = proc;
|
|
agentThreadArg = arg;
|
|
return NSK_TRUE;
|
|
}
|
|
|
|
/** Get agent thread ref. */
|
|
jthread nsk_jvmti_getAgentThread() {
|
|
return agentThread;
|
|
}
|
|
|
|
/** Run registered user agent thread via wrapper. */
|
|
static jthread nsk_jvmti_runAgentThread(JNIEnv *jni_env, jvmtiEnv* jvmti_env) {
|
|
/* start agent thread wrapper */
|
|
jthread thread = startAgentThreadWrapper(jni_env, jvmti_env);
|
|
if (thread == NULL) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NULL;
|
|
}
|
|
|
|
return thread;
|
|
}
|
|
|
|
/* ============================================================================= */
|
|
|
|
/** Sleep current thread. */
|
|
void nsk_jvmti_sleep(jlong timeout) {
|
|
int seconds = (int)((timeout + 999) / 1000);
|
|
THREAD_sleep(seconds);
|
|
}
|
|
|
|
/** Sync point called from Java code. */
|
|
static jint syncDebuggeeStatus(JNIEnv* jni_env, jvmtiEnv* jvmti_env, jint debuggeeStatus) {
|
|
jint result = NSK_STATUS_FAILED;
|
|
|
|
rawMonitorEnter(jvmti_env, agent_data.monitor);
|
|
|
|
/* save last debugee status */
|
|
agent_data.last_debuggee_status = debuggeeStatus;
|
|
|
|
/* we don't enter if-stmt in second call */
|
|
if (agent_data.thread_state == NEW) {
|
|
if (nsk_jvmti_runAgentThread(jni_env, jvmti_env) == NULL)
|
|
goto monitor_exit_and_return;
|
|
|
|
/* SP2.2-w - wait for agent thread */
|
|
while (agent_data.thread_state == NEW) {
|
|
rawMonitorWait(jvmti_env, agent_data.monitor, 0);
|
|
}
|
|
}
|
|
|
|
/* wait for sync permit */
|
|
/* we don't enter loop in first call */
|
|
while (agent_data.thread_state != WAITING && agent_data.thread_state != TERMINATED) {
|
|
/* SP4.2-w - second wait for agent thread */
|
|
rawMonitorWait(jvmti_env, agent_data.monitor, 0);
|
|
}
|
|
|
|
if (agent_data.thread_state != TERMINATED) {
|
|
agent_data.thread_state = SUSPENDED;
|
|
/* SP3.2-n - notify to start test */
|
|
/* SP6.2-n - notify to end test */
|
|
rawMonitorNotify(jvmti_env, agent_data.monitor);
|
|
}
|
|
else {
|
|
NSK_COMPLAIN0("Debuggee status sync aborted because agent thread has finished\n");
|
|
goto monitor_exit_and_return;
|
|
}
|
|
|
|
/* update status from debuggee */
|
|
if (debuggeeStatus != NSK_STATUS_PASSED) {
|
|
nsk_jvmti_setFailStatus();
|
|
}
|
|
|
|
while (agent_data.thread_state == SUSPENDED) {
|
|
/* SP5.2-w - wait while testing */
|
|
/* SP7.2 - wait for agent end */
|
|
rawMonitorWait(jvmti_env, agent_data.monitor, 0);
|
|
}
|
|
|
|
agent_data.last_debuggee_status = nsk_jvmti_getStatus();
|
|
result = agent_data.last_debuggee_status;
|
|
|
|
monitor_exit_and_return:
|
|
rawMonitorExit(jvmti_env, agent_data.monitor);
|
|
return result;
|
|
}
|
|
|
|
/** Wait for sync point with Java code. */
|
|
int nsk_jvmti_waitForSync(jlong timeout) {
|
|
static const int inc_timeout = 1000;
|
|
|
|
jlong t = 0;
|
|
int result = NSK_TRUE;
|
|
|
|
rawMonitorEnter(jvmti_env, agent_data.monitor);
|
|
|
|
agent_data.thread_state = WAITING;
|
|
|
|
/* SP2.2-n - notify agent is waiting and wait */
|
|
/* SP4.1-n - notify agent is waiting and wait */
|
|
rawMonitorNotify(jvmti_env, agent_data.monitor);
|
|
|
|
while (agent_data.thread_state == WAITING) {
|
|
/* SP3.2-w - wait to start test */
|
|
/* SP6.2-w - wait to end test */
|
|
rawMonitorWait(jvmti_env, agent_data.monitor, inc_timeout);
|
|
|
|
if (timeout == 0) continue;
|
|
|
|
t += inc_timeout;
|
|
|
|
if (t >= timeout) break;
|
|
}
|
|
|
|
if (agent_data.thread_state == WAITING) {
|
|
NSK_COMPLAIN1("No status sync occured for timeout: %" LL "d ms\n", timeout);
|
|
nsk_jvmti_setFailStatus();
|
|
result = NSK_FALSE;
|
|
}
|
|
|
|
rawMonitorExit(jvmti_env, agent_data.monitor);
|
|
|
|
return result;
|
|
}
|
|
|
|
/** Resume java code suspended on sync point. */
|
|
int nsk_jvmti_resumeSync() {
|
|
int result;
|
|
rawMonitorEnter(jvmti_env, agent_data.monitor);
|
|
|
|
if (agent_data.thread_state == SUSPENDED) {
|
|
result = NSK_TRUE;
|
|
agent_data.thread_state = RUNNABLE;
|
|
/* SP5.2-n - notify suspend done */
|
|
/* SP7.2-n - notify agent end */
|
|
rawMonitorNotify(jvmti_env, agent_data.monitor);
|
|
}
|
|
else {
|
|
NSK_COMPLAIN0("Debuggee was not suspended on status sync\n");
|
|
nsk_jvmti_setFailStatus();
|
|
result = NSK_FALSE;
|
|
}
|
|
|
|
rawMonitorExit(jvmti_env, agent_data.monitor);
|
|
return NSK_TRUE;
|
|
}
|
|
|
|
/** Native function for Java code to provide sync point. */
|
|
JNIEXPORT jint JNICALL
|
|
Java_nsk_share_jvmti_DebugeeClass_checkStatus(JNIEnv* jni_env, jclass cls, jint debuggeeStatus) {
|
|
jint status;
|
|
NSK_TRACE(status = syncDebuggeeStatus(jni_env, jvmti_env, debuggeeStatus));
|
|
return status;
|
|
}
|
|
|
|
/** Native function for Java code to reset agent data. */
|
|
JNIEXPORT void JNICALL
|
|
Java_nsk_share_jvmti_DebugeeClass_resetAgentData(JNIEnv* jni_env, jclass cls) {
|
|
NSK_TRACE(nsk_jvmti_resetAgentData());
|
|
}
|
|
|
|
/* ============================================================================= */
|
|
|
|
/** Find loaded class by signature. */
|
|
jclass nsk_jvmti_classBySignature(const char signature[]) {
|
|
jclass* classes = NULL;
|
|
jint count = 0;
|
|
jclass foundClass = NULL;
|
|
int i;
|
|
|
|
if (!NSK_VERIFY(signature != NULL)) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NULL;
|
|
}
|
|
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB3(GetLoadedClasses, jvmti_env, &count, &classes))) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
char* sig = NULL;
|
|
char* generic = NULL;
|
|
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB4(GetClassSignature, jvmti_env, classes[i], &sig, &generic))) {
|
|
nsk_jvmti_setFailStatus();
|
|
break;
|
|
}
|
|
|
|
if (sig != NULL && strcmp(signature, sig) == 0) {
|
|
foundClass = classes[i];
|
|
}
|
|
|
|
if (!(NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)sig))
|
|
&& NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)generic)))) {
|
|
nsk_jvmti_setFailStatus();
|
|
break;
|
|
}
|
|
|
|
if (foundClass != NULL)
|
|
break;
|
|
}
|
|
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)classes))) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NULL;
|
|
}
|
|
|
|
if (!NSK_JNI_VERIFY(jni_env, (foundClass = (jclass)
|
|
NSK_CPP_STUB2(NewGlobalRef, jni_env, foundClass)) != NULL)) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NULL;
|
|
}
|
|
|
|
return foundClass;
|
|
}
|
|
|
|
/** Find alive thread by name. */
|
|
jthread nsk_jvmti_threadByName(const char name[]) {
|
|
jthread* threads = NULL;
|
|
jint count = 0;
|
|
jthread foundThread = NULL;
|
|
int i;
|
|
|
|
if (!NSK_VERIFY(name != NULL)) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NULL;
|
|
}
|
|
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB3(GetAllThreads, jvmti_env, &count, &threads))) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
jvmtiThreadInfo info;
|
|
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB3(GetThreadInfo, jvmti_env, threads[i], &info))) {
|
|
nsk_jvmti_setFailStatus();
|
|
break;
|
|
}
|
|
|
|
if (info.name != NULL && strcmp(name, info.name) == 0) {
|
|
foundThread = threads[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)threads))) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NULL;
|
|
}
|
|
|
|
if (!NSK_JNI_VERIFY(jni_env, (foundThread = (jthread)
|
|
NSK_CPP_STUB2(NewGlobalRef, jni_env, foundThread)) != NULL)) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NULL;
|
|
}
|
|
|
|
return foundThread;
|
|
}
|
|
|
|
|
|
/* ============================================================================= */
|
|
|
|
/** Add all capabilities for finding line locations. */
|
|
int nsk_jvmti_addLocationCapabilities() {
|
|
jvmtiCapabilities caps;
|
|
|
|
memset(&caps, 0, sizeof(caps));
|
|
caps.can_get_line_numbers = 1;
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB2(AddCapabilities, jvmti_env, &caps)))
|
|
return NSK_FALSE;
|
|
|
|
return NSK_TRUE;
|
|
}
|
|
|
|
/** Add all capabilities for using breakpoints. */
|
|
int nsk_jvmti_addBreakpointCapabilities() {
|
|
jvmtiCapabilities caps;
|
|
|
|
if (!nsk_jvmti_addLocationCapabilities())
|
|
return NSK_FALSE;
|
|
|
|
memset(&caps, 0, sizeof(caps));
|
|
caps.can_generate_breakpoint_events = 1;
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB2(AddCapabilities, jvmti_env, &caps)))
|
|
return NSK_FALSE;
|
|
|
|
return NSK_TRUE;
|
|
}
|
|
|
|
/** Find line location. */
|
|
jlocation nsk_jvmti_getLineLocation(jclass cls, jmethodID method, int line) {
|
|
jint count = 0;
|
|
jvmtiLineNumberEntry* table = NULL;
|
|
jlocation location = NSK_JVMTI_INVALID_JLOCATION;
|
|
int i;
|
|
|
|
if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetLineNumberTable, jvmti_env, method, &count, &table)))
|
|
return NSK_JVMTI_INVALID_JLOCATION;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (table[i].line_number == line) {
|
|
location = table[i].start_location;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)table)))
|
|
return NSK_JVMTI_INVALID_JLOCATION;
|
|
|
|
return location;
|
|
}
|
|
|
|
/** Set breakpoint to a line. */
|
|
jlocation nsk_jvmti_setLineBreakpoint(jclass cls, jmethodID method, int line) {
|
|
jlocation location = NSK_JVMTI_INVALID_JLOCATION;
|
|
|
|
if (!NSK_VERIFY((location =
|
|
nsk_jvmti_getLineLocation(cls, method, line)) != NSK_JVMTI_INVALID_JLOCATION))
|
|
return NSK_JVMTI_INVALID_JLOCATION;
|
|
|
|
if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetBreakpoint, jvmti_env, method, location)))
|
|
return NSK_JVMTI_INVALID_JLOCATION;
|
|
|
|
return location;
|
|
}
|
|
|
|
/** Remove breakpoint from a line. */
|
|
jlocation nsk_jvmti_clearLineBreakpoint(jclass cls, jmethodID method, int line) {
|
|
jlocation location = NSK_JVMTI_INVALID_JLOCATION;
|
|
|
|
if (!NSK_VERIFY((location =
|
|
nsk_jvmti_getLineLocation(cls, method, line)) != NSK_JVMTI_INVALID_JLOCATION))
|
|
return NSK_JVMTI_INVALID_JLOCATION;
|
|
|
|
if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(ClearBreakpoint, jvmti_env, method, location)))
|
|
return NSK_JVMTI_INVALID_JLOCATION;
|
|
|
|
return location;
|
|
}
|
|
|
|
/* ============================================================================= */
|
|
|
|
/** Enable or disable given events. */
|
|
int nsk_jvmti_enableEvents(jvmtiEventMode enable, int size, jvmtiEvent list[], jthread thread) {
|
|
int i;
|
|
|
|
for (i = 0; i < size; i++) {
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB4(SetEventNotificationMode, jvmti_env, enable,
|
|
list[i], thread))) {
|
|
nsk_jvmti_setFailStatus();
|
|
return NSK_FALSE;
|
|
}
|
|
}
|
|
return NSK_TRUE;
|
|
}
|
|
|
|
/* ============================================================================= */
|
|
|
|
typedef jint (JNICALL *checkStatus_type)(JNIEnv* jni_env, jclass cls, jint debuggeeStatus);
|
|
|
|
static checkStatus_type checkStatus_func = NULL;
|
|
|
|
/**
|
|
* Proxy function to gain sequential access to checkStatus of each agent
|
|
*/
|
|
JNIEXPORT jint JNICALL
|
|
MA_checkStatus(JNIEnv* jni_env, jclass cls, jint debuggeeStatus) {
|
|
jint status;
|
|
|
|
NSK_TRACE(status = syncDebuggeeStatus(jni_env, jvmti_env, debuggeeStatus));
|
|
return (*checkStatus_func)(jni_env, cls, status);
|
|
}
|
|
|
|
/**
|
|
* nativeMethodBind callback:
|
|
* if needed, redirects checkStatus native method call
|
|
*/
|
|
static void JNICALL nativeMethodBind(jvmtiEnv* jvmti_env, JNIEnv *jni_env,
|
|
jthread thread, jmethodID mid,
|
|
void* address, void** new_address_ptr) {
|
|
const char* BIND_CLASS_NAME = "Lnsk/share/jvmti/DebugeeClass;";
|
|
const char* BIND_METHOD_NAME = "checkStatus";
|
|
const char* BIND_METHOD_SIGNATURE = "(I)I";
|
|
|
|
jvmtiPhase phase;
|
|
jclass cls;
|
|
char *class_sig = NULL;
|
|
char *name = NULL;
|
|
char *sig = NULL;
|
|
|
|
if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetPhase, jvmti_env, &phase))) {
|
|
nsk_jvmti_setFailStatus();
|
|
return;
|
|
}
|
|
|
|
if (phase != JVMTI_PHASE_START && phase != JVMTI_PHASE_LIVE)
|
|
return;
|
|
|
|
if (NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB5(GetMethodName, jvmti_env, mid, &name, &sig, NULL))) {
|
|
if (strcmp(name, BIND_METHOD_NAME) == 0 &&
|
|
strcmp(sig, BIND_METHOD_SIGNATURE) == 0) {
|
|
|
|
if (NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB3(GetMethodDeclaringClass, jvmti_env, mid, &cls))
|
|
&& NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB4(GetClassSignature, jvmti_env, cls, &class_sig, NULL))
|
|
&& strcmp(class_sig, BIND_CLASS_NAME) == 0
|
|
&& address != (void*)Java_nsk_share_jvmti_DebugeeClass_checkStatus) {
|
|
checkStatus_func = (checkStatus_type)address;
|
|
NSK_TRACE(*new_address_ptr = (void*)MA_checkStatus);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (name != NULL)
|
|
NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)name);
|
|
|
|
if (sig != NULL)
|
|
NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)sig);
|
|
|
|
if (class_sig != NULL)
|
|
NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)class_sig);
|
|
}
|
|
|
|
/**
|
|
* Initialize multiple agent:
|
|
* establish processing of nativeMethodBind events
|
|
*/
|
|
int nsk_jvmti_init_MA(jvmtiEventCallbacks* callbacks) {
|
|
|
|
if (callbacks == NULL) {
|
|
NSK_COMPLAIN0("callbacks should not be NULL\n");
|
|
nsk_jvmti_setFailStatus();
|
|
return NSK_FALSE;
|
|
}
|
|
|
|
if (callbacks->NativeMethodBind != NULL) {
|
|
NSK_COMPLAIN0("callbacks.NativeMethodBind should be NULL\n");
|
|
nsk_jvmti_setFailStatus();
|
|
return NSK_FALSE;
|
|
}
|
|
|
|
{
|
|
jvmtiCapabilities caps;
|
|
memset(&caps, 0, sizeof(caps));
|
|
caps.can_generate_native_method_bind_events = 1;
|
|
if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities, jvmti_env, &caps)))
|
|
return NSK_FALSE;
|
|
}
|
|
|
|
callbacks->NativeMethodBind = nativeMethodBind;
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB3(SetEventCallbacks, jvmti_env, callbacks,
|
|
sizeof(jvmtiEventCallbacks))))
|
|
return NSK_FALSE;
|
|
|
|
if (!NSK_JVMTI_VERIFY(
|
|
NSK_CPP_STUB4(SetEventNotificationMode, jvmti_env, JVMTI_ENABLE,
|
|
JVMTI_EVENT_NATIVE_METHOD_BIND, NULL)))
|
|
return NSK_FALSE;
|
|
|
|
return NSK_TRUE;
|
|
}
|
|
|
|
/* ============================================================================= */
|
|
|
|
int nsk_jvmti_isOptionalEvent(jvmtiEvent event) {
|
|
|
|
return (event == JVMTI_EVENT_EXCEPTION)
|
|
|| (event == JVMTI_EVENT_EXCEPTION_CATCH)
|
|
|| (event == JVMTI_EVENT_SINGLE_STEP)
|
|
|| (event == JVMTI_EVENT_FRAME_POP)
|
|
|| (event == JVMTI_EVENT_BREAKPOINT)
|
|
|| (event == JVMTI_EVENT_FIELD_ACCESS)
|
|
|| (event == JVMTI_EVENT_FIELD_MODIFICATION)
|
|
|| (event == JVMTI_EVENT_METHOD_ENTRY)
|
|
|| (event == JVMTI_EVENT_METHOD_EXIT)
|
|
|| (event == JVMTI_EVENT_NATIVE_METHOD_BIND)
|
|
|| (event == JVMTI_EVENT_COMPILED_METHOD_LOAD)
|
|
|| (event == JVMTI_EVENT_COMPILED_METHOD_UNLOAD)
|
|
|| (event == JVMTI_EVENT_MONITOR_WAIT)
|
|
|| (event == JVMTI_EVENT_MONITOR_WAITED)
|
|
|| (event == JVMTI_EVENT_MONITOR_CONTENDED_ENTER)
|
|
|| (event == JVMTI_EVENT_MONITOR_CONTENDED_ENTERED)
|
|
|| (event == JVMTI_EVENT_GARBAGE_COLLECTION_START)
|
|
|| (event == JVMTI_EVENT_GARBAGE_COLLECTION_FINISH)
|
|
|| (event == JVMTI_EVENT_OBJECT_FREE)
|
|
|| (event == JVMTI_EVENT_VM_OBJECT_ALLOC);
|
|
}
|
|
|
|
/* ============================================================================= */
|
|
|
|
void nsk_jvmti_showPossessedCapabilities(jvmtiEnv *jvmti_env) {
|
|
|
|
jvmtiCapabilities caps;
|
|
|
|
if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetCapabilities, jvmti_env, &caps))) {
|
|
return;
|
|
}
|
|
|
|
NSK_DISPLAY0("\n");
|
|
NSK_DISPLAY0("Possessed capabilities:\n");
|
|
NSK_DISPLAY0("-----------------------\n");
|
|
if (caps.can_tag_objects)
|
|
NSK_DISPLAY0("\tcan_tag_objects\n");
|
|
if (caps.can_generate_field_modification_events)
|
|
NSK_DISPLAY0("\tcan_generate_field_modification_events\n");
|
|
if (caps.can_generate_field_access_events)
|
|
NSK_DISPLAY0("\tcan_generate_field_access_events\n");
|
|
if (caps.can_get_bytecodes)
|
|
NSK_DISPLAY0("\tcan_get_bytecodes\n");
|
|
if (caps.can_get_synthetic_attribute)
|
|
NSK_DISPLAY0("\tcan_get_synthetic_attribute\n");
|
|
if (caps.can_get_owned_monitor_info)
|
|
NSK_DISPLAY0("\tcan_get_owned_monitor_info\n");
|
|
if (caps.can_get_current_contended_monitor)
|
|
NSK_DISPLAY0("\tcan_get_current_contended_monitor\n");
|
|
if (caps.can_get_monitor_info)
|
|
NSK_DISPLAY0("\tcan_get_monitor_info\n");
|
|
if (caps.can_pop_frame)
|
|
NSK_DISPLAY0("\tcan_pop_frame\n");
|
|
if (caps.can_redefine_classes)
|
|
NSK_DISPLAY0("\tcan_redefine_classes\n");
|
|
if (caps.can_signal_thread)
|
|
NSK_DISPLAY0("\tcan_signal_thread\n");
|
|
if (caps.can_get_source_file_name)
|
|
NSK_DISPLAY0("\tcan_get_source_file_name\n");
|
|
if (caps.can_get_line_numbers)
|
|
NSK_DISPLAY0("\tcan_get_line_numbers\n");
|
|
if (caps.can_get_source_debug_extension)
|
|
NSK_DISPLAY0("\tcan_get_source_debug_extension\n");
|
|
if (caps.can_access_local_variables)
|
|
NSK_DISPLAY0("\tcan_access_local_variables\n");
|
|
if (caps.can_maintain_original_method_order)
|
|
NSK_DISPLAY0("\tcan_maintain_original_method_order\n");
|
|
if (caps.can_generate_single_step_events)
|
|
NSK_DISPLAY0("\tcan_generate_single_step_events\n");
|
|
if (caps.can_generate_exception_events)
|
|
NSK_DISPLAY0("\tcan_generate_exception_events\n");
|
|
if (caps.can_generate_frame_pop_events)
|
|
NSK_DISPLAY0("\tcan_generate_frame_pop_events\n");
|
|
if (caps.can_generate_breakpoint_events)
|
|
NSK_DISPLAY0("\tcan_generate_breakpoint_events\n");
|
|
if (caps.can_suspend)
|
|
NSK_DISPLAY0("\tcan_suspend\n");
|
|
if (caps.can_get_current_thread_cpu_time)
|
|
NSK_DISPLAY0("\tcan_get_current_thread_cpu_time\n");
|
|
if (caps.can_get_thread_cpu_time)
|
|
NSK_DISPLAY0("\tcan_get_thread_cpu_time\n");
|
|
if (caps.can_generate_method_entry_events)
|
|
NSK_DISPLAY0("\tcan_generate_method_entry_events\n");
|
|
if (caps.can_generate_method_exit_events)
|
|
NSK_DISPLAY0("\tcan_generate_method_exit_events\n");
|
|
if (caps.can_generate_all_class_hook_events)
|
|
NSK_DISPLAY0("\tcan_generate_all_class_hook_events\n");
|
|
if (caps.can_generate_compiled_method_load_events)
|
|
NSK_DISPLAY0("\tcan_generate_compiled_method_load_events\n");
|
|
if (caps.can_generate_monitor_events)
|
|
NSK_DISPLAY0("\tcan_generate_monitor_events\n");
|
|
if (caps.can_generate_vm_object_alloc_events)
|
|
NSK_DISPLAY0("\tcan_generate_vm_object_alloc_events\n");
|
|
if (caps.can_generate_native_method_bind_events)
|
|
NSK_DISPLAY0("\tcan_generate_native_method_bind_events\n");
|
|
if (caps.can_generate_garbage_collection_events)
|
|
NSK_DISPLAY0("\tcan_generate_garbage_collection_events\n");
|
|
if (caps.can_generate_object_free_events)
|
|
NSK_DISPLAY0("\tcan_generate_object_free_events\n");
|
|
|
|
NSK_DISPLAY0("\n");
|
|
}
|
|
|
|
/* ============================================================================= */
|
|
|
|
}
|