1 /* 2 * Copyright (c) 1998, 2005, 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 "ReferenceTypeImpl.h" 28 #include "inStream.h" 29 #include "outStream.h" 30 31 32 static jboolean 33 signature(PacketInputStream *in, PacketOutputStream *out) 34 { 35 char *signature = NULL; 36 jclass clazz; 37 jvmtiError error; 38 39 clazz = inStream_readClassRef(getEnv(), in); 40 if (inStream_error(in)) { 41 return JNI_TRUE; 42 } 43 44 error = classSignature(clazz, &signature, NULL); 45 if (error != JVMTI_ERROR_NONE) { 46 outStream_setError(out, map2jdwpError(error)); 47 return JNI_TRUE; 48 } 49 50 (void)outStream_writeString(out, signature); 51 jvmtiDeallocate(signature); 52 53 return JNI_TRUE; 54 } 55 56 static jboolean 57 signatureWithGeneric(PacketInputStream *in, PacketOutputStream *out) 58 { 59 /* Returns both the signature and the generic signature */ 60 char *signature = NULL; 61 char *genericSignature = NULL; 62 jclass clazz; 63 jvmtiError error; 64 65 clazz = inStream_readClassRef(getEnv(), in); 66 if (inStream_error(in)) { 67 return JNI_TRUE; 68 } 69 error = classSignature(clazz, &signature, &genericSignature); 70 if (error != JVMTI_ERROR_NONE) { 71 outStream_setError(out, map2jdwpError(error)); 72 return JNI_TRUE; 73 } 74 75 (void)outStream_writeString(out, signature); 76 writeGenericSignature(out, genericSignature); 77 jvmtiDeallocate(signature); 78 if (genericSignature != NULL) { 79 jvmtiDeallocate(genericSignature); 80 } 81 82 83 return JNI_TRUE; 84 } 85 86 static jboolean 87 getClassLoader(PacketInputStream *in, PacketOutputStream *out) 88 { 89 jclass clazz; 90 jobject loader; 91 jvmtiError error; 92 JNIEnv *env; 93 94 env = getEnv(); 95 96 clazz = inStream_readClassRef(env, in); 97 if (inStream_error(in)) { 98 return JNI_TRUE; 99 } 100 101 error = classLoader(clazz, &loader); 102 if (error != JVMTI_ERROR_NONE) { 103 outStream_setError(out, map2jdwpError(error)); 104 return JNI_TRUE; 105 } 106 107 (void)outStream_writeObjectRef(env, out, loader); 108 return JNI_TRUE; 109 } 110 111 static jboolean 112 modifiers(PacketInputStream *in, PacketOutputStream *out) 113 { 114 jint modifiers; 115 jclass clazz; 116 jvmtiError error; 117 118 clazz = inStream_readClassRef(getEnv(), in); 119 if (inStream_error(in)) { 120 return JNI_TRUE; 121 } 122 123 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassModifiers) 124 (gdata->jvmti, clazz, &modifiers); 125 if (error != JVMTI_ERROR_NONE) { 126 outStream_setError(out, map2jdwpError(error)); 127 return JNI_TRUE; 128 } 129 130 (void)outStream_writeInt(out, modifiers); 131 132 return JNI_TRUE; 133 } 134 135 static void 136 writeMethodInfo(PacketOutputStream *out, jclass clazz, jmethodID method, 137 int outputGenerics) 138 { 139 char *name = NULL; 140 char *signature = NULL; 141 char *genericSignature = NULL; 142 jint modifiers; 143 jvmtiError error; 144 jboolean isSynthetic; 145 146 error = isMethodSynthetic(method, &isSynthetic); 147 if (error != JVMTI_ERROR_NONE) { 148 outStream_setError(out, map2jdwpError(error)); 149 return; 150 } 151 152 error = methodModifiers(method, &modifiers); 153 if (error != JVMTI_ERROR_NONE) { 154 outStream_setError(out, map2jdwpError(error)); 155 return; 156 } 157 158 error = methodSignature(method, &name, &signature, &genericSignature); 159 if (error != JVMTI_ERROR_NONE) { 160 outStream_setError(out, map2jdwpError(error)); 161 return; 162 } 163 164 if (isSynthetic) { 165 modifiers |= MOD_SYNTHETIC; 166 } 167 (void)outStream_writeMethodID(out, method); 168 (void)outStream_writeString(out, name); 169 (void)outStream_writeString(out, signature); 170 if (outputGenerics == 1) { 171 writeGenericSignature(out, genericSignature); 172 } 173 (void)outStream_writeInt(out, modifiers); 174 jvmtiDeallocate(name); 175 jvmtiDeallocate(signature); 176 if (genericSignature != NULL) { 177 jvmtiDeallocate(genericSignature); 178 } 179 } 180 181 static jboolean 182 methods1(PacketInputStream *in, PacketOutputStream *out, 183 int outputGenerics) 184 { 185 int i; 186 jclass clazz; 187 jint methodCount = 0; 188 jmethodID *methods = NULL; 189 jvmtiError error; 190 191 clazz = inStream_readClassRef(getEnv(), in); 192 if (inStream_error(in)) { 193 return JNI_TRUE; 194 } 195 196 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassMethods) 197 (gdata->jvmti, clazz, &methodCount, &methods); 198 if (error != JVMTI_ERROR_NONE) { 199 outStream_setError(out, map2jdwpError(error)); 200 return JNI_TRUE; 201 } 202 203 (void)outStream_writeInt(out, methodCount); 204 for (i = 0; (i < methodCount) && !outStream_error(out); i++) { 205 writeMethodInfo(out, clazz, methods[i], outputGenerics); 206 } 207 208 /* Free methods array */ 209 if ( methods != NULL ) { 210 jvmtiDeallocate(methods); 211 } 212 return JNI_TRUE; 213 } 214 215 static jboolean 216 methods(PacketInputStream *in, PacketOutputStream *out, 217 int outputGenerics) 218 { 219 return methods1(in, out, 0); 220 } 221 222 static jboolean 223 methodsWithGeneric(PacketInputStream *in, PacketOutputStream *out) 224 { 225 return methods1(in, out, 1); 226 } 227 228 229 230 static jboolean 231 instances(PacketInputStream *in, PacketOutputStream *out) 232 { 233 jint maxInstances; 234 jclass clazz; 235 JNIEnv *env; 236 237 if (gdata->vmDead) { 238 outStream_setError(out, JDWP_ERROR(VM_DEAD)); 239 return JNI_TRUE; 240 } 241 242 env = getEnv(); 243 clazz = inStream_readClassRef(env, in); 244 maxInstances = inStream_readInt(in); 245 if (inStream_error(in)) { 246 return JNI_TRUE; 247 } 248 249 WITH_LOCAL_REFS(env, 1) { 250 jvmtiError error; 251 ObjectBatch batch; 252 253 error = classInstances(clazz, &batch, maxInstances); 254 if (error != JVMTI_ERROR_NONE) { 255 outStream_setError(out, map2jdwpError(error)); 256 } else { 257 int kk; 258 jbyte typeKey; 259 260 (void)outStream_writeInt(out, batch.count); 261 if (batch.count > 0) { 262 /* 263 * They are all instances of this class and will all have 264 * the same typeKey, so just compute it once. 265 */ 266 typeKey = specificTypeKey(env, batch.objects[0]); 267 268 for (kk = 0; kk < batch.count; kk++) { 269 jobject inst; 270 271 inst = batch.objects[kk]; 272 (void)outStream_writeByte(out, typeKey); 273 (void)outStream_writeObjectRef(env, out, inst); 274 } 275 } 276 jvmtiDeallocate(batch.objects); 277 } 278 } END_WITH_LOCAL_REFS(env); 279 280 return JNI_TRUE; 281 } 282 283 static jboolean 284 getClassVersion(PacketInputStream *in, PacketOutputStream *out) 285 { 286 jclass clazz; 287 jvmtiError error; 288 jint majorVersion; 289 jint minorVersion; 290 291 clazz = inStream_readClassRef(getEnv(), in); 292 if (inStream_error(in)) { 293 return JNI_TRUE; 294 } 295 296 error = JVMTI_FUNC_PTR(gdata->jvmti, GetClassVersionNumbers) 297 (gdata->jvmti, clazz, &minorVersion, &majorVersion); 298 if (error != JVMTI_ERROR_NONE) { 299 outStream_setError(out, map2jdwpError(error)); 300 return JNI_TRUE; 301 } 302 303 (void)outStream_writeInt(out, majorVersion); 304 (void)outStream_writeInt(out, minorVersion); 305 306 return JNI_TRUE; 307 } 308 309 static jboolean 310 getConstantPool(PacketInputStream *in, PacketOutputStream *out) 311 { 312 313 jclass clazz; 314 jvmtiError error; 315 jint cpCount; 316 jint cpByteCount; 317 unsigned char* cpBytesPtr; 318 319 320 clazz = inStream_readClassRef(getEnv(), in); 321 if (inStream_error(in)) { 322 return JNI_TRUE; 323 } 324 325 /* Initialize assuming no bytecodes and no error */ 326 error = JVMTI_ERROR_NONE; 327 cpCount = 0; 328 cpByteCount = 0; 329 cpBytesPtr = NULL; 330 331 332 error = JVMTI_FUNC_PTR(gdata->jvmti,GetConstantPool) 333 (gdata->jvmti, clazz, &cpCount, &cpByteCount, &cpBytesPtr); 334 if (error != JVMTI_ERROR_NONE) { 335 outStream_setError(out, map2jdwpError(error)); 336 } else { 337 (void)outStream_writeInt(out, cpCount); 338 (void)outStream_writeByteArray(out, cpByteCount, (jbyte *)cpBytesPtr); 339 jvmtiDeallocate(cpBytesPtr); 340 } 341 342 return JNI_TRUE; 343 } 344 345 static void 346 writeFieldInfo(PacketOutputStream *out, jclass clazz, jfieldID fieldID, 347 int outputGenerics) 348 { 349 char *name; 350 char *signature = NULL; 351 char *genericSignature = NULL; 352 jint modifiers; 353 jboolean isSynthetic; 354 jvmtiError error; 355 356 error = isFieldSynthetic(clazz, fieldID, &isSynthetic); 357 if (error != JVMTI_ERROR_NONE) { 358 outStream_setError(out, map2jdwpError(error)); 359 return; 360 } 361 362 error = fieldModifiers(clazz, fieldID, &modifiers); 363 if (error != JVMTI_ERROR_NONE) { 364 outStream_setError(out, map2jdwpError(error)); 365 return; 366 } 367 368 error = fieldSignature(clazz, fieldID, &name, &signature, &genericSignature); 369 if (error != JVMTI_ERROR_NONE) { 370 outStream_setError(out, map2jdwpError(error)); 371 return; 372 } 373 if (isSynthetic) { 374 modifiers |= MOD_SYNTHETIC; 375 } 376 (void)outStream_writeFieldID(out, fieldID); 377 (void)outStream_writeString(out, name); 378 (void)outStream_writeString(out, signature); 379 if (outputGenerics == 1) { 380 writeGenericSignature(out, genericSignature); 381 } 382 (void)outStream_writeInt(out, modifiers); 383 jvmtiDeallocate(name); 384 jvmtiDeallocate(signature); 385 if (genericSignature != NULL) { 386 jvmtiDeallocate(genericSignature); 387 } 388 } 389 390 static jboolean 391 fields1(PacketInputStream *in, PacketOutputStream *out, int outputGenerics) 392 { 393 int i; 394 jclass clazz; 395 jint fieldCount = 0; 396 jfieldID *fields = NULL; 397 jvmtiError error; 398 399 clazz = inStream_readClassRef(getEnv(), in); 400 if (inStream_error(in)) { 401 return JNI_TRUE; 402 } 403 404 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassFields) 405 (gdata->jvmti, clazz, &fieldCount, &fields); 406 if (error != JVMTI_ERROR_NONE) { 407 outStream_setError(out, map2jdwpError(error)); 408 return JNI_TRUE; 409 } 410 411 (void)outStream_writeInt(out, fieldCount); 412 for (i = 0; (i < fieldCount) && !outStream_error(out); i++) { 413 writeFieldInfo(out, clazz, fields[i], outputGenerics); 414 } 415 416 /* Free fields array */ 417 if ( fields != NULL ) { 418 jvmtiDeallocate(fields); 419 } 420 return JNI_TRUE; 421 } 422 423 424 static jboolean 425 fields(PacketInputStream *in, PacketOutputStream *out) 426 { 427 return fields1(in, out, 0); 428 } 429 430 static jboolean 431 fieldsWithGeneric(PacketInputStream *in, PacketOutputStream *out) 432 { 433 return fields1(in, out, 1); 434 435 } 436 437 static jboolean 438 getValues(PacketInputStream *in, PacketOutputStream *out) 439 { 440 sharedGetFieldValues(in, out, JNI_TRUE); 441 return JNI_TRUE; 442 } 443 444 static jboolean 445 sourceFile(PacketInputStream *in, PacketOutputStream *out) 446 { 447 char *fileName; 448 jvmtiError error; 449 jclass clazz; 450 451 clazz = inStream_readClassRef(getEnv(), in); 452 if (inStream_error(in)) { 453 return JNI_TRUE; 454 } 455 456 error = JVMTI_FUNC_PTR(gdata->jvmti,GetSourceFileName) 457 (gdata->jvmti, clazz, &fileName); 458 if (error != JVMTI_ERROR_NONE) { 459 outStream_setError(out, map2jdwpError(error)); 460 return JNI_TRUE; 461 } 462 463 (void)outStream_writeString(out, fileName); 464 jvmtiDeallocate(fileName); 465 return JNI_TRUE; 466 } 467 468 static jboolean 469 sourceDebugExtension(PacketInputStream *in, PacketOutputStream *out) 470 { 471 char *extension; 472 jvmtiError error; 473 jclass clazz; 474 475 clazz = inStream_readClassRef(getEnv(), in); 476 if (inStream_error(in)) { 477 return JNI_TRUE; 478 } 479 480 error = getSourceDebugExtension(clazz, &extension); 481 if (error != JVMTI_ERROR_NONE) { 482 outStream_setError(out, map2jdwpError(error)); 483 return JNI_TRUE; 484 } 485 486 (void)outStream_writeString(out, extension); 487 jvmtiDeallocate(extension); 488 return JNI_TRUE; 489 } 490 491 static jboolean 492 nestedTypes(PacketInputStream *in, PacketOutputStream *out) 493 { 494 JNIEnv *env; 495 jclass clazz; 496 497 env = getEnv(); 498 499 clazz = inStream_readClassRef(env, in); 500 if (inStream_error(in)) { 501 return JNI_TRUE; 502 } 503 504 WITH_LOCAL_REFS(env, 1) { 505 506 jvmtiError error; 507 jint count; 508 jclass *nested; 509 510 error = allNestedClasses(clazz, &nested, &count); 511 if (error != JVMTI_ERROR_NONE) { 512 outStream_setError(out, map2jdwpError(error)); 513 } else { 514 int i; 515 (void)outStream_writeInt(out, count); 516 for (i = 0; i < count; i++) { 517 (void)outStream_writeByte(out, referenceTypeTag(nested[i])); 518 (void)outStream_writeObjectRef(env, out, nested[i]); 519 } 520 if ( nested != NULL ) { 521 jvmtiDeallocate(nested); 522 } 523 } 524 525 } END_WITH_LOCAL_REFS(env); 526 527 return JNI_TRUE; 528 } 529 530 static jboolean 531 getClassStatus(PacketInputStream *in, PacketOutputStream *out) 532 { 533 jint status; 534 jclass clazz; 535 536 clazz = inStream_readClassRef(getEnv(), in); 537 if (inStream_error(in)) { 538 return JNI_TRUE; 539 } 540 541 status = classStatus(clazz); 542 (void)outStream_writeInt(out, map2jdwpClassStatus(status)); 543 return JNI_TRUE; 544 } 545 546 static jboolean 547 interfaces(PacketInputStream *in, PacketOutputStream *out) 548 { 549 JNIEnv *env; 550 jclass clazz; 551 552 env = getEnv(); 553 554 clazz = inStream_readClassRef(env, in); 555 if (inStream_error(in)) { 556 return JNI_TRUE; 557 } 558 559 WITH_LOCAL_REFS(env, 1) { 560 561 jvmtiError error; 562 jint interfaceCount; 563 jclass *interfaces; 564 565 error = allInterfaces(clazz, &interfaces, &interfaceCount); 566 if (error != JVMTI_ERROR_NONE) { 567 outStream_setError(out, map2jdwpError(error)); 568 } else { 569 int i; 570 571 (void)outStream_writeInt(out, interfaceCount); 572 for (i = 0; i < interfaceCount; i++) { 573 (void)outStream_writeObjectRef(env, out, interfaces[i]); 574 } 575 if ( interfaces != NULL ) { 576 jvmtiDeallocate(interfaces); 577 } 578 } 579 580 } END_WITH_LOCAL_REFS(env); 581 582 return JNI_TRUE; 583 } 584 585 static jboolean 586 classObject(PacketInputStream *in, PacketOutputStream *out) 587 { 588 jclass clazz; 589 JNIEnv *env; 590 591 env = getEnv(); 592 clazz = inStream_readClassRef(env, in); 593 if (inStream_error(in)) { 594 return JNI_TRUE; 595 } 596 597 /* 598 * In our implementation, the reference type id is the same as the 599 * class object id, so we bounce it right back. 600 * 601 */ 602 603 (void)outStream_writeObjectRef(env, out, clazz); 604 605 return JNI_TRUE; 606 } 607 608 void *ReferenceType_Cmds[] = { (void *)18 609 ,(void *)signature 610 ,(void *)getClassLoader 611 ,(void *)modifiers 612 ,(void *)fields 613 ,(void *)methods 614 ,(void *)getValues 615 ,(void *)sourceFile 616 ,(void *)nestedTypes 617 ,(void *)getClassStatus 618 ,(void *)interfaces 619 ,(void *)classObject 620 ,(void *)sourceDebugExtension 621 ,(void *)signatureWithGeneric 622 ,(void *)fieldsWithGeneric 623 ,(void *)methodsWithGeneric 624 ,(void *)instances 625 ,(void *)getClassVersion 626 ,(void *)getConstantPool 627 }; 628