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