1 /*
2 * Copyright (c) 2003, 2018, 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 #include "agent_common.h"
28 #include "JVMTITools.h"
29
30 extern "C" {
31
32
33 #define METH_NUM 4 /* overall number of methods */
34
35 #define STATUS_FAILED 2
36 #define PASSED 0
37
38 /* line number matrix of original methods */
39 static int orig_ln[METH_NUM][8] = {
40 { 34, 0, 0, 0, 0, 0, 0, 0 }, /* <init> */
41 { 40,41,43, 0, 0, 0, 0, 0 }, /* checkIt */
42 { 55, 0, 0, 0, 0, 0, 0, 0 }, /* finMethod */
43 { 48,50,51,50,52, 0, 0, 0 } /* statMethod */
44 };
45
46 /* line number matrix of redefined methods */
47 static int redf_ln[METH_NUM][8] = {
48 { 38,39,40,41,42,43,44,46 }, /* <init> */
49 { 51,53,55, 0, 0, 0, 0, 0 }, /* checkIt */
50 { 64,66,67,68,69,70,72, 0 }, /* finMethod */
51 { 60, 0, 0, 0, 0, 0, 0, 0 } /* statMethod */
52 };
53
54 typedef struct { /* line numbers of a method */
55 int inst; /* type of a method: 0- static; 1- instance */
56 char *m_name; /* a method name */
57 char *m_sign; /* JVM signature of a method */
58 int lcount; /* line numbers quantity */
59 jmethodID mid; /* JNI's method ID */
60 } methInfo;
61
62 /* list of original methods */
63 static methInfo origMethInfo[] = {
64 { 1, (char*) "<init>", (char*) "()V", 1, NULL },
65 { 1, (char*) "checkIt", (char*) "(Ljava/io/PrintStream;Z)I", 3, NULL },
66 { 1, (char*) "finMethod", (char*) "(CJIJ)V", 1, NULL },
67 { 0, (char*) "statMethod", (char*) "(III)D", 5, NULL }
68 };
69
70 /* list of redefined methods */
71 static methInfo redefMethInfo[] = {
72 { 1, (char*) "<init>", (char*) "()V", 8, NULL },
73 { 1, (char*) "checkIt", (char*) "(Ljava/io/PrintStream;Z)I", 3, NULL },
74 { 1, (char*) "finMethod", (char*) "(CJIJ)V", 7, NULL },
75 { 0, (char*) "statMethod", (char*) "(III)D", 1, NULL }
76 };
77
78 static jvmtiEnv *jvmti = NULL;
79 static jvmtiCapabilities caps;
80
81 #ifdef STATIC_BUILD
Agent_OnLoad_redefclass010(JavaVM * jvm,char * options,void * reserved)82 JNIEXPORT jint JNICALL Agent_OnLoad_redefclass010(JavaVM *jvm, char *options, void *reserved) {
83 return Agent_Initialize(jvm, options, reserved);
84 }
Agent_OnAttach_redefclass010(JavaVM * jvm,char * options,void * reserved)85 JNIEXPORT jint JNICALL Agent_OnAttach_redefclass010(JavaVM *jvm, char *options, void *reserved) {
86 return Agent_Initialize(jvm, options, reserved);
87 }
JNI_OnLoad_redefclass010(JavaVM * jvm,char * options,void * reserved)88 JNIEXPORT jint JNI_OnLoad_redefclass010(JavaVM *jvm, char *options, void *reserved) {
89 return JNI_VERSION_1_8;
90 }
91 #endif
Agent_Initialize(JavaVM * vm,char * options,void * reserved)92 jint Agent_Initialize(JavaVM *vm, char *options, void *reserved) {
93 jint res;
94 jvmtiError err;
95
96 res = vm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
97 if (res != JNI_OK) {
98 printf("%s: Failed to call GetEnv: error=%d\n", __FILE__, res);
99 return JNI_ERR;
100 }
101
102 err = jvmti->GetPotentialCapabilities(&caps);
103 if (err != JVMTI_ERROR_NONE) {
104 printf("(GetPotentialCapabilities) unexpected error: %s (%d)\n",
105 TranslateError(err), err);
106 return JNI_ERR;
107 }
108
109 err = jvmti->AddCapabilities(&caps);
110 if (err != JVMTI_ERROR_NONE) {
111 printf("(AddCapabilities) unexpected error: %s (%d)\n",
112 TranslateError(err), err);
113 return JNI_ERR;
114 }
115
116 err = jvmti->GetCapabilities(&caps);
117 if (err != JVMTI_ERROR_NONE) {
118 printf("(GetCapabilities) unexpected error: %s (%d)\n",
119 TranslateError(err), err);
120 return JNI_ERR;
121 }
122
123 if (!caps.can_redefine_classes) {
124 printf("Warning: RedefineClasses is not implemented\n");
125 }
126
127 if (!caps.can_get_line_numbers) {
128 printf("Warning: no access to line number info\n");
129 }
130
131 return JNI_OK;
132 }
133
checkAttr(JNIEnv * env,jclass redefCls,methInfo methodsInfo[],jint vrb)134 int checkAttr(JNIEnv *env, jclass redefCls, methInfo methodsInfo[], jint vrb) {
135 jvmtiError err;
136 int i, j, chkval = 0;
137 int totRes = PASSED;
138 jint count = -1;
139 jvmtiLineNumberEntry *ln_table;
140
141 if (!caps.can_get_line_numbers) {
142 return PASSED;
143 }
144
145 for (i=0; i<METH_NUM; i++) {
146 /* get the JNI method ID for a method with name m_name and
147 signature m_sign */
148 if (methodsInfo[i].inst) { /* an instance method */
149 methodsInfo[i].mid = env->GetMethodID(redefCls,
150 methodsInfo[i].m_name, methodsInfo[i].m_sign);
151 } else { /* a static method */
152 methodsInfo[i].mid = env->GetStaticMethodID(redefCls,
153 methodsInfo[i].m_name, methodsInfo[i].m_sign);
154 }
155 if (methodsInfo[i].mid == NULL) {
156 printf("%s: Failed to get the method ID for the%s%s method \"%s\", signature \"%s\"\n",
157 __FILE__, (vrb == 2) ? " original " : " ",
158 methodsInfo[i].inst ? "instance" : "static",
159 methodsInfo[i].m_name, methodsInfo[i].m_sign);
160 return STATUS_FAILED;
161 }
162
163 /* get the LineNumberTable attribute */
164 err = jvmti->GetLineNumberTable(methodsInfo[i].mid, &count, &ln_table);
165 if (err != JVMTI_ERROR_NONE) {
166 printf("%s: Failed to call GetLineNumberTable(): error=%d: %s\n",
167 __FILE__, err, TranslateError(err));
168 printf("\tfor the%s%s method \"%s\", signature \"%s\"\n\n",
169 (vrb == 2) ? " original " : " ",
170 methodsInfo[i].inst ? "instance" : "static",
171 methodsInfo[i].m_name, methodsInfo[i].m_sign);
172 return STATUS_FAILED;
173 } else {
174 if (count != methodsInfo[i].lcount) {
175 printf(
176 "TEST %s %s method \"%s\", signature \"%s\": found %d lines in the LineNumberTable, expected %d\n",
177 (vrb == 2) ? "BUG: original " : "FAILED:",
178 methodsInfo[i].inst ? "instance" : "static",
179 methodsInfo[i].m_name, methodsInfo[i].m_sign,
180 count, methodsInfo[i].lcount);
181 totRes = STATUS_FAILED;
182 continue;
183 }
184 else if (vrb == 1)
185 printf(
186 "\nChecking line numbers in the LineNumberTable of the %s method \"%s\", signature \"%s\" ...\n"
187 "\toverall number of lines: %d as expected\n",
188 methodsInfo[i].inst ? "instance" : "static",
189 methodsInfo[i].m_name, methodsInfo[i].m_sign, count);
190
191 for (j=0; j<count; j++) {
192 if (vrb == 2)
193 chkval = orig_ln[i][j];
194 else
195 chkval = redf_ln[i][j];
196
197 if (ln_table[j].line_number != chkval) {
198 printf(
199 "TEST %s %s method \"%s\", signature \"%s\": "
200 "entry #%d has value %d in the LineNumberTable, expected %d\n",
201 (vrb == 2) ? "BUG: original" : "FAILED:",
202 methodsInfo[i].inst ? "instance" : "static",
203 methodsInfo[i].m_name, methodsInfo[i].m_sign,
204 j, ln_table[j].line_number, chkval);
205 totRes = STATUS_FAILED;
206 break;
207 }
208 else if (vrb == 1)
209 printf("\tentry #%d has value %d as expected\n",
210 j, ln_table[j].line_number);
211 }
212 }
213 }
214 return totRes;
215 }
216
217 JNIEXPORT jint JNICALL
Java_nsk_jvmti_RedefineClasses_redefclass010_checkOrigAttr(JNIEnv * env,jclass cls,jobject redefObj)218 Java_nsk_jvmti_RedefineClasses_redefclass010_checkOrigAttr(JNIEnv *env,
219 jclass cls, jobject redefObj) {
220 jclass redefCls = env->GetObjectClass(redefObj);
221 return checkAttr(env, redefCls, origMethInfo, 2);
222 }
223
224 JNIEXPORT jint JNICALL
Java_nsk_jvmti_RedefineClasses_redefclass010_makeRedefinition(JNIEnv * env,jclass cls,jint vrb,jclass redefCls,jbyteArray classBytes)225 Java_nsk_jvmti_RedefineClasses_redefclass010_makeRedefinition(JNIEnv *env,
226 jclass cls, jint vrb, jclass redefCls, jbyteArray classBytes) {
227 jvmtiError err;
228 jvmtiClassDefinition classDef;
229
230 if (jvmti == NULL) {
231 printf("JVMTI client was not properly loaded!\n");
232 return STATUS_FAILED;
233 }
234
235 if (!caps.can_redefine_classes) {
236 return PASSED;
237 }
238
239 /* fill the structure jvmtiClassDefinition */
240 classDef.klass = redefCls;
241 classDef.class_byte_count = env->GetArrayLength(classBytes);
242 classDef.class_bytes = (unsigned char *) env->GetByteArrayElements(classBytes, NULL);
243
244 if (vrb)
245 printf("\n>>>>>>>> Invoke RedefineClasses():\n\tnew class byte count=%d\n",
246 classDef.class_byte_count);
247 err = jvmti->RedefineClasses(1, &classDef);
248 if (err != JVMTI_ERROR_NONE) {
249 printf("%s: Failed to call RedefineClasses(): error=%d: %s\n",
250 __FILE__, err, TranslateError(err));
251 printf("\tFor more info about this error see the JVMTI spec.\n");
252 return JNI_ERR;
253 }
254 if (vrb)
255 printf("<<<<<<<< RedefineClasses() is successfully done\n\n");
256
257 return PASSED;
258 }
259
260 JNIEXPORT jint JNICALL
Java_nsk_jvmti_RedefineClasses_redefclass010_getResult(JNIEnv * env,jclass cls,jint vrb,jobject redefObj)261 Java_nsk_jvmti_RedefineClasses_redefclass010_getResult(JNIEnv *env,
262 jclass cls, jint vrb, jobject redefObj) {
263 jclass redefCls = env->GetObjectClass(redefObj);
264 return checkAttr(env, redefCls, redefMethInfo, vrb);
265 }
266
267 }
268