| /* |
| * Copyright (c) 2007, 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 "jvmti.h" |
| #include "jni_tools.h" |
| #include "jvmti_tools.h" |
| #include "agent_common.h" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /* ============================================================================= */ |
| |
| static jlong timeout = 0; |
| |
| static char segment1[3000] = ""; |
| static char segment2[3000] = ""; |
| |
| static const char* const illegal_segments[] = {"", "tmp/"}; |
| |
| jboolean use_segment2 = JNI_FALSE; |
| |
| jvmtiPhase jvmti_phase_to_check = JVMTI_PHASE_ONLOAD; |
| |
| /* ============================================================================= */ |
| |
| /** |
| * Add segment to bootstrap classloader path. |
| * @returns NSK_FALSE if any error occured. |
| */ |
| static int addSegment(jvmtiEnv* jvmti, const char segment[], const char where[]) { |
| NSK_DISPLAY1("Add segment: \"%s\"\n", segment); |
| if (!NSK_JVMTI_VERIFY( |
| NSK_CPP_STUB2(AddToBootstrapClassLoaderSearch, jvmti, segment))) { |
| NSK_COMPLAIN1("TEST FAILURE: failed to add segment %s\n", segment); |
| return NSK_FALSE; |
| } |
| NSK_DISPLAY0(" ... added\n"); |
| |
| return NSK_TRUE; |
| } |
| |
| /** |
| * Try to add illegal segment to bootstrap classloader path and check that expected error |
| * (expectedError) is returned. |
| * @returns NSK_FALSE if no error or wronf error is occured. |
| */ |
| static int addIllegalSegment(jvmtiEnv* jvmti, const char segment[], const char where[], jvmtiError expectedError) { |
| NSK_DISPLAY1("Add illegal segment: \"%s\"\n", segment); |
| if (!NSK_JVMTI_VERIFY_CODE(expectedError, |
| NSK_CPP_STUB2(AddToBootstrapClassLoaderSearch, jvmti, segment))) { |
| |
| NSK_COMPLAIN2("TEST FAILURE: got wrong error when tried to add segment %s (expected error=%s)\n", |
| segment, TranslateError(expectedError)); |
| return NSK_FALSE; |
| } |
| NSK_DISPLAY0(" ... not added\n"); |
| |
| return NSK_TRUE; |
| } |
| |
| /* |
| * Check that attempt to add illegal segment causes the error. |
| */ |
| static void checkLivePhaseForIllegalArgs (jvmtiEnv* jvmti, const char where[]) { |
| size_t i; |
| |
| for (i = 0; i < sizeof(illegal_segments)/sizeof(char*); i++) { |
| if (!addIllegalSegment(jvmti, illegal_segments[i], where, JVMTI_ERROR_ILLEGAL_ARGUMENT)) { |
| nsk_jvmti_setFailStatus(); |
| NSK_BEFORE_TRACE(exit(nsk_jvmti_getStatus())); |
| } |
| } |
| } |
| |
| /* ============================================================================= */ |
| |
| void JNICALL |
| callbackVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) { |
| NSK_DISPLAY0(">>> Testcase #1: Add bootstrap class load segment(s) in VMInit (live phase)\n"); |
| |
| // At first check that it is not possible to add anything other than an existing JAR file |
| checkLivePhaseForIllegalArgs(jvmti, "VMInit()"); |
| |
| if (!addSegment(jvmti, segment1, "VMInit()")) { |
| nsk_jvmti_setFailStatus(); |
| NSK_BEFORE_TRACE(exit(nsk_jvmti_getStatus())); |
| } |
| |
| if (use_segment2 == JNI_FALSE) return; |
| |
| if (!addSegment(jvmti, segment2, "VMInit()")) { |
| nsk_jvmti_setFailStatus(); |
| NSK_BEFORE_TRACE(exit(nsk_jvmti_getStatus())); |
| } |
| } |
| |
| /* |
| * Check that it is possible to add to the boot class path before VMDeath event return. |
| */ |
| void JNICALL |
| callbackVMDeath(jvmtiEnv *jvmti, JNIEnv* jni) { |
| jvmtiPhase phase; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetPhase, jvmti, &phase))) { |
| NSK_COMPLAIN0("TEST FAILURE: unable to get phase\n"); |
| nsk_jvmti_setFailStatus(); |
| NSK_BEFORE_TRACE(exit(nsk_jvmti_getStatus())); |
| } |
| |
| if (!NSK_VERIFY(phase == JVMTI_PHASE_LIVE)) { |
| NSK_DISPLAY0(">>> Testcase #1: Add bootstrap class load segment(s) in VMDeath (live phase)\n"); |
| |
| // At first check that it is not possible to add anything other than an existing JAR file |
| checkLivePhaseForIllegalArgs(jvmti, "VMDeath()"); |
| |
| /* Check, that it is possible to add a JAR file containing a class that is already |
| * loaded (or is in the process of being loaded) by a _bootstrap_ class loader. |
| */ |
| |
| if (!addSegment(jvmti, segment1, "VMDeath()")) { |
| nsk_jvmti_setFailStatus(); |
| NSK_BEFORE_TRACE(exit(nsk_jvmti_getStatus())); |
| } |
| |
| if (use_segment2 == JNI_FALSE) return; |
| // otherwise add to classpath |
| if (!addSegment(jvmti, segment2, "VMDeath()")) { |
| nsk_jvmti_setFailStatus(); |
| NSK_BEFORE_TRACE(exit(nsk_jvmti_getStatus())); |
| } |
| } |
| } |
| |
| /** Agent library initialization. */ |
| jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { |
| jvmtiEnv* jvmti; |
| const char *p_segment1, *p_segment2, *phase_to_check; |
| |
| jvmti = NULL; |
| p_segment1 = p_segment2 = phase_to_check = NULL; |
| |
| if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) |
| return JNI_ERR; |
| |
| timeout = nsk_jvmti_getWaitTime() * 60 * 1000; |
| |
| p_segment1 = nsk_jvmti_findOptionStringValue("segment1", NULL); |
| if (!NSK_VERIFY(p_segment1 != NULL)) { |
| return JNI_ERR; |
| } else { |
| strncpy(segment1, p_segment1, (size_t) sizeof(segment1)/sizeof(char)); |
| segment1[(size_t) sizeof(segment1)/sizeof(char) - 1] = 0; |
| } |
| |
| // 'segment2' parameter is not mandatory |
| p_segment2 = nsk_jvmti_findOptionStringValue("segment2", NULL); |
| if (p_segment2 != NULL) { |
| strncpy(segment2, p_segment2, (size_t) sizeof(segment2)/sizeof(char)); |
| segment2[(size_t) sizeof(segment2)/sizeof(char) - 1] = 0; |
| use_segment2 = JNI_TRUE; |
| } |
| |
| if (!NSK_VERIFY((jvmti = |
| nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) |
| return JNI_ERR; |
| |
| // Check what phase(s) we are going to test |
| phase_to_check = nsk_jvmti_findOptionStringValue("phasetocheck", NULL); |
| if (!NSK_VERIFY(phase_to_check != NULL)) { |
| return JNI_ERR; |
| } else if (strcmp(phase_to_check, "onload") == 0) { |
| jvmti_phase_to_check = JVMTI_PHASE_ONLOAD; |
| } else if (strcmp(phase_to_check, "live") == 0) { |
| jvmti_phase_to_check = JVMTI_PHASE_LIVE; |
| } |
| |
| if (jvmti_phase_to_check == JVMTI_PHASE_ONLOAD) { |
| NSK_DISPLAY0(">>> Testcase #1: Add bootstrap class load segment in Agent_OnLoad()\n"); |
| if (!addSegment(jvmti, segment1, "Agent_OnLoad()")) { |
| return JNI_ERR; |
| } |
| |
| if (!addSegment(jvmti, segment2, "Agent_OnLoad()")) { |
| return JNI_ERR; |
| } |
| |
| return JNI_OK; |
| } |
| |
| /* For Live phase enable events and set callbacks for them */ |
| NSK_DISPLAY1("Set callback for events: %s\n", "VM_INIT, VM_DEATH"); |
| { |
| jvmtiEventCallbacks eventCallbacks; |
| memset(&eventCallbacks, 0, sizeof(eventCallbacks)); |
| |
| eventCallbacks.VMInit = callbackVMInit; |
| eventCallbacks.VMDeath = callbackVMDeath; |
| |
| if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks, jvmti, |
| &eventCallbacks, sizeof(eventCallbacks)))) { |
| return JNI_ERR; |
| } |
| } |
| NSK_DISPLAY0(" ... set\n"); |
| |
| NSK_DISPLAY1("Enable events: %s\n", "VM_INIT, VM_DEATH"); |
| { |
| |
| jvmtiEvent eventsList[] = { JVMTI_EVENT_VM_INIT, JVMTI_EVENT_VM_DEATH }; |
| if (!NSK_VERIFY(nsk_jvmti_enableEvents( |
| JVMTI_ENABLE, sizeof(eventsList)/sizeof(jvmtiEvent), eventsList, NULL))) { |
| return JNI_ERR; |
| } |
| } |
| NSK_DISPLAY0(" ... enabled\n"); |
| |
| return JNI_OK; |
| } |
| |
| /* ============================================================================= */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |