Source for gnu.classpath.jdwp.processor.VirtualMachineCommandSet

   1: /* VirtualMachineCommandSet.java -- class to implement the VirtualMachine
   2:    Command Set
   3:    Copyright (C) 2005 Free Software Foundation
   4:  
   5: This file is part of GNU Classpath.
   6: 
   7: GNU Classpath is free software; you can redistribute it and/or modify
   8: it under the terms of the GNU General Public License as published by
   9: the Free Software Foundation; either version 2, or (at your option)
  10: any later version.
  11: 
  12: GNU Classpath is distributed in the hope that it will be useful, but
  13: WITHOUT ANY WARRANTY; without even the implied warranty of
  14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15: General Public License for more details.
  16: 
  17: You should have received a copy of the GNU General Public License
  18: along with GNU Classpath; see the file COPYING.  If not, write to the
  19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20: 02110-1301 USA.
  21: 
  22: Linking this library statically or dynamically with other modules is
  23: making a combined work based on this library.  Thus, the terms and
  24: conditions of the GNU General Public License cover the whole
  25: combination.
  26: 
  27: As a special exception, the copyright holders of this library give you
  28: permission to link this library with independent modules to produce an
  29: executable, regardless of the license terms of these independent
  30: modules, and to copy and distribute the resulting executable under
  31: terms of your choice, provided that you also meet, for each linked
  32: independent module, the terms and conditions of the license of that
  33: module.  An independent module is a module which is not derived from
  34: or based on this library.  If you modify this library, you may extend
  35: this exception to your version of the library, but you are not
  36: obligated to do so.  If you do not wish to do so, delete this
  37: exception statement from your version. */
  38: 
  39: 
  40: package gnu.classpath.jdwp.processor;
  41: 
  42: import gnu.classpath.jdwp.JdwpConstants;
  43: import gnu.classpath.jdwp.VMVirtualMachine;
  44: import gnu.classpath.jdwp.exception.JdwpException;
  45: import gnu.classpath.jdwp.exception.JdwpInternalErrorException;
  46: import gnu.classpath.jdwp.exception.NotImplementedException;
  47: import gnu.classpath.jdwp.id.ObjectId;
  48: import gnu.classpath.jdwp.id.ReferenceTypeId;
  49: import gnu.classpath.jdwp.util.JdwpString;
  50: import gnu.classpath.jdwp.util.Signature;
  51: 
  52: import java.io.DataOutputStream;
  53: import java.io.IOException;
  54: import java.nio.ByteBuffer;
  55: import java.util.ArrayList;
  56: import java.util.Iterator;
  57: import java.util.Properties;
  58: 
  59: /**
  60:  * A class representing the VirtualMachine Command Set.
  61:  * 
  62:  * @author Aaron Luchko <aluchko@redhat.com>
  63:  */
  64: public class VirtualMachineCommandSet
  65:   extends CommandSet
  66: {
  67:   public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command)
  68:     throws JdwpException
  69:   {
  70:     boolean shutdown = false;
  71:     try
  72:       {
  73:         switch (command)
  74:           {
  75:           case JdwpConstants.CommandSet.VirtualMachine.VERSION:
  76:             executeVersion(bb, os);
  77:             break;
  78:           case JdwpConstants.CommandSet.VirtualMachine.CLASSES_BY_SIGNATURE:
  79:             executeClassesBySignature(bb, os);
  80:             break;
  81:           case JdwpConstants.CommandSet.VirtualMachine.ALL_CLASSES:
  82:             executeAllClasses(bb, os);
  83:             break;
  84:           case JdwpConstants.CommandSet.VirtualMachine.ALL_THREADS:
  85:             executeAllThreads(bb, os);
  86:             break;
  87:           case JdwpConstants.CommandSet.VirtualMachine.TOP_LEVEL_THREAD_GROUPS:
  88:             executeTopLevelThreadGroups(bb, os);
  89:             break;
  90:           case JdwpConstants.CommandSet.VirtualMachine.IDSIZES:
  91:             executeIDsizes(bb, os);
  92:             break;
  93:           case JdwpConstants.CommandSet.VirtualMachine.DISPOSE:
  94:             shutdown = true;
  95:             executeDispose(bb, os);
  96:             break;
  97:           case JdwpConstants.CommandSet.VirtualMachine.SUSPEND:
  98:             executeSuspend(bb, os);
  99:             break;
 100:           case JdwpConstants.CommandSet.VirtualMachine.RESUME:
 101:             executeResume(bb, os);
 102:             break;
 103:           case JdwpConstants.CommandSet.VirtualMachine.EXIT:
 104:         shutdown = true;
 105:             executeExit(bb, os);
 106:             break;
 107:           case JdwpConstants.CommandSet.VirtualMachine.CREATE_STRING:
 108:             executeCreateString(bb, os);
 109:             break;
 110:           case JdwpConstants.CommandSet.VirtualMachine.CAPABILITIES:
 111:             executeCapabilities(bb, os);
 112:             break;
 113:           case JdwpConstants.CommandSet.VirtualMachine.CLASS_PATHS:
 114:             executeClassPaths(bb, os);
 115:             break;
 116:           case JdwpConstants.CommandSet.VirtualMachine.DISPOSE_OBJECTS:
 117:             executeDisposeObjects(bb, os);
 118:             break;
 119:           case JdwpConstants.CommandSet.VirtualMachine.HOLD_EVENTS:
 120:             executeHoldEvents(bb, os);
 121:             break;
 122:           case JdwpConstants.CommandSet.VirtualMachine.RELEASE_EVENTS:
 123:             executeReleaseEvents(bb, os);
 124:             break;
 125:           case JdwpConstants.CommandSet.VirtualMachine.CAPABILITIES_NEW:
 126:             executeCapabilitiesNew(bb, os);
 127:             break;
 128:           case JdwpConstants.CommandSet.VirtualMachine.REDEFINE_CLASSES:
 129:             executeRedefineClasses(bb, os);
 130:             break;
 131:           case JdwpConstants.CommandSet.VirtualMachine.SET_DEFAULT_STRATUM:
 132:             executeSetDefaultStratum(bb, os);
 133:             break;
 134:           case JdwpConstants.CommandSet.VirtualMachine.ALL_CLASSES_WITH_GENERIC:
 135:             executeAllClassesWithGeneric(bb, os);
 136:             break;
 137:           default:
 138:             throw new NotImplementedException("Command " + command +
 139:             " not found in VirtualMachine Command Set.");
 140:           }
 141:       }
 142:     catch (IOException ex)
 143:       {
 144:         // The DataOutputStream we're using isn't talking to a socket at all
 145:         // So if we throw an IOException we're in serious trouble
 146:         throw new JdwpInternalErrorException(ex);
 147:       }
 148: 
 149:     return shutdown;
 150:   }
 151: 
 152:   private void executeVersion(ByteBuffer bb, DataOutputStream os)
 153:     throws JdwpException, IOException
 154:   {
 155: 
 156:     Properties props = System.getProperties();
 157: 
 158:     int jdwpMajor = JdwpConstants.Version.MAJOR;
 159:     int jdwpMinor = JdwpConstants.Version.MINOR;
 160:     // The description field is pretty loosely defined
 161:     String description = "JDWP version " + jdwpMajor + "." + jdwpMinor
 162:                          + ", JVM version " + props.getProperty("java.vm.name")
 163:                          + " " + props.getProperty("java.vm.version") + " "
 164:                          + props.getProperty("java.version");
 165:     String vmVersion = props.getProperty("java.version");
 166:     String vmName = props.getProperty("java.vm.name");
 167:     JdwpString.writeString(os, description);
 168:     os.writeInt(jdwpMajor);
 169:     os.writeInt(jdwpMinor);
 170:     JdwpString.writeString(os, vmName);
 171:     JdwpString.writeString(os, vmVersion);
 172:   }
 173: 
 174:   private void executeClassesBySignature(ByteBuffer bb, DataOutputStream os)
 175:     throws JdwpException, IOException
 176:   {
 177:     String sig = JdwpString.readString(bb);
 178:     ArrayList allMatchingClasses = new ArrayList();
 179: 
 180:     // This will be an Iterator over all loaded Classes
 181:     Iterator iter = VMVirtualMachine.getAllLoadedClasses();
 182: 
 183:     while (iter.hasNext())
 184:       {
 185:         Class clazz = (Class) iter.next();
 186:         String clazzSig = Signature.computeClassSignature(clazz);
 187:         if (clazzSig.equals(sig))
 188:           allMatchingClasses.add(clazz);
 189:       }
 190: 
 191:     os.writeInt(allMatchingClasses.size());
 192:     for (int i = 0; i < allMatchingClasses.size(); i++)
 193:       {
 194:         Class clazz = (Class) allMatchingClasses.get(i);
 195:         ReferenceTypeId id = idMan.getReferenceTypeId(clazz);
 196:         id.writeTagged(os);
 197:         int status = VMVirtualMachine.getClassStatus(clazz);
 198:         os.writeInt(status);
 199:       }
 200:   }
 201: 
 202:   private void executeAllClasses(ByteBuffer bb, DataOutputStream os)
 203:     throws JdwpException, IOException
 204:   {
 205:     // Disable garbage collection while we're collecting the info on loaded
 206:     // classes so we some classes don't get collected between the time we get
 207:     // the count and the time we get the list
 208:     //VMVirtualMachine.disableGarbageCollection();
 209: 
 210:     int classCount = VMVirtualMachine.getAllLoadedClassesCount();
 211:     os.writeInt(classCount);
 212: 
 213:     // This will be an Iterator over all loaded Classes
 214:     Iterator iter = VMVirtualMachine.getAllLoadedClasses();
 215:     //VMVirtualMachine.enableGarbageCollection();
 216:     int count = 0;
 217: 
 218:     // Note it's possible classes were created since out classCount so make
 219:     // sure we don't write more classes than we told the debugger
 220:     while (iter.hasNext() && count++ < classCount)
 221:       {
 222:         Class clazz = (Class) iter.next();
 223:         ReferenceTypeId id = idMan.getReferenceTypeId(clazz);
 224:         id.writeTagged(os);
 225:         String sig = Signature.computeClassSignature(clazz);
 226:         JdwpString.writeString(os, sig);
 227:         int status = VMVirtualMachine.getClassStatus(clazz);
 228:         os.writeInt(status);
 229:       }
 230:   }
 231: 
 232:   private void executeAllThreads(ByteBuffer bb, DataOutputStream os)
 233:     throws JdwpException, IOException
 234:   {
 235:     ThreadGroup jdwpGroup = Thread.currentThread().getThreadGroup();
 236:     ThreadGroup root = getRootThreadGroup(jdwpGroup);
 237: 
 238:     int numThreads = root.activeCount();
 239:     Thread allThreads[] = new Thread[numThreads];
 240:     root.enumerate(allThreads);
 241: 
 242:     // We need to loop through for the true count since some threads may have
 243:     // been destroyed since we got
 244:     // activeCount so those spots in the array will be null. As well we must
 245:     // ignore any threads that belong to jdwp
 246:     numThreads = 0;
 247:     for (int i = 0; i < allThreads.length; i++)
 248:       {
 249:         Thread thread = allThreads[i];
 250:         if (thread == null)
 251:           break; // No threads after this point
 252:         if (!thread.getThreadGroup().equals(jdwpGroup))
 253:           numThreads++;
 254:       }
 255: 
 256:     os.writeInt(numThreads);
 257: 
 258:     for (int i = 0; i < allThreads.length; i++)
 259:       {
 260:         Thread thread = allThreads[i];
 261:         if (thread == null)
 262:           break; // No threads after this point
 263:         if (!thread.getThreadGroup().equals(jdwpGroup))
 264:           idMan.getObjectId(thread).write(os);
 265:       }
 266:   }
 267: 
 268:   private void executeTopLevelThreadGroups(ByteBuffer bb, DataOutputStream os)
 269:     throws JdwpException, IOException
 270:   {
 271:     ThreadGroup jdwpGroup = Thread.currentThread().getThreadGroup ();
 272:     ThreadGroup root = getRootThreadGroup(jdwpGroup);
 273: 
 274:     os.writeInt(1); // Just one top level group allowed?
 275:     idMan.getObjectId(root);
 276:   }
 277: 
 278:   private void executeDispose(ByteBuffer bb, DataOutputStream os)
 279:     throws JdwpException
 280:   {
 281:     // resumeAllThreads isn't sufficient as a thread may have been
 282:     // suspended multiple times, we likely need a way to keep track of how many
 283:     // times a thread has been suspended or else a stronger resume method for
 284:     // this purpose
 285:     // VMVirtualMachine.resumeAllThreads ();
 286: 
 287:     // Simply shutting down the jdwp layer will take care of the rest of the
 288:     // shutdown other than disabling debugging in the VM
 289:     // VMVirtualMachine.disableDebugging();
 290: 
 291:     // Don't implement this until we're sure how to remove all the debugging
 292:     // effects from the VM.
 293:     throw new NotImplementedException(
 294:       "Command VirtualMachine.Dispose not implemented");
 295: 
 296:   }
 297: 
 298:   private void executeIDsizes(ByteBuffer bb, DataOutputStream os)
 299:     throws JdwpException, IOException
 300:   {
 301:     ObjectId oid = new ObjectId();
 302:     os.writeInt(oid.size()); // fieldId
 303:     os.writeInt(oid.size()); // methodId
 304:     os.writeInt(oid.size()); // objectId
 305:     os.writeInt(new ReferenceTypeId((byte) 0x00).size()); // referenceTypeId
 306:     os.writeInt(oid.size()); // frameId
 307:   }
 308: 
 309:   private void executeSuspend(ByteBuffer bb, DataOutputStream os)
 310:     throws JdwpException
 311:   {
 312:     VMVirtualMachine.suspendAllThreads ();
 313:   }
 314: 
 315:   private void executeResume(ByteBuffer bb, DataOutputStream os)
 316:     throws JdwpException
 317:   {
 318:     VMVirtualMachine.resumeAllThreads ();
 319:   }
 320: 
 321:   private void executeExit(ByteBuffer bb, DataOutputStream os)
 322:     throws JdwpException, IOException
 323:   {
 324:     int exitCode = bb.getInt();
 325:     System.exit (exitCode);
 326:   }
 327: 
 328:   private void executeCreateString(ByteBuffer bb, DataOutputStream os)
 329:     throws JdwpException, IOException
 330:   {
 331:     String string = JdwpString.readString(bb);
 332:     ObjectId stringId = idMan.getObjectId(string);
 333:     
 334:     // Since this string isn't referenced anywhere we'll disable garbage
 335:     // collection on it so it's still around when the debugger gets back to it.
 336:     stringId.disableCollection();
 337:     stringId.write(os);
 338:   }
 339: 
 340:   private void executeCapabilities(ByteBuffer bb, DataOutputStream os)
 341:     throws JdwpException, IOException
 342:   {
 343:     // Store these somewhere?
 344:     os.writeBoolean(false); // canWatchFieldModification
 345:     os.writeBoolean(false); // canWatchFieldAccess
 346:     os.writeBoolean(false); // canGetBytecodes
 347:     os.writeBoolean(false); // canGetSyntheticAttribute
 348:     os.writeBoolean(false); // canGetOwnedMonitorInfo
 349:     os.writeBoolean(false); // canGetCurrentContendedMonitor
 350:     os.writeBoolean(false); // canGetMonitorInfo
 351:   }
 352: 
 353:   private void executeClassPaths(ByteBuffer bb, DataOutputStream os)
 354:     throws JdwpException, IOException
 355:   {
 356:     String baseDir = System.getProperty("user.dir");
 357:     JdwpString.writeString(os, baseDir);
 358: 
 359:     // Find and write the classpath
 360:     String classPath = System.getProperty("java.class.path");
 361:     String[] paths = classPath.split(":");
 362: 
 363:     os.writeInt(paths.length);
 364:     for (int i = 0; i < paths.length; i++)
 365:       JdwpString.writeString(os, paths[i]);
 366: 
 367:     // Now the bootpath
 368:     String bootPath = System.getProperty("sun.boot.class.path");
 369:     paths = bootPath.split(":");
 370:     os.writeInt(paths.length);
 371:     for (int i = 0; i < paths.length; i++)
 372:       JdwpString.writeString(os, paths[i]);
 373:   }
 374: 
 375:   private void executeDisposeObjects(ByteBuffer bb, DataOutputStream os)
 376:     throws JdwpException
 377:   {
 378:     // Instead of going through the list of objects they give us it's probably
 379:     // better just to find the garbage collected objects ourselves
 380:     //idMan.update();
 381:   }
 382: 
 383:   private void executeHoldEvents(ByteBuffer bb, DataOutputStream os)
 384:     throws JdwpException
 385:   {
 386:     // Going to have to implement a send queue somewhere and do this without
 387:     // triggering events
 388:     // Until then just don't implement
 389:     throw new NotImplementedException(
 390:       "Command VirtualMachine.HoldEvents not implemented");
 391:   }
 392: 
 393:   // Opposite of executeHoldEvents
 394:   private void executeReleaseEvents(ByteBuffer bb, DataOutputStream os)
 395:     throws JdwpException
 396:   {
 397:     throw new NotImplementedException(
 398:       "Command VirtualMachine.ReleaseEvents not implemented");
 399:   }
 400: 
 401:   private void executeCapabilitiesNew(ByteBuffer bb, DataOutputStream os)
 402:     throws JdwpException, IOException
 403:   {
 404:     // Store these somewhere?
 405:     final int CAPABILITIES_NEW_SIZE = 32;
 406:     os.writeBoolean(false); // canWatchFieldModification
 407:     os.writeBoolean(false); // canWatchFieldAccess
 408:     os.writeBoolean(false); // canGetBytecodes
 409:     os.writeBoolean(false); // canGetSyntheticAttribute
 410:     os.writeBoolean(false); // canGetOwnedMonitorInfo
 411:     os.writeBoolean(false); // canGetCurrentContendedMonitor
 412:     os.writeBoolean(false); // canGetMonitorInfo
 413:     os.writeBoolean(false); // canRedefineClasses
 414:     os.writeBoolean(false); // canAddMethod
 415:     os.writeBoolean(false); // canUnrestrictedlyRedefineClasses
 416:     os.writeBoolean(false); // canPopFrames
 417:     os.writeBoolean(false); // canUseInstanceFilters
 418:     os.writeBoolean(false); // canGetSourceDebugExtension
 419:     os.writeBoolean(false); // canRequestVMDeathEvent
 420:     os.writeBoolean(false); // canSetDefaultStratum
 421:     for (int i = 15; i < CAPABILITIES_NEW_SIZE; i++)
 422:       // Future capabilities
 423:       // currently unused
 424:       os.writeBoolean(false); // Set to false
 425:   }
 426: 
 427:   private void executeRedefineClasses(ByteBuffer bb, DataOutputStream os)
 428:     throws JdwpException
 429:   {
 430:     // Optional command, don't implement
 431:     throw new NotImplementedException(
 432:       "Command VirtualMachine.RedefineClasses not implemented");
 433:   }
 434: 
 435:   private void executeSetDefaultStratum(ByteBuffer bb, DataOutputStream os)
 436:     throws JdwpException
 437:   {
 438:     // Optional command, don't implement
 439:     throw new NotImplementedException(
 440:       "Command VirtualMachine.SetDefaultStratum not implemented");
 441:   }
 442: 
 443:   private void executeAllClassesWithGeneric(ByteBuffer bb, DataOutputStream os)
 444:     throws JdwpException
 445:   {
 446:     // We don't handle generics
 447:     throw new NotImplementedException(
 448:       "Command VirtualMachine.AllClassesWithGeneric not implemented");
 449:   }
 450: 
 451:   /**
 452:    * Find the root ThreadGroup of this ThreadGroup
 453:    */
 454:   private ThreadGroup getRootThreadGroup(ThreadGroup group)
 455:   {
 456:     ThreadGroup parent = group.getParent();
 457: 
 458:     while (parent != null)
 459:       {
 460:         group = parent;
 461:         parent = group.getParent();
 462:       }
 463:     return group; // This group was the root
 464:   }
 465: }