1 /* 2 * Copyright (c) 1998, 2020, 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 { 238 return methods1(in, out, 0); 239 } 240 241 static jboolean 242 methodsWithGeneric(PacketInputStream *in, PacketOutputStream *out) 243 { 244 return methods1(in, out, 1); 245 } 246 247 248 249 static jboolean 250 instances(PacketInputStream *in, PacketOutputStream *out) 251 { 252 jint maxInstances; 253 jclass clazz; 254 JNIEnv *env; 255 256 if (gdata->vmDead) { 257 outStream_setError(out, JDWP_ERROR(VM_DEAD)); 258 return JNI_TRUE; 259 } 260 261 env = getEnv(); 262 clazz = inStream_readClassRef(env, in); 263 maxInstances = inStream_readInt(in); 264 if (inStream_error(in)) { 265 return JNI_TRUE; 266 } 267 268 WITH_LOCAL_REFS(env, 1) { 269 jvmtiError error; 270 ObjectBatch batch; 271 272 error = classInstances(clazz, &batch, maxInstances); 273 if (error != JVMTI_ERROR_NONE) { 274 outStream_setError(out, map2jdwpError(error)); 275 } else { 276 int kk; 277 jbyte typeKey; 278 279 (void)outStream_writeInt(out, batch.count); 280 if (batch.count > 0) { 281 /* 282 * They are all instances of this class and will all have 283 * the same typeKey, so just compute it once. 284 */ 285 typeKey = specificTypeKey(env, batch.objects[0]); 286 287 for (kk = 0; kk < batch.count; kk++) { 288 jobject inst; 289 290 inst = batch.objects[kk]; 291 (void)outStream_writeByte(out, typeKey); 292 (void)outStream_writeObjectRef(env, out, inst); 293 } 294 } 295 jvmtiDeallocate(batch.objects); 296 } 297 } END_WITH_LOCAL_REFS(env); 298 299 return JNI_TRUE; 300 } 301 302 static jboolean 303 getClassVersion(PacketInputStream *in, PacketOutputStream *out) 304 { 305 jclass clazz; 306 jvmtiError error; 307 jint majorVersion; 308 jint minorVersion; 309 310 clazz = inStream_readClassRef(getEnv(), in); 311 if (inStream_error(in)) { 312 return JNI_TRUE; 313 } 314 315 error = JVMTI_FUNC_PTR(gdata->jvmti, GetClassVersionNumbers) 316 (gdata->jvmti, clazz, &minorVersion, &majorVersion); 317 if (error != JVMTI_ERROR_NONE) { 318 outStream_setError(out, map2jdwpError(error)); 319 return JNI_TRUE; 320 } 321 322 (void)outStream_writeInt(out, majorVersion); 323 (void)outStream_writeInt(out, minorVersion); 324 325 return JNI_TRUE; 326 } 327 328 static jboolean 329 getConstantPool(PacketInputStream *in, PacketOutputStream *out) 330 { 331 332 jclass clazz; 333 jvmtiError error; 334 jint cpCount; 335 jint cpByteCount; 336 unsigned char* cpBytesPtr; 337 338 339 clazz = inStream_readClassRef(getEnv(), in); 340 if (inStream_error(in)) { 341 return JNI_TRUE; 342 } 343 344 /* Initialize assuming no bytecodes and no error */ 345 error = JVMTI_ERROR_NONE; 346 cpCount = 0; 347 cpByteCount = 0; 348 cpBytesPtr = NULL; 349 350 351 error = JVMTI_FUNC_PTR(gdata->jvmti,GetConstantPool) 352 (gdata->jvmti, clazz, &cpCount, &cpByteCount, &cpBytesPtr); 353 if (error != JVMTI_ERROR_NONE) { 354 outStream_setError(out, map2jdwpError(error)); 355 } else { 356 (void)outStream_writeInt(out, cpCount); 357 (void)outStream_writeByteArray(out, cpByteCount, (jbyte *)cpBytesPtr); 358 jvmtiDeallocate(cpBytesPtr); 359 } 360 361 return JNI_TRUE; 362 } 363 364 static void 365 writeFieldInfo(PacketOutputStream *out, jclass clazz, jfieldID fieldID, 366 int outputGenerics) 367 { 368 char *name; 369 char *signature = NULL; 370 char *genericSignature = NULL; 371 jint modifiers; 372 jboolean isSynthetic; 373 jvmtiError error; 374 375 error = isFieldSynthetic(clazz, fieldID, &isSynthetic); 376 if (error != JVMTI_ERROR_NONE) { 377 outStream_setError(out, map2jdwpError(error)); 378 return; 379 } 380 381 error = fieldModifiers(clazz, fieldID, &modifiers); 382 if (error != JVMTI_ERROR_NONE) { 383 outStream_setError(out, map2jdwpError(error)); 384 return; 385 } 386 387 error = fieldSignature(clazz, fieldID, &name, &signature, &genericSignature); 388 if (error != JVMTI_ERROR_NONE) { 389 outStream_setError(out, map2jdwpError(error)); 390 return; 391 } 392 if (isSynthetic) { 393 modifiers |= MOD_SYNTHETIC; 394 } 395 (void)outStream_writeFieldID(out, fieldID); 396 (void)outStream_writeString(out, name); 397 (void)outStream_writeString(out, signature); 398 if (outputGenerics == 1) { 399 writeGenericSignature(out, genericSignature); 400 } 401 (void)outStream_writeInt(out, modifiers); 402 jvmtiDeallocate(name); 403 jvmtiDeallocate(signature); 404 if (genericSignature != NULL) { 405 jvmtiDeallocate(genericSignature); 406 } 407 } 408 409 static jboolean 410 fields1(PacketInputStream *in, PacketOutputStream *out, int outputGenerics) 411 { 412 int i; 413 jclass clazz; 414 jint fieldCount = 0; 415 jfieldID *fields = NULL; 416 jvmtiError error; 417 418 clazz = inStream_readClassRef(getEnv(), in); 419 if (inStream_error(in)) { 420 return JNI_TRUE; 421 } 422 423 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassFields) 424 (gdata->jvmti, clazz, &fieldCount, &fields); 425 if (error != JVMTI_ERROR_NONE) { 426 outStream_setError(out, map2jdwpError(error)); 427 return JNI_TRUE; 428 } 429 430 (void)outStream_writeInt(out, fieldCount); 431 for (i = 0; (i < fieldCount) && !outStream_error(out); i++) { 432 writeFieldInfo(out, clazz, fields[i], outputGenerics); 433 } 434 435 /* Free fields array */ 436 if ( fields != NULL ) { 437 jvmtiDeallocate(fields); 438 } 439 return JNI_TRUE; 440 } 441 442 443 static jboolean 444 fields(PacketInputStream *in, PacketOutputStream *out) 445 { 446 return fields1(in, out, 0); 447 } 448 449 static jboolean 450 fieldsWithGeneric(PacketInputStream *in, PacketOutputStream *out) 451 { 452 return fields1(in, out, 1); 453 454 } 455 456 static jboolean 457 getValues(PacketInputStream *in, PacketOutputStream *out) 458 { 459 sharedGetFieldValues(in, out, JNI_TRUE); 460 return JNI_TRUE; 461 } 462 463 static jboolean 464 sourceFile(PacketInputStream *in, PacketOutputStream *out) 465 { 466 char *fileName; 467 jvmtiError error; 468 jclass clazz; 469 470 clazz = inStream_readClassRef(getEnv(), in); 471 if (inStream_error(in)) { 472 return JNI_TRUE; 473 } 474 475 error = JVMTI_FUNC_PTR(gdata->jvmti,GetSourceFileName) 476 (gdata->jvmti, clazz, &fileName); 477 if (error != JVMTI_ERROR_NONE) { 478 outStream_setError(out, map2jdwpError(error)); 479 return JNI_TRUE; 480 } 481 482 (void)outStream_writeString(out, fileName); 483 jvmtiDeallocate(fileName); 484 return JNI_TRUE; 485 } 486 487 static jboolean 488 sourceDebugExtension(PacketInputStream *in, PacketOutputStream *out) 489 { 490 char *extension; 491 jvmtiError error; 492 jclass clazz; 493 494 clazz = inStream_readClassRef(getEnv(), in); 495 if (inStream_error(in)) { 496 return JNI_TRUE; 497 } 498 499 error = getSourceDebugExtension(clazz, &extension); 500 if (error != JVMTI_ERROR_NONE) { 501 outStream_setError(out, map2jdwpError(error)); 502 return JNI_TRUE; 503 } 504 505 (void)outStream_writeString(out, extension); 506 jvmtiDeallocate(extension); 507 return JNI_TRUE; 508 } 509 510 static jboolean 511 nestedTypes(PacketInputStream *in, PacketOutputStream *out) 512 { 513 JNIEnv *env; 514 jclass clazz; 515 516 env = getEnv(); 517 518 clazz = inStream_readClassRef(env, in); 519 if (inStream_error(in)) { 520 return JNI_TRUE; 521 } 522 523 WITH_LOCAL_REFS(env, 1) { 524 525 jvmtiError error; 526 jint count; 527 jclass *nested; 528 529 error = allNestedClasses(clazz, &nested, &count); 530 if (error != JVMTI_ERROR_NONE) { 531 outStream_setError(out, map2jdwpError(error)); 532 } else { 533 int i; 534 (void)outStream_writeInt(out, count); 535 for (i = 0; i < count; i++) { 536 (void)outStream_writeByte(out, referenceTypeTag(nested[i])); 537 (void)outStream_writeObjectRef(env, out, nested[i]); 538 } 539 if ( nested != NULL ) { 540 jvmtiDeallocate(nested); 541 } 542 } 543 544 } END_WITH_LOCAL_REFS(env); 545 546 return JNI_TRUE; 547 } 548 549 static jboolean 550 getClassStatus(PacketInputStream *in, PacketOutputStream *out) 551 { 552 jint status; 553 jclass clazz; 554 555 clazz = inStream_readClassRef(getEnv(), in); 556 if (inStream_error(in)) { 557 return JNI_TRUE; 558 } 559 560 status = classStatus(clazz); 561 (void)outStream_writeInt(out, map2jdwpClassStatus(status)); 562 return JNI_TRUE; 563 } 564 565 static jboolean 566 interfaces(PacketInputStream *in, PacketOutputStream *out) 567 { 568 JNIEnv *env; 569 jclass clazz; 570 571 env = getEnv(); 572 573 clazz = inStream_readClassRef(env, in); 574 if (inStream_error(in)) { 575 return JNI_TRUE; 576 } 577 578 WITH_LOCAL_REFS(env, 1) { 579 580 jvmtiError error; 581 jint interfaceCount; 582 jclass *interfaces; 583 584 error = allInterfaces(clazz, &interfaces, &interfaceCount); 585 if (error != JVMTI_ERROR_NONE) { 586 outStream_setError(out, map2jdwpError(error)); 587 } else { 588 int i; 589 590 (void)outStream_writeInt(out, interfaceCount); 591 for (i = 0; i < interfaceCount; i++) { 592 (void)outStream_writeObjectRef(env, out, interfaces[i]); 593 } 594 if ( interfaces != NULL ) { 595 jvmtiDeallocate(interfaces); 596 } 597 } 598 599 } END_WITH_LOCAL_REFS(env); 600 601 return JNI_TRUE; 602 } 603 604 static jboolean 605 classObject(PacketInputStream *in, PacketOutputStream *out) 606 { 607 jclass clazz; 608 JNIEnv *env; 609 610 env = getEnv(); 611 clazz = inStream_readClassRef(env, in); 612 if (inStream_error(in)) { 613 return JNI_TRUE; 614 } 615 616 /* 617 * In our implementation, the reference type id is the same as the 618 * class object id, so we bounce it right back. 619 * 620 */ 621 622 (void)outStream_writeObjectRef(env, out, clazz); 623 624 return JNI_TRUE; 625 } 626 627 CommandSet ReferenceType_Cmds = { 628 19, "ReferenceType", 629 { 630 {signature, "Signature"}, 631 {getClassLoader, "GetClassLoader"}, 632 {modifiers, "Modifiers"}, 633 {fields, "Fields"}, 634 {methods, "Methods"}, 635 {getValues, "GetValues"}, 636 {sourceFile, "SourceFile"}, 637 {nestedTypes, "NestedTypes"}, 638 {getClassStatus, "GetClassStatus"}, 639 {interfaces, "Interfaces"}, 640 {classObject, "ClassObject"}, 641 {sourceDebugExtension, "SourceDebugExtension"}, 642 {signatureWithGeneric, "SignatureWithGeneric"}, 643 {fieldsWithGeneric, "FieldsWithGeneric"}, 644 {methodsWithGeneric, "MethodsWithGeneric"}, 645 {instances, "Instances"}, 646 {getClassVersion, "GetClassVersion"}, 647 {getConstantPool, "GetConstantPool"}, 648 {getModule, "GetModule"} 649 } 650 };