1 | /*
|
---|
2 | * Copyright (c) 1998, 2006, 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. Oracle designates this
|
---|
8 | * particular file as subject to the "Classpath" exception as provided
|
---|
9 | * by Oracle in the LICENSE file that accompanied this code.
|
---|
10 | *
|
---|
11 | * This code is distributed in the hope that it will be useful, but WITHOUT
|
---|
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
---|
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
---|
14 | * version 2 for more details (a copy is included in the LICENSE file that
|
---|
15 | * accompanied this code).
|
---|
16 | *
|
---|
17 | * You should have received a copy of the GNU General Public License version
|
---|
18 | * 2 along with this work; if not, write to the Free Software Foundation,
|
---|
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
---|
20 | *
|
---|
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
---|
22 | * or visit www.oracle.com if you need additional information or have any
|
---|
23 | * questions.
|
---|
24 | */
|
---|
25 |
|
---|
26 | #include "util.h"
|
---|
27 | #include "VirtualMachineImpl.h"
|
---|
28 | #include "commonRef.h"
|
---|
29 | #include "inStream.h"
|
---|
30 | #include "outStream.h"
|
---|
31 | #include "eventHandler.h"
|
---|
32 | #include "eventHelper.h"
|
---|
33 | #include "threadControl.h"
|
---|
34 | #include "SDE.h"
|
---|
35 | #include "FrameID.h"
|
---|
36 |
|
---|
37 | static char *versionName = "Java Debug Wire Protocol (Reference Implementation)";
|
---|
38 | static int majorVersion = 1; /* JDWP major version */
|
---|
39 | static int minorVersion = 6; /* JDWP minor version */
|
---|
40 |
|
---|
41 | static jboolean
|
---|
42 | version(PacketInputStream *in, PacketOutputStream *out)
|
---|
43 | {
|
---|
44 | char buf[500];
|
---|
45 | char *vmName;
|
---|
46 | char *vmVersion;
|
---|
47 | char *vmInfo;
|
---|
48 |
|
---|
49 | if (gdata->vmDead) {
|
---|
50 | outStream_setError(out, JDWP_ERROR(VM_DEAD));
|
---|
51 | return JNI_TRUE;
|
---|
52 | }
|
---|
53 |
|
---|
54 | vmVersion = gdata->property_java_version;
|
---|
55 | if (vmVersion == NULL) {
|
---|
56 | vmVersion = "<unknown>";
|
---|
57 | }
|
---|
58 | vmName = gdata->property_java_vm_name;
|
---|
59 | if (vmName == NULL) {
|
---|
60 | vmName = "<unknown>";
|
---|
61 | }
|
---|
62 | vmInfo = gdata->property_java_vm_info;
|
---|
63 | if (vmInfo == NULL) {
|
---|
64 | vmInfo = "<unknown>";
|
---|
65 | }
|
---|
66 |
|
---|
67 | /*
|
---|
68 | * Write the descriptive version information
|
---|
69 | */
|
---|
70 | (void)snprintf(buf, sizeof(buf),
|
---|
71 | "%s version %d.%d\nJVM Debug Interface version %d.%d\n"
|
---|
72 | "JVM version %s (%s, %s)",
|
---|
73 | versionName, majorVersion, minorVersion,
|
---|
74 | jvmtiMajorVersion(), jvmtiMinorVersion(),
|
---|
75 | vmVersion, vmName, vmInfo);
|
---|
76 | (void)outStream_writeString(out, buf);
|
---|
77 |
|
---|
78 | /*
|
---|
79 | * Write the JDWP version numbers
|
---|
80 | */
|
---|
81 | (void)outStream_writeInt(out, majorVersion);
|
---|
82 | (void)outStream_writeInt(out, minorVersion);
|
---|
83 |
|
---|
84 | /*
|
---|
85 | * Write the VM version and name
|
---|
86 | */
|
---|
87 | (void)outStream_writeString(out, vmVersion);
|
---|
88 | (void)outStream_writeString(out, vmName);
|
---|
89 |
|
---|
90 | return JNI_TRUE;
|
---|
91 | }
|
---|
92 |
|
---|
93 | static jboolean
|
---|
94 | classesForSignature(PacketInputStream *in, PacketOutputStream *out)
|
---|
95 | {
|
---|
96 | JNIEnv *env;
|
---|
97 | char *signature;
|
---|
98 |
|
---|
99 | if (gdata->vmDead) {
|
---|
100 | outStream_setError(out, JDWP_ERROR(VM_DEAD));
|
---|
101 | return JNI_TRUE;
|
---|
102 | }
|
---|
103 |
|
---|
104 | signature = inStream_readString(in);
|
---|
105 | if (signature == NULL) {
|
---|
106 | outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
|
---|
107 | return JNI_TRUE;
|
---|
108 | }
|
---|
109 | if (inStream_error(in)) {
|
---|
110 | return JNI_TRUE;
|
---|
111 | }
|
---|
112 |
|
---|
113 | env = getEnv();
|
---|
114 |
|
---|
115 | WITH_LOCAL_REFS(env, 1) {
|
---|
116 |
|
---|
117 | jint classCount;
|
---|
118 | jclass *theClasses;
|
---|
119 | jvmtiError error;
|
---|
120 |
|
---|
121 | error = allLoadedClasses(&theClasses, &classCount);
|
---|
122 | if ( error == JVMTI_ERROR_NONE ) {
|
---|
123 | /* Count classes in theClasses which match signature */
|
---|
124 | int matchCount = 0;
|
---|
125 | /* Count classes written to the JDWP connection */
|
---|
126 | int writtenCount = 0;
|
---|
127 | int i;
|
---|
128 |
|
---|
129 | for (i=0; i<classCount; i++) {
|
---|
130 | jclass clazz = theClasses[i];
|
---|
131 | jint status = classStatus(clazz);
|
---|
132 | char *candidate_signature = NULL;
|
---|
133 | jint wanted =
|
---|
134 | (JVMTI_CLASS_STATUS_PREPARED|JVMTI_CLASS_STATUS_ARRAY|
|
---|
135 | JVMTI_CLASS_STATUS_PRIMITIVE);
|
---|
136 |
|
---|
137 | /* We want prepared classes, primitives, and arrays only */
|
---|
138 | if ((status & wanted) == 0) {
|
---|
139 | continue;
|
---|
140 | }
|
---|
141 |
|
---|
142 | error = classSignature(clazz, &candidate_signature, NULL);
|
---|
143 | if (error != JVMTI_ERROR_NONE) {
|
---|
144 | break;
|
---|
145 | }
|
---|
146 |
|
---|
147 | if (strcmp(candidate_signature, signature) == 0) {
|
---|
148 | /* Float interesting classes (those that
|
---|
149 | * are matching and are prepared) to the
|
---|
150 | * beginning of the array.
|
---|
151 | */
|
---|
152 | theClasses[i] = theClasses[matchCount];
|
---|
153 | theClasses[matchCount++] = clazz;
|
---|
154 | }
|
---|
155 | jvmtiDeallocate(candidate_signature);
|
---|
156 | }
|
---|
157 |
|
---|
158 | /* At this point matching prepared classes occupy
|
---|
159 | * indicies 0 thru matchCount-1 of theClasses.
|
---|
160 | */
|
---|
161 |
|
---|
162 | if ( error == JVMTI_ERROR_NONE ) {
|
---|
163 | (void)outStream_writeInt(out, matchCount);
|
---|
164 | for (; writtenCount < matchCount; writtenCount++) {
|
---|
165 | jclass clazz = theClasses[writtenCount];
|
---|
166 | jint status = classStatus(clazz);
|
---|
167 | jbyte tag = referenceTypeTag(clazz);
|
---|
168 | (void)outStream_writeByte(out, tag);
|
---|
169 | (void)outStream_writeObjectRef(env, out, clazz);
|
---|
170 | (void)outStream_writeInt(out, map2jdwpClassStatus(status));
|
---|
171 | /* No point in continuing if there's an error */
|
---|
172 | if (outStream_error(out)) {
|
---|
173 | break;
|
---|
174 | }
|
---|
175 | }
|
---|
176 | }
|
---|
177 |
|
---|
178 | jvmtiDeallocate(theClasses);
|
---|
179 | }
|
---|
180 |
|
---|
181 | if ( error != JVMTI_ERROR_NONE ) {
|
---|
182 | outStream_setError(out, map2jdwpError(error));
|
---|
183 | }
|
---|
184 |
|
---|
185 | } END_WITH_LOCAL_REFS(env);
|
---|
186 |
|
---|
187 | jvmtiDeallocate(signature);
|
---|
188 |
|
---|
189 | return JNI_TRUE;
|
---|
190 | }
|
---|
191 |
|
---|
192 | static jboolean
|
---|
193 | allClasses1(PacketInputStream *in, PacketOutputStream *out, int outputGenerics)
|
---|
194 | {
|
---|
195 | JNIEnv *env;
|
---|
196 |
|
---|
197 | if (gdata->vmDead) {
|
---|
198 | outStream_setError(out, JDWP_ERROR(VM_DEAD));
|
---|
199 | return JNI_TRUE;
|
---|
200 | }
|
---|
201 |
|
---|
202 | env = getEnv();
|
---|
203 |
|
---|
204 | WITH_LOCAL_REFS(env, 1) {
|
---|
205 |
|
---|
206 | jint classCount;
|
---|
207 | jclass *theClasses;
|
---|
208 | jvmtiError error;
|
---|
209 |
|
---|
210 | error = allLoadedClasses(&theClasses, &classCount);
|
---|
211 | if ( error != JVMTI_ERROR_NONE ) {
|
---|
212 | outStream_setError(out, map2jdwpError(error));
|
---|
213 | } else {
|
---|
214 | /* Count classes in theClasses which are prepared */
|
---|
215 | int prepCount = 0;
|
---|
216 | /* Count classes written to the JDWP connection */
|
---|
217 | int writtenCount = 0;
|
---|
218 | int i;
|
---|
219 |
|
---|
220 | for (i=0; i<classCount; i++) {
|
---|
221 | jclass clazz = theClasses[i];
|
---|
222 | jint status = classStatus(clazz);
|
---|
223 | jint wanted =
|
---|
224 | (JVMTI_CLASS_STATUS_PREPARED|JVMTI_CLASS_STATUS_ARRAY);
|
---|
225 |
|
---|
226 | /* We want prepared classes and arrays only */
|
---|
227 | if ((status & wanted) != 0) {
|
---|
228 | /* Float interesting classes (those that
|
---|
229 | * are prepared) to the beginning of the array.
|
---|
230 | */
|
---|
231 | theClasses[i] = theClasses[prepCount];
|
---|
232 | theClasses[prepCount++] = clazz;
|
---|
233 | }
|
---|
234 | }
|
---|
235 |
|
---|
236 | /* At this point prepared classes occupy
|
---|
237 | * indicies 0 thru prepCount-1 of theClasses.
|
---|
238 | */
|
---|
239 |
|
---|
240 | (void)outStream_writeInt(out, prepCount);
|
---|
241 | for (; writtenCount < prepCount; writtenCount++) {
|
---|
242 | char *signature = NULL;
|
---|
243 | char *genericSignature = NULL;
|
---|
244 | jclass clazz = theClasses[writtenCount];
|
---|
245 | jint status = classStatus(clazz);
|
---|
246 | jbyte tag = referenceTypeTag(clazz);
|
---|
247 | jvmtiError error;
|
---|
248 |
|
---|
249 | error = classSignature(clazz, &signature, &genericSignature);
|
---|
250 | if (error != JVMTI_ERROR_NONE) {
|
---|
251 | outStream_setError(out, map2jdwpError(error));
|
---|
252 | break;
|
---|
253 | }
|
---|
254 |
|
---|
255 | (void)outStream_writeByte(out, tag);
|
---|
256 | (void)outStream_writeObjectRef(env, out, clazz);
|
---|
257 | (void)outStream_writeString(out, signature);
|
---|
258 | if (outputGenerics == 1) {
|
---|
259 | writeGenericSignature(out, genericSignature);
|
---|
260 | }
|
---|
261 |
|
---|
262 | (void)outStream_writeInt(out, map2jdwpClassStatus(status));
|
---|
263 | jvmtiDeallocate(signature);
|
---|
264 | if (genericSignature != NULL) {
|
---|
265 | jvmtiDeallocate(genericSignature);
|
---|
266 | }
|
---|
267 |
|
---|
268 | /* No point in continuing if there's an error */
|
---|
269 | if (outStream_error(out)) {
|
---|
270 | break;
|
---|
271 | }
|
---|
272 | }
|
---|
273 | jvmtiDeallocate(theClasses);
|
---|
274 | }
|
---|
275 |
|
---|
276 | } END_WITH_LOCAL_REFS(env);
|
---|
277 |
|
---|
278 | return JNI_TRUE;
|
---|
279 | }
|
---|
280 |
|
---|
281 | static jboolean
|
---|
282 | allClasses(PacketInputStream *in, PacketOutputStream *out)
|
---|
283 | {
|
---|
284 | return allClasses1(in, out, 0);
|
---|
285 | }
|
---|
286 |
|
---|
287 | static jboolean
|
---|
288 | allClassesWithGeneric(PacketInputStream *in, PacketOutputStream *out)
|
---|
289 | {
|
---|
290 | return allClasses1(in, out, 1);
|
---|
291 | }
|
---|
292 |
|
---|
293 | /***********************************************************/
|
---|
294 |
|
---|
295 |
|
---|
296 | static jboolean
|
---|
297 | instanceCounts(PacketInputStream *in, PacketOutputStream *out)
|
---|
298 | {
|
---|
299 | jint classCount;
|
---|
300 | jclass *classes;
|
---|
301 | JNIEnv *env;
|
---|
302 | int ii;
|
---|
303 |
|
---|
304 | if (gdata->vmDead) {
|
---|
305 | outStream_setError(out, JDWP_ERROR(VM_DEAD));
|
---|
306 | return JNI_TRUE;
|
---|
307 | }
|
---|
308 |
|
---|
309 | classCount = inStream_readInt(in);
|
---|
310 |
|
---|
311 | if (inStream_error(in)) {
|
---|
312 | return JNI_TRUE;
|
---|
313 | }
|
---|
314 | if (classCount == 0) {
|
---|
315 | (void)outStream_writeInt(out, 0);
|
---|
316 | return JNI_TRUE;
|
---|
317 | }
|
---|
318 | if (classCount < 0) {
|
---|
319 | outStream_setError(out, JDWP_ERROR(ILLEGAL_ARGUMENT));
|
---|
320 | return JNI_TRUE;
|
---|
321 | }
|
---|
322 | env = getEnv();
|
---|
323 | classes = jvmtiAllocate(classCount * (int)sizeof(jclass));
|
---|
324 | for (ii = 0; ii < classCount; ii++) {
|
---|
325 | jdwpError errorCode;
|
---|
326 | classes[ii] = inStream_readClassRef(env, in);
|
---|
327 | errorCode = inStream_error(in);
|
---|
328 | if (errorCode != JDWP_ERROR(NONE)) {
|
---|
329 | /*
|
---|
330 | * A class could have been unloaded/gc'd so
|
---|
331 | * if we get an error, just ignore it and keep
|
---|
332 | * going. An instanceCount of 0 will be returned.
|
---|
333 | */
|
---|
334 | if (errorCode == JDWP_ERROR(INVALID_OBJECT) ||
|
---|
335 | errorCode == JDWP_ERROR(INVALID_CLASS)) {
|
---|
336 | inStream_clearError(in);
|
---|
337 | classes[ii] = NULL;
|
---|
338 | continue;
|
---|
339 | }
|
---|
340 | jvmtiDeallocate(classes);
|
---|
341 | return JNI_TRUE;
|
---|
342 | }
|
---|
343 | }
|
---|
344 |
|
---|
345 | WITH_LOCAL_REFS(env, 1) {
|
---|
346 | jlong *counts;
|
---|
347 | jvmtiError error;
|
---|
348 |
|
---|
349 | counts = jvmtiAllocate(classCount * (int)sizeof(jlong));
|
---|
350 | /* Iterate over heap getting info on these classes */
|
---|
351 | error = classInstanceCounts(classCount, classes, counts);
|
---|
352 | if (error != JVMTI_ERROR_NONE) {
|
---|
353 | outStream_setError(out, map2jdwpError(error));
|
---|
354 | } else {
|
---|
355 | (void)outStream_writeInt(out, classCount);
|
---|
356 | for (ii = 0; ii < classCount; ii++) {
|
---|
357 | (void)outStream_writeLong(out, counts[ii]);
|
---|
358 | }
|
---|
359 | }
|
---|
360 | jvmtiDeallocate(counts);
|
---|
361 | } END_WITH_LOCAL_REFS(env);
|
---|
362 | jvmtiDeallocate(classes);
|
---|
363 | return JNI_TRUE;
|
---|
364 | }
|
---|
365 |
|
---|
366 | static jboolean
|
---|
367 | redefineClasses(PacketInputStream *in, PacketOutputStream *out)
|
---|
368 | {
|
---|
369 | jvmtiClassDefinition *classDefs;
|
---|
370 | jboolean ok = JNI_TRUE;
|
---|
371 | jint classCount;
|
---|
372 | jint i;
|
---|
373 | JNIEnv *env;
|
---|
374 |
|
---|
375 | if (gdata->vmDead) {
|
---|
376 | /* quietly ignore */
|
---|
377 | return JNI_TRUE;
|
---|
378 | }
|
---|
379 |
|
---|
380 | classCount = inStream_readInt(in);
|
---|
381 | if (inStream_error(in)) {
|
---|
382 | return JNI_TRUE;
|
---|
383 | }
|
---|
384 | if ( classCount == 0 ) {
|
---|
385 | return JNI_TRUE;
|
---|
386 | }
|
---|
387 | /*LINTED*/
|
---|
388 | classDefs = jvmtiAllocate(classCount*(int)sizeof(jvmtiClassDefinition));
|
---|
389 | if (classDefs == NULL) {
|
---|
390 | outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
|
---|
391 | return JNI_TRUE;
|
---|
392 | }
|
---|
393 | /*LINTED*/
|
---|
394 | (void)memset(classDefs, 0, classCount*sizeof(jvmtiClassDefinition));
|
---|
395 |
|
---|
396 | env = getEnv();
|
---|
397 | for (i = 0; i < classCount; ++i) {
|
---|
398 | int byteCount;
|
---|
399 | unsigned char * bytes;
|
---|
400 | jclass clazz;
|
---|
401 |
|
---|
402 | clazz = inStream_readClassRef(env, in);
|
---|
403 | if (inStream_error(in)) {
|
---|
404 | ok = JNI_FALSE;
|
---|
405 | break;
|
---|
406 | }
|
---|
407 | byteCount = inStream_readInt(in);
|
---|
408 | if (inStream_error(in)) {
|
---|
409 | ok = JNI_FALSE;
|
---|
410 | break;
|
---|
411 | }
|
---|
412 | if ( byteCount <= 0 ) {
|
---|
413 | outStream_setError(out, JDWP_ERROR(INVALID_CLASS_FORMAT));
|
---|
414 | ok = JNI_FALSE;
|
---|
415 | break;
|
---|
416 | }
|
---|
417 | bytes = (unsigned char *)jvmtiAllocate(byteCount);
|
---|
418 | if (bytes == NULL) {
|
---|
419 | outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
|
---|
420 | ok = JNI_FALSE;
|
---|
421 | break;
|
---|
422 | }
|
---|
423 | (void)inStream_readBytes(in, byteCount, (jbyte *)bytes);
|
---|
424 | if (inStream_error(in)) {
|
---|
425 | ok = JNI_FALSE;
|
---|
426 | break;
|
---|
427 | }
|
---|
428 |
|
---|
429 | classDefs[i].klass = clazz;
|
---|
430 | classDefs[i].class_byte_count = byteCount;
|
---|
431 | classDefs[i].class_bytes = bytes;
|
---|
432 | }
|
---|
433 |
|
---|
434 | if (ok == JNI_TRUE) {
|
---|
435 | jvmtiError error;
|
---|
436 |
|
---|
437 | error = JVMTI_FUNC_PTR(gdata->jvmti,RedefineClasses)
|
---|
438 | (gdata->jvmti, classCount, classDefs);
|
---|
439 | if (error != JVMTI_ERROR_NONE) {
|
---|
440 | outStream_setError(out, map2jdwpError(error));
|
---|
441 | } else {
|
---|
442 | /* zap our BP info */
|
---|
443 | for ( i = 0 ; i < classCount; i++ ) {
|
---|
444 | eventHandler_freeClassBreakpoints(classDefs[i].klass);
|
---|
445 | }
|
---|
446 | }
|
---|
447 | }
|
---|
448 |
|
---|
449 | /* free up allocated memory */
|
---|
450 | for ( i = 0 ; i < classCount; i++ ) {
|
---|
451 | if ( classDefs[i].class_bytes != NULL ) {
|
---|
452 | jvmtiDeallocate((void*)classDefs[i].class_bytes);
|
---|
453 | }
|
---|
454 | }
|
---|
455 | jvmtiDeallocate(classDefs);
|
---|
456 |
|
---|
457 | return JNI_TRUE;
|
---|
458 | }
|
---|
459 |
|
---|
460 | static jboolean
|
---|
461 | setDefaultStratum(PacketInputStream *in, PacketOutputStream *out)
|
---|
462 | {
|
---|
463 | char *stratumId;
|
---|
464 |
|
---|
465 | if (gdata->vmDead) {
|
---|
466 | /* quietly ignore */
|
---|
467 | return JNI_TRUE;
|
---|
468 | }
|
---|
469 |
|
---|
470 | stratumId = inStream_readString(in);
|
---|
471 | if (inStream_error(in)) {
|
---|
472 | return JNI_TRUE;
|
---|
473 | } else if (strcmp(stratumId, "") == 0) {
|
---|
474 | stratumId = NULL;
|
---|
475 | }
|
---|
476 | setGlobalStratumId(stratumId);
|
---|
477 |
|
---|
478 | return JNI_TRUE;
|
---|
479 | }
|
---|
480 |
|
---|
481 | static jboolean
|
---|
482 | getAllThreads(PacketInputStream *in, PacketOutputStream *out)
|
---|
483 | {
|
---|
484 | JNIEnv *env;
|
---|
485 |
|
---|
486 | if (gdata->vmDead) {
|
---|
487 | outStream_setError(out, JDWP_ERROR(VM_DEAD));
|
---|
488 | return JNI_TRUE;
|
---|
489 | }
|
---|
490 |
|
---|
491 | env = getEnv();
|
---|
492 |
|
---|
493 | WITH_LOCAL_REFS(env, 1) {
|
---|
494 |
|
---|
495 | int i;
|
---|
496 | jint threadCount;
|
---|
497 | jthread *theThreads;
|
---|
498 |
|
---|
499 | theThreads = allThreads(&threadCount);
|
---|
500 | if (theThreads == NULL) {
|
---|
501 | outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
|
---|
502 | } else {
|
---|
503 | /* Squish out all of the debugger-spawned threads */
|
---|
504 | threadCount = filterDebugThreads(theThreads, threadCount);
|
---|
505 |
|
---|
506 | (void)outStream_writeInt(out, threadCount);
|
---|
507 | for (i = 0; i <threadCount; i++) {
|
---|
508 | (void)outStream_writeObjectRef(env, out, theThreads[i]);
|
---|
509 | }
|
---|
510 |
|
---|
511 | jvmtiDeallocate(theThreads);
|
---|
512 | }
|
---|
513 |
|
---|
514 | } END_WITH_LOCAL_REFS(env);
|
---|
515 |
|
---|
516 | return JNI_TRUE;
|
---|
517 | }
|
---|
518 |
|
---|
519 | static jboolean
|
---|
520 | topLevelThreadGroups(PacketInputStream *in, PacketOutputStream *out)
|
---|
521 | {
|
---|
522 | JNIEnv *env;
|
---|
523 |
|
---|
524 | if (gdata->vmDead) {
|
---|
525 | outStream_setError(out, JDWP_ERROR(VM_DEAD));
|
---|
526 | return JNI_TRUE;
|
---|
527 | }
|
---|
528 |
|
---|
529 | env = getEnv();
|
---|
530 |
|
---|
531 | WITH_LOCAL_REFS(env, 1) {
|
---|
532 |
|
---|
533 | jvmtiError error;
|
---|
534 | jint groupCount;
|
---|
535 | jthreadGroup *groups;
|
---|
536 |
|
---|
537 | groups = NULL;
|
---|
538 | error = JVMTI_FUNC_PTR(gdata->jvmti,GetTopThreadGroups)
|
---|
539 | (gdata->jvmti, &groupCount, &groups);
|
---|
540 | if (error != JVMTI_ERROR_NONE) {
|
---|
541 | outStream_setError(out, map2jdwpError(error));
|
---|
542 | } else {
|
---|
543 | int i;
|
---|
544 |
|
---|
545 | (void)outStream_writeInt(out, groupCount);
|
---|
546 | for (i = 0; i < groupCount; i++) {
|
---|
547 | (void)outStream_writeObjectRef(env, out, groups[i]);
|
---|
548 | }
|
---|
549 |
|
---|
550 | jvmtiDeallocate(groups);
|
---|
551 | }
|
---|
552 |
|
---|
553 | } END_WITH_LOCAL_REFS(env);
|
---|
554 |
|
---|
555 | return JNI_TRUE;
|
---|
556 | }
|
---|
557 |
|
---|
558 | static jboolean
|
---|
559 | dispose(PacketInputStream *in, PacketOutputStream *out)
|
---|
560 | {
|
---|
561 | return JNI_TRUE;
|
---|
562 | }
|
---|
563 |
|
---|
564 | static jboolean
|
---|
565 | idSizes(PacketInputStream *in, PacketOutputStream *out)
|
---|
566 | {
|
---|
567 | (void)outStream_writeInt(out, sizeof(jfieldID)); /* fields */
|
---|
568 | (void)outStream_writeInt(out, sizeof(jmethodID)); /* methods */
|
---|
569 | (void)outStream_writeInt(out, sizeof(jlong)); /* objects */
|
---|
570 | (void)outStream_writeInt(out, sizeof(jlong)); /* referent types */
|
---|
571 | (void)outStream_writeInt(out, sizeof(FrameID)); /* frames */
|
---|
572 | return JNI_TRUE;
|
---|
573 | }
|
---|
574 |
|
---|
575 | static jboolean
|
---|
576 | suspend(PacketInputStream *in, PacketOutputStream *out)
|
---|
577 | {
|
---|
578 | jvmtiError error;
|
---|
579 |
|
---|
580 | if (gdata->vmDead) {
|
---|
581 | outStream_setError(out, JDWP_ERROR(VM_DEAD));
|
---|
582 | return JNI_TRUE;
|
---|
583 | }
|
---|
584 | error = threadControl_suspendAll();
|
---|
585 | if (error != JVMTI_ERROR_NONE) {
|
---|
586 | outStream_setError(out, map2jdwpError(error));
|
---|
587 | }
|
---|
588 | return JNI_TRUE;
|
---|
589 | }
|
---|
590 |
|
---|
591 | static jboolean
|
---|
592 | resume(PacketInputStream *in, PacketOutputStream *out)
|
---|
593 | {
|
---|
594 | jvmtiError error;
|
---|
595 |
|
---|
596 | if (gdata->vmDead) {
|
---|
597 | outStream_setError(out, JDWP_ERROR(VM_DEAD));
|
---|
598 | return JNI_TRUE;
|
---|
599 | }
|
---|
600 | error = threadControl_resumeAll();
|
---|
601 | if (error != JVMTI_ERROR_NONE) {
|
---|
602 | outStream_setError(out, map2jdwpError(error));
|
---|
603 | }
|
---|
604 | return JNI_TRUE;
|
---|
605 | }
|
---|
606 |
|
---|
607 | static jboolean
|
---|
608 | doExit(PacketInputStream *in, PacketOutputStream *out)
|
---|
609 | {
|
---|
610 | jint exitCode;
|
---|
611 |
|
---|
612 | exitCode = inStream_readInt(in);
|
---|
613 | if (gdata->vmDead) {
|
---|
614 | /* quietly ignore */
|
---|
615 | return JNI_FALSE;
|
---|
616 | }
|
---|
617 |
|
---|
618 | /* We send the reply from here because we are about to exit. */
|
---|
619 | if (inStream_error(in)) {
|
---|
620 | outStream_setError(out, inStream_error(in));
|
---|
621 | }
|
---|
622 | outStream_sendReply(out);
|
---|
623 |
|
---|
624 | forceExit(exitCode);
|
---|
625 |
|
---|
626 | /* Shouldn't get here */
|
---|
627 | JDI_ASSERT(JNI_FALSE);
|
---|
628 |
|
---|
629 | /* Shut up the compiler */
|
---|
630 | return JNI_FALSE;
|
---|
631 |
|
---|
632 | }
|
---|
633 |
|
---|
634 | static jboolean
|
---|
635 | createString(PacketInputStream *in, PacketOutputStream *out)
|
---|
636 | {
|
---|
637 | JNIEnv *env;
|
---|
638 | char *cstring;
|
---|
639 |
|
---|
640 | if (gdata->vmDead) {
|
---|
641 | outStream_setError(out, JDWP_ERROR(VM_DEAD));
|
---|
642 | return JNI_TRUE;
|
---|
643 | }
|
---|
644 |
|
---|
645 | cstring = inStream_readString(in);
|
---|
646 | if (cstring == NULL) {
|
---|
647 | outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
|
---|
648 | return JNI_TRUE;
|
---|
649 | }
|
---|
650 | if (inStream_error(in)) {
|
---|
651 | return JNI_TRUE;
|
---|
652 | }
|
---|
653 |
|
---|
654 | env = getEnv();
|
---|
655 |
|
---|
656 | WITH_LOCAL_REFS(env, 1) {
|
---|
657 |
|
---|
658 | jstring string;
|
---|
659 |
|
---|
660 | string = JNI_FUNC_PTR(env,NewStringUTF)(env, cstring);
|
---|
661 | if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
|
---|
662 | outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY));
|
---|
663 | } else {
|
---|
664 | (void)outStream_writeObjectRef(env, out, string);
|
---|
665 | }
|
---|
666 |
|
---|
667 | } END_WITH_LOCAL_REFS(env);
|
---|
668 |
|
---|
669 | jvmtiDeallocate(cstring);
|
---|
670 |
|
---|
671 | return JNI_TRUE;
|
---|
672 | }
|
---|
673 |
|
---|
674 | static jboolean
|
---|
675 | capabilities(PacketInputStream *in, PacketOutputStream *out)
|
---|
676 | {
|
---|
677 | jvmtiCapabilities caps;
|
---|
678 | jvmtiError error;
|
---|
679 |
|
---|
680 | if (gdata->vmDead) {
|
---|
681 | outStream_setError(out, JDWP_ERROR(VM_DEAD));
|
---|
682 | return JNI_TRUE;
|
---|
683 | }
|
---|
684 | error = jvmtiGetCapabilities(&caps);
|
---|
685 | if (error != JVMTI_ERROR_NONE) {
|
---|
686 | outStream_setError(out, map2jdwpError(error));
|
---|
687 | return JNI_TRUE;
|
---|
688 | }
|
---|
689 |
|
---|
690 | (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_modification_events);
|
---|
691 | (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_access_events);
|
---|
692 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_bytecodes);
|
---|
693 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_synthetic_attribute);
|
---|
694 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_owned_monitor_info);
|
---|
695 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_current_contended_monitor);
|
---|
696 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_monitor_info);
|
---|
697 | return JNI_TRUE;
|
---|
698 | }
|
---|
699 |
|
---|
700 | static jboolean
|
---|
701 | capabilitiesNew(PacketInputStream *in, PacketOutputStream *out)
|
---|
702 | {
|
---|
703 | jvmtiCapabilities caps;
|
---|
704 | jvmtiError error;
|
---|
705 |
|
---|
706 | if (gdata->vmDead) {
|
---|
707 | outStream_setError(out, JDWP_ERROR(VM_DEAD));
|
---|
708 | return JNI_TRUE;
|
---|
709 | }
|
---|
710 | error = jvmtiGetCapabilities(&caps);
|
---|
711 | if (error != JVMTI_ERROR_NONE) {
|
---|
712 | outStream_setError(out, map2jdwpError(error));
|
---|
713 | return JNI_TRUE;
|
---|
714 | }
|
---|
715 |
|
---|
716 | (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_modification_events);
|
---|
717 | (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_access_events);
|
---|
718 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_bytecodes);
|
---|
719 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_synthetic_attribute);
|
---|
720 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_owned_monitor_info);
|
---|
721 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_current_contended_monitor);
|
---|
722 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_monitor_info);
|
---|
723 |
|
---|
724 | /* new since JDWP version 1.4 */
|
---|
725 | (void)outStream_writeBoolean(out, (jboolean)caps.can_redefine_classes);
|
---|
726 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE /* can_add_method */ );
|
---|
727 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE /* can_unrestrictedly_redefine_classes */ );
|
---|
728 | /* 11: canPopFrames */
|
---|
729 | (void)outStream_writeBoolean(out, (jboolean)caps.can_pop_frame);
|
---|
730 | /* 12: canUseInstanceFilters */
|
---|
731 | (void)outStream_writeBoolean(out, (jboolean)JNI_TRUE);
|
---|
732 | /* 13: canGetSourceDebugExtension */
|
---|
733 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_source_debug_extension);
|
---|
734 | /* 14: canRequestVMDeathEvent */
|
---|
735 | (void)outStream_writeBoolean(out, (jboolean)JNI_TRUE);
|
---|
736 | /* 15: canSetDefaultStratum */
|
---|
737 | (void)outStream_writeBoolean(out, (jboolean)JNI_TRUE);
|
---|
738 | /* 16: canGetInstanceInfo */
|
---|
739 | (void)outStream_writeBoolean(out, (jboolean)caps.can_tag_objects);
|
---|
740 | /* 17: canRequestMonitorEvents */
|
---|
741 | (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_monitor_events);
|
---|
742 | /* 18: canGetMonitorFrameInfo */
|
---|
743 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_owned_monitor_stack_depth_info);
|
---|
744 | /* remaining reserved */
|
---|
745 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 19 */
|
---|
746 | /* 20 Can get constant pool information */
|
---|
747 | (void)outStream_writeBoolean(out, (jboolean)caps.can_get_constant_pool);
|
---|
748 | /* 21 Can force early return */
|
---|
749 | (void)outStream_writeBoolean(out, (jboolean)caps.can_force_early_return);
|
---|
750 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 22 */
|
---|
751 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 23 */
|
---|
752 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 24 */
|
---|
753 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 25 */
|
---|
754 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 26 */
|
---|
755 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 27 */
|
---|
756 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 28 */
|
---|
757 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 29 */
|
---|
758 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 30 */
|
---|
759 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 31 */
|
---|
760 | (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 32 */
|
---|
761 | return JNI_TRUE;
|
---|
762 | }
|
---|
763 |
|
---|
764 | static int
|
---|
765 | countPaths(char *string) {
|
---|
766 | int cnt = 1; /* always have one */
|
---|
767 | char *pos = string;
|
---|
768 | char *ps;
|
---|
769 |
|
---|
770 | ps = gdata->property_path_separator;
|
---|
771 | if ( ps == NULL ) {
|
---|
772 | ps = ";";
|
---|
773 | }
|
---|
774 | while ((pos = strchr(pos, ps[0])) != NULL) {
|
---|
775 | ++cnt;
|
---|
776 | ++pos;
|
---|
777 | }
|
---|
778 | return cnt;
|
---|
779 | }
|
---|
780 |
|
---|
781 | static void
|
---|
782 | writePaths(PacketOutputStream *out, char *string) {
|
---|
783 | char *pos;
|
---|
784 | char *ps;
|
---|
785 | char *buf;
|
---|
786 | int npaths;
|
---|
787 | int i;
|
---|
788 |
|
---|
789 | buf = jvmtiAllocate((int)strlen(string)+1);
|
---|
790 |
|
---|
791 | npaths = countPaths(string);
|
---|
792 | (void)outStream_writeInt(out, npaths);
|
---|
793 |
|
---|
794 | ps = gdata->property_path_separator;
|
---|
795 | if ( ps == NULL ) {
|
---|
796 | ps = ";";
|
---|
797 | }
|
---|
798 |
|
---|
799 | pos = string;
|
---|
800 | for ( i = 0 ; i < npaths ; i++ ) {
|
---|
801 | char *psPos;
|
---|
802 | int plen;
|
---|
803 |
|
---|
804 | psPos = strchr(pos, ps[0]);
|
---|
805 | if ( psPos == NULL ) {
|
---|
806 | plen = (int)strlen(pos);
|
---|
807 | } else {
|
---|
808 | plen = (int)(psPos-pos);
|
---|
809 | psPos++;
|
---|
810 | }
|
---|
811 | (void)memcpy(buf, pos, plen);
|
---|
812 | buf[plen] = 0;
|
---|
813 | (void)outStream_writeString(out, buf);
|
---|
814 | pos = psPos;
|
---|
815 | }
|
---|
816 |
|
---|
817 | jvmtiDeallocate(buf);
|
---|
818 | }
|
---|
819 |
|
---|
820 |
|
---|
821 |
|
---|
822 | static jboolean
|
---|
823 | classPaths(PacketInputStream *in, PacketOutputStream *out)
|
---|
824 | {
|
---|
825 | char *ud;
|
---|
826 | char *bp;
|
---|
827 | char *cp;
|
---|
828 |
|
---|
829 | ud = gdata->property_user_dir;
|
---|
830 | if ( ud == NULL ) {
|
---|
831 | ud = "";
|
---|
832 | }
|
---|
833 | cp = gdata->property_java_class_path;
|
---|
834 | if ( cp == NULL ) {
|
---|
835 | cp = "";
|
---|
836 | }
|
---|
837 | bp = gdata->property_sun_boot_class_path;
|
---|
838 | if ( bp == NULL ) {
|
---|
839 | bp = "";
|
---|
840 | }
|
---|
841 | (void)outStream_writeString(out, ud);
|
---|
842 | writePaths(out, cp);
|
---|
843 | writePaths(out, bp);
|
---|
844 | return JNI_TRUE;
|
---|
845 | }
|
---|
846 |
|
---|
847 | static jboolean
|
---|
848 | disposeObjects(PacketInputStream *in, PacketOutputStream *out)
|
---|
849 | {
|
---|
850 | int i;
|
---|
851 | int refCount;
|
---|
852 | jlong id;
|
---|
853 | int requestCount;
|
---|
854 | JNIEnv *env;
|
---|
855 |
|
---|
856 | if (gdata->vmDead) {
|
---|
857 | /* quietly ignore */
|
---|
858 | return JNI_TRUE;
|
---|
859 | }
|
---|
860 |
|
---|
861 | requestCount = inStream_readInt(in);
|
---|
862 | if (inStream_error(in)) {
|
---|
863 | return JNI_TRUE;
|
---|
864 | }
|
---|
865 |
|
---|
866 | env = getEnv();
|
---|
867 | for (i = 0; i < requestCount; i++) {
|
---|
868 | id = inStream_readObjectID(in);
|
---|
869 | refCount = inStream_readInt(in);
|
---|
870 | if (inStream_error(in)) {
|
---|
871 | return JNI_TRUE;
|
---|
872 | }
|
---|
873 | commonRef_releaseMultiple(env, id, refCount);
|
---|
874 | }
|
---|
875 |
|
---|
876 | return JNI_TRUE;
|
---|
877 | }
|
---|
878 |
|
---|
879 | static jboolean
|
---|
880 | holdEvents(PacketInputStream *in, PacketOutputStream *out)
|
---|
881 | {
|
---|
882 | eventHelper_holdEvents();
|
---|
883 | return JNI_TRUE;
|
---|
884 | }
|
---|
885 |
|
---|
886 | static jboolean
|
---|
887 | releaseEvents(PacketInputStream *in, PacketOutputStream *out)
|
---|
888 | {
|
---|
889 | eventHelper_releaseEvents();
|
---|
890 | return JNI_TRUE;
|
---|
891 | }
|
---|
892 |
|
---|
893 | void *VirtualMachine_Cmds[] = { (void *)21
|
---|
894 | ,(void *)version
|
---|
895 | ,(void *)classesForSignature
|
---|
896 | ,(void *)allClasses
|
---|
897 | ,(void *)getAllThreads
|
---|
898 | ,(void *)topLevelThreadGroups
|
---|
899 | ,(void *)dispose
|
---|
900 | ,(void *)idSizes
|
---|
901 | ,(void *)suspend
|
---|
902 | ,(void *)resume
|
---|
903 | ,(void *)doExit
|
---|
904 | ,(void *)createString
|
---|
905 | ,(void *)capabilities
|
---|
906 | ,(void *)classPaths
|
---|
907 | ,(void *)disposeObjects
|
---|
908 | ,(void *)holdEvents
|
---|
909 | ,(void *)releaseEvents
|
---|
910 | ,(void *)capabilitiesNew
|
---|
911 | ,(void *)redefineClasses
|
---|
912 | ,(void *)setDefaultStratum
|
---|
913 | ,(void *)allClassesWithGeneric
|
---|
914 | ,(void *)instanceCounts
|
---|
915 | };
|
---|