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 };