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