1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 #include <stdio.h> 25 #include <string.h> 26 #include "jvmti.h" 27 28 #ifdef __cplusplus 29 extern "C" { 30 #endif 31 32 #ifndef JNI_ENV_ARG 33 34 #ifdef __cplusplus 35 #define JNI_ENV_ARG(x, y) y 36 #define JNI_ENV_PTR(x) x 37 #else 38 #define JNI_ENV_ARG(x,y) x, y 39 #define JNI_ENV_PTR(x) (*x) 40 #endif 41 42 #endif 43 44 #define TranslateError(err) "JVMTI error" 45 46 static jvmtiEnv *jvmti = NULL; 47 48 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); 49 50 JNIEXPORT 51 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 52 return Agent_Initialize(jvm, options, reserved); 53 } 54 55 JNIEXPORT 56 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 57 return Agent_Initialize(jvm, options, reserved); 58 } 59 60 JNIEXPORT 61 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { 62 return JNI_VERSION_9; 63 } 64 65 66 static jint newClassDataLen = 0; 67 static unsigned char* newClassData = NULL; 68 69 static jint 70 getBytecodes(jvmtiEnv *jvmti_env, 71 jint class_data_len, const unsigned char* class_data) { 72 int i; 73 jint res; 74 75 newClassDataLen = class_data_len; 76 res = (*jvmti_env)->Allocate(jvmti_env, newClassDataLen, &newClassData); 77 if (res != JNI_OK) { 78 printf(" Unable to allocate bytes\n"); 79 return JNI_ERR; 80 } 81 for (i = 0; i < newClassDataLen; i++) { 82 newClassData[i] = class_data[i]; 83 // Rewrite oo in class to aa 84 if (i > 0 && class_data[i] == 'o' && class_data[i-1] == 'o') { 85 newClassData[i] = newClassData[i-1] = 'a'; 86 } 87 } 88 printf(" ... copied bytecode: %d bytes\n", (int)newClassDataLen); 89 return JNI_OK; 90 } 91 92 93 static void JNICALL 94 Callback_ClassFileLoadHook(jvmtiEnv *jvmti_env, JNIEnv *env, 95 jclass class_being_redefined, 96 jobject loader, const char* name, jobject protection_domain, 97 jint class_data_len, const unsigned char* class_data, 98 jint *new_class_data_len, unsigned char** new_class_data) { 99 if (name != NULL && strcmp(name, "RedefineDoubleDelete$B") == 0) { 100 if (newClassData == NULL) { 101 jint res = getBytecodes(jvmti_env, class_data_len, class_data); 102 if (res == JNI_ERR) { 103 printf(">>> ClassFileLoadHook event: class name %s FAILED\n", name); 104 return; 105 } 106 // Only change for first CFLH event. 107 *new_class_data_len = newClassDataLen; 108 *new_class_data = newClassData; 109 } 110 printf(">>> ClassFileLoadHook event: class name %s\n", name); 111 } 112 } 113 114 static 115 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 116 jint res, size; 117 jvmtiCapabilities caps; 118 jvmtiEventCallbacks callbacks; 119 jvmtiError err; 120 121 res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), 122 JVMTI_VERSION_9); 123 if (res != JNI_OK || jvmti == NULL) { 124 printf(" Error: wrong result of a valid call to GetEnv!\n"); 125 return JNI_ERR; 126 } 127 128 printf("Enabling following capabilities: can_generate_all_class_hook_events, " 129 "can_retransform_classes, can_redefine_classes"); 130 memset(&caps, 0, sizeof(caps)); 131 caps.can_generate_all_class_hook_events = 1; 132 caps.can_retransform_classes = 1; 133 caps.can_redefine_classes = 1; 134 printf("\n"); 135 136 err = (*jvmti)->AddCapabilities(jvmti, &caps); 137 if (err != JVMTI_ERROR_NONE) { 138 printf(" Error in AddCapabilites: %s (%d)\n", TranslateError(err), err); 139 return JNI_ERR; 140 } 141 142 size = (jint)sizeof(callbacks); 143 144 memset(&callbacks, 0, sizeof(callbacks)); 145 callbacks.ClassFileLoadHook = Callback_ClassFileLoadHook; 146 147 err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size); 148 if (err != JVMTI_ERROR_NONE) { 149 printf(" Error in SetEventCallbacks: %s (%d)\n", TranslateError(err), err); 150 return JNI_ERR; 151 } 152 153 err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); 154 if (err != JVMTI_ERROR_NONE) { 155 printf(" Error in SetEventNotificationMode: %s (%d)\n", TranslateError(err), err); 156 return JNI_ERR; 157 } 158 159 return JNI_OK; 160 } 161 162 #ifdef __cplusplus 163 } 164 #endif