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