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 { runCommand(ByteBuffer bb, DataOutputStream os, byte command)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 executeVersion(ByteBuffer bb, DataOutputStream os)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 executeClassesBySignature(ByteBuffer bb, DataOutputStream os)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 executeAllClasses(ByteBuffer bb, DataOutputStream os)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 executeAllThreads(ByteBuffer bb, DataOutputStream os)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 executeTopLevelThreadGroups(ByteBuffer bb, DataOutputStream os)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 executeDispose(ByteBuffer bb, DataOutputStream os)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 executeIDsizes(ByteBuffer bb, DataOutputStream os)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 executeSuspend(ByteBuffer bb, DataOutputStream os)309 private void executeSuspend(ByteBuffer bb, DataOutputStream os) 310 throws JdwpException 311 { 312 VMVirtualMachine.suspendAllThreads (); 313 } 314 executeResume(ByteBuffer bb, DataOutputStream os)315 private void executeResume(ByteBuffer bb, DataOutputStream os) 316 throws JdwpException 317 { 318 VMVirtualMachine.resumeAllThreads (); 319 } 320 executeExit(ByteBuffer bb, DataOutputStream os)321 private void executeExit(ByteBuffer bb, DataOutputStream os) 322 throws JdwpException, IOException 323 { 324 int exitCode = bb.getInt(); 325 System.exit (exitCode); 326 } 327 executeCreateString(ByteBuffer bb, DataOutputStream os)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 executeCapabilities(ByteBuffer bb, DataOutputStream os)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 executeClassPaths(ByteBuffer bb, DataOutputStream os)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 executeDisposeObjects(ByteBuffer bb, DataOutputStream os)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 executeHoldEvents(ByteBuffer bb, DataOutputStream os)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 executeReleaseEvents(ByteBuffer bb, DataOutputStream os)394 private void executeReleaseEvents(ByteBuffer bb, DataOutputStream os) 395 throws JdwpException 396 { 397 throw new NotImplementedException( 398 "Command VirtualMachine.ReleaseEvents not implemented"); 399 } 400 executeCapabilitiesNew(ByteBuffer bb, DataOutputStream os)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 executeRedefineClasses(ByteBuffer bb, DataOutputStream os)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 executeSetDefaultStratum(ByteBuffer bb, DataOutputStream os)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 executeAllClassesWithGeneric(ByteBuffer bb, DataOutputStream os)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 */ getRootThreadGroup(ThreadGroup group)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 } 466