1 /* VirtualMachineCommandSet.java -- class to implement the VirtualMachine
3 Copyright (C) 2005, 2006, 2007 Free Software Foundation
5 This file is part of GNU Classpath.
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)
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.
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
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
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. */
40 package gnu
.classpath
.jdwp
.processor
;
42 import gnu
.classpath
.jdwp
.JdwpConstants
;
43 import gnu
.classpath
.jdwp
.VMFrame
;
44 import gnu
.classpath
.jdwp
.VMVirtualMachine
;
45 import gnu
.classpath
.jdwp
.exception
.JdwpException
;
46 import gnu
.classpath
.jdwp
.exception
.JdwpInternalErrorException
;
47 import gnu
.classpath
.jdwp
.exception
.NotImplementedException
;
48 import gnu
.classpath
.jdwp
.id
.ObjectId
;
49 import gnu
.classpath
.jdwp
.id
.ReferenceTypeId
;
50 import gnu
.classpath
.jdwp
.util
.JdwpString
;
51 import gnu
.classpath
.jdwp
.util
.Signature
;
53 import java
.io
.DataOutputStream
;
54 import java
.io
.IOException
;
55 import java
.nio
.ByteBuffer
;
56 import java
.util
.ArrayList
;
57 import java
.util
.Collection
;
58 import java
.util
.Iterator
;
59 import java
.util
.Properties
;
62 * A class representing the VirtualMachine Command Set.
64 * @author Aaron Luchko <aluchko@redhat.com>
66 public class VirtualMachineCommandSet
69 public boolean runCommand(ByteBuffer bb
, DataOutputStream os
, byte command
)
72 boolean shutdown
= false;
77 case JdwpConstants
.CommandSet
.VirtualMachine
.VERSION
:
78 executeVersion(bb
, os
);
80 case JdwpConstants
.CommandSet
.VirtualMachine
.CLASSES_BY_SIGNATURE
:
81 executeClassesBySignature(bb
, os
);
83 case JdwpConstants
.CommandSet
.VirtualMachine
.ALL_CLASSES
:
84 executeAllClasses(bb
, os
);
86 case JdwpConstants
.CommandSet
.VirtualMachine
.ALL_THREADS
:
87 executeAllThreads(bb
, os
);
89 case JdwpConstants
.CommandSet
.VirtualMachine
.TOP_LEVEL_THREAD_GROUPS
:
90 executeTopLevelThreadGroups(bb
, os
);
92 case JdwpConstants
.CommandSet
.VirtualMachine
.IDSIZES
:
93 executeIDsizes(bb
, os
);
95 case JdwpConstants
.CommandSet
.VirtualMachine
.DISPOSE
:
97 executeDispose(bb
, os
);
99 case JdwpConstants
.CommandSet
.VirtualMachine
.SUSPEND
:
100 executeSuspend(bb
, os
);
102 case JdwpConstants
.CommandSet
.VirtualMachine
.RESUME
:
103 executeResume(bb
, os
);
105 case JdwpConstants
.CommandSet
.VirtualMachine
.EXIT
:
109 case JdwpConstants
.CommandSet
.VirtualMachine
.CREATE_STRING
:
110 executeCreateString(bb
, os
);
112 case JdwpConstants
.CommandSet
.VirtualMachine
.CAPABILITIES
:
113 executeCapabilities(bb
, os
);
115 case JdwpConstants
.CommandSet
.VirtualMachine
.CLASS_PATHS
:
116 executeClassPaths(bb
, os
);
118 case JdwpConstants
.CommandSet
.VirtualMachine
.DISPOSE_OBJECTS
:
119 executeDisposeObjects(bb
, os
);
121 case JdwpConstants
.CommandSet
.VirtualMachine
.HOLD_EVENTS
:
122 executeHoldEvents(bb
, os
);
124 case JdwpConstants
.CommandSet
.VirtualMachine
.RELEASE_EVENTS
:
125 executeReleaseEvents(bb
, os
);
127 case JdwpConstants
.CommandSet
.VirtualMachine
.CAPABILITIES_NEW
:
128 executeCapabilitiesNew(bb
, os
);
130 case JdwpConstants
.CommandSet
.VirtualMachine
.REDEFINE_CLASSES
:
131 executeRedefineClasses(bb
, os
);
133 case JdwpConstants
.CommandSet
.VirtualMachine
.SET_DEFAULT_STRATUM
:
134 executeSetDefaultStratum(bb
, os
);
136 case JdwpConstants
.CommandSet
.VirtualMachine
.ALL_CLASSES_WITH_GENERIC
:
137 executeAllClassesWithGeneric(bb
, os
);
140 throw new NotImplementedException("Command " + command
+
141 " not found in VirtualMachine Command Set.");
144 catch (IOException ex
)
146 // The DataOutputStream we're using isn't talking to a socket at all
147 // So if we throw an IOException we're in serious trouble
148 throw new JdwpInternalErrorException(ex
);
154 private void executeVersion(ByteBuffer bb
, DataOutputStream os
)
155 throws JdwpException
, IOException
158 Properties props
= System
.getProperties();
160 int jdwpMajor
= JdwpConstants
.Version
.MAJOR
;
161 int jdwpMinor
= JdwpConstants
.Version
.MINOR
;
162 // The description field is pretty loosely defined
163 String description
= "JDWP version " + jdwpMajor
+ "." + jdwpMinor
164 + ", JVM version " + props
.getProperty("java.vm.name")
165 + " " + props
.getProperty("java.vm.version") + " "
166 + props
.getProperty("java.version");
167 String vmVersion
= props
.getProperty("java.version");
168 String vmName
= props
.getProperty("java.vm.name");
169 JdwpString
.writeString(os
, description
);
170 os
.writeInt(jdwpMajor
);
171 os
.writeInt(jdwpMinor
);
172 JdwpString
.writeString(os
, vmName
);
173 JdwpString
.writeString(os
, vmVersion
);
176 private void executeClassesBySignature(ByteBuffer bb
, DataOutputStream os
)
177 throws JdwpException
, IOException
179 String sig
= JdwpString
.readString(bb
);
180 ArrayList allMatchingClasses
= new ArrayList();
182 // This will be an Iterator over all loaded Classes
183 Collection classes
= VMVirtualMachine
.getAllLoadedClasses();
184 Iterator iter
= classes
.iterator ();
186 while (iter
.hasNext())
188 Class clazz
= (Class
) iter
.next();
189 String clazzSig
= Signature
.computeClassSignature(clazz
);
190 if (clazzSig
.equals(sig
))
191 allMatchingClasses
.add(clazz
);
194 os
.writeInt(allMatchingClasses
.size());
195 for (int i
= 0; i
< allMatchingClasses
.size(); i
++)
197 Class clazz
= (Class
) allMatchingClasses
.get(i
);
198 ReferenceTypeId id
= idMan
.getReferenceTypeId(clazz
);
200 int status
= VMVirtualMachine
.getClassStatus(clazz
);
205 private void executeAllClasses(ByteBuffer bb
, DataOutputStream os
)
206 throws JdwpException
, IOException
208 Collection classes
= VMVirtualMachine
.getAllLoadedClasses();
209 os
.writeInt(classes
.size ());
211 Iterator iter
= classes
.iterator ();
212 while (iter
.hasNext())
214 Class clazz
= (Class
) iter
.next();
215 ReferenceTypeId id
= idMan
.getReferenceTypeId(clazz
);
217 String sig
= Signature
.computeClassSignature(clazz
);
218 JdwpString
.writeString(os
, sig
);
219 int status
= VMVirtualMachine
.getClassStatus(clazz
);
224 private void executeAllThreads(ByteBuffer bb
, DataOutputStream os
)
225 throws JdwpException
, IOException
227 ThreadGroup jdwpGroup
= Thread
.currentThread().getThreadGroup();
228 ThreadGroup root
= getRootThreadGroup(jdwpGroup
);
230 int numThreads
= root
.activeCount();
231 Thread allThreads
[] = new Thread
[numThreads
];
232 root
.enumerate(allThreads
);
234 // We need to loop through for the true count since some threads may have
235 // been destroyed since we got
236 // activeCount so those spots in the array will be null. As well we must
237 // ignore any threads that belong to jdwp
239 for (int i
= 0; i
< allThreads
.length
; i
++)
241 Thread thread
= allThreads
[i
];
243 break; // No threads after this point
244 if (!thread
.getThreadGroup().equals(jdwpGroup
))
248 os
.writeInt(numThreads
);
250 for (int i
= 0; i
< allThreads
.length
; i
++)
252 Thread thread
= allThreads
[i
];
254 break; // No threads after this point
255 if (!thread
.getThreadGroup().equals(jdwpGroup
))
256 idMan
.getObjectId(thread
).write(os
);
260 private void executeTopLevelThreadGroups(ByteBuffer bb
, DataOutputStream os
)
261 throws JdwpException
, IOException
263 ThreadGroup jdwpGroup
= Thread
.currentThread().getThreadGroup ();
264 ThreadGroup root
= getRootThreadGroup(jdwpGroup
);
266 os
.writeInt(1); // Just one top level group allowed?
267 idMan
.getObjectId(root
).write(os
);
270 private void executeDispose(ByteBuffer bb
, DataOutputStream os
)
273 // resumeAllThreads isn't sufficient as a thread may have been
274 // suspended multiple times, we likely need a way to keep track of how many
275 // times a thread has been suspended or else a stronger resume method for
277 // VMVirtualMachine.resumeAllThreads ();
279 // Simply shutting down the jdwp layer will take care of the rest of the
280 // shutdown other than disabling debugging in the VM
281 // VMVirtualMachine.disableDebugging();
283 // Don't implement this until we're sure how to remove all the debugging
284 // effects from the VM.
285 throw new NotImplementedException(
286 "Command VirtualMachine.Dispose not implemented");
290 private void executeIDsizes(ByteBuffer bb
, DataOutputStream os
)
291 throws JdwpException
, IOException
293 os
.writeInt(ObjectId
.SIZE
); // fieldId FIXME
294 os
.writeInt(ObjectId
.SIZE
); // methodId FIXME
295 os
.writeInt(ObjectId
.SIZE
); // objectId
296 os
.writeInt(ReferenceTypeId
.SIZE
); // referenceTypeId
297 os
.writeInt(VMFrame
.SIZE
); // frameId
300 private void executeSuspend(ByteBuffer bb
, DataOutputStream os
)
303 VMVirtualMachine
.suspendAllThreads ();
306 private void executeResume(ByteBuffer bb
, DataOutputStream os
)
309 VMVirtualMachine
.resumeAllThreads ();
312 private void executeExit(ByteBuffer bb
, DataOutputStream os
)
313 throws JdwpException
, IOException
315 int exitCode
= bb
.getInt();
316 System
.exit (exitCode
);
319 private void executeCreateString(ByteBuffer bb
, DataOutputStream os
)
320 throws JdwpException
, IOException
322 String string
= JdwpString
.readString(bb
);
323 ObjectId stringId
= idMan
.getObjectId(string
);
325 // Since this string isn't referenced anywhere we'll disable garbage
326 // collection on it so it's still around when the debugger gets back to it.
327 stringId
.disableCollection();
331 private void executeCapabilities(ByteBuffer bb
, DataOutputStream os
)
332 throws JdwpException
, IOException
334 os
.writeBoolean(VMVirtualMachine
.canWatchFieldModification
);
335 os
.writeBoolean(VMVirtualMachine
.canWatchFieldAccess
);
336 os
.writeBoolean(VMVirtualMachine
.canGetBytecodes
);
337 os
.writeBoolean(VMVirtualMachine
.canGetSyntheticAttribute
);
338 os
.writeBoolean(VMVirtualMachine
.canGetOwnedMonitorInfo
);
339 os
.writeBoolean(VMVirtualMachine
.canGetCurrentContendedMonitor
);
340 os
.writeBoolean(VMVirtualMachine
.canGetMonitorInfo
);
343 private void executeClassPaths(ByteBuffer bb
, DataOutputStream os
)
344 throws JdwpException
, IOException
346 String baseDir
= System
.getProperty("user.dir");
347 JdwpString
.writeString(os
, baseDir
);
349 // Find and write the classpath
350 String classPath
= System
.getProperty("java.class.path");
351 String
[] paths
= classPath
.split(":");
353 os
.writeInt(paths
.length
);
354 for (int i
= 0; i
< paths
.length
; i
++)
355 JdwpString
.writeString(os
, paths
[i
]);
358 String bootPath
= System
.getProperty("sun.boot.class.path");
359 paths
= bootPath
.split(":");
360 os
.writeInt(paths
.length
);
361 for (int i
= 0; i
< paths
.length
; i
++)
362 JdwpString
.writeString(os
, paths
[i
]);
365 private void executeDisposeObjects(ByteBuffer bb
, DataOutputStream os
)
368 // Instead of going through the list of objects they give us it's probably
369 // better just to find the garbage collected objects ourselves
373 private void executeHoldEvents(ByteBuffer bb
, DataOutputStream os
)
376 // Going to have to implement a send queue somewhere and do this without
378 // Until then just don't implement
379 throw new NotImplementedException(
380 "Command VirtualMachine.HoldEvents not implemented");
383 // Opposite of executeHoldEvents
384 private void executeReleaseEvents(ByteBuffer bb
, DataOutputStream os
)
387 throw new NotImplementedException(
388 "Command VirtualMachine.ReleaseEvents not implemented");
391 private void executeCapabilitiesNew(ByteBuffer bb
, DataOutputStream os
)
392 throws JdwpException
, IOException
394 final int CAPABILITIES_NEW_SIZE
= 32;
396 executeCapabilities(bb
, os
);
397 os
.writeBoolean(VMVirtualMachine
.canRedefineClasses
);
398 os
.writeBoolean(VMVirtualMachine
.canAddMethod
);
399 os
.writeBoolean(VMVirtualMachine
.canUnrestrictedlyRedefineClasses
);
400 os
.writeBoolean(VMVirtualMachine
.canPopFrames
);
401 os
.writeBoolean(VMVirtualMachine
.canUseInstanceFilters
);
402 os
.writeBoolean(VMVirtualMachine
.canGetSourceDebugExtension
);
403 os
.writeBoolean(VMVirtualMachine
.canRequestVMDeathEvent
);
404 os
.writeBoolean(VMVirtualMachine
.canSetDefaultStratum
);
405 for (int i
= 15; i
< CAPABILITIES_NEW_SIZE
; i
++)
407 // Future capabilities (currently unused)
408 os
.writeBoolean(false);
412 private void executeRedefineClasses(ByteBuffer bb
, DataOutputStream os
)
415 if (!VMVirtualMachine
.canRedefineClasses
)
417 String msg
= "redefinition of classes is not supported";
418 throw new NotImplementedException(msg
);
421 int classes
= bb
.getInt();
422 Class
[] types
= new Class
[classes
];
423 byte[][] bytecodes
= new byte[classes
][];
424 for (int i
= 0; i
< classes
; ++i
)
426 ReferenceTypeId id
= idMan
.readReferenceTypeId(bb
);
427 int classfile
= bb
.getInt();
428 byte[] bytecode
= new byte[classfile
];
430 types
[i
] = id
.getType();
431 bytecodes
[i
] = bytecode
;
434 VMVirtualMachine
.redefineClasses (types
, bytecodes
);
437 private void executeSetDefaultStratum(ByteBuffer bb
, DataOutputStream os
)
440 if (!VMVirtualMachine
.canSetDefaultStratum
)
442 String msg
= "setting the default stratum is not supported";
443 throw new NotImplementedException(msg
);
446 String stratum
= JdwpString
.readString(bb
);
447 VMVirtualMachine
.setDefaultStratum(stratum
);
450 private void executeAllClassesWithGeneric(ByteBuffer bb
, DataOutputStream os
)
453 // We don't handle generics
454 throw new NotImplementedException(
455 "Command VirtualMachine.AllClassesWithGeneric not implemented");
459 * Find the root ThreadGroup of this ThreadGroup
461 private ThreadGroup
getRootThreadGroup(ThreadGroup group
)
463 ThreadGroup parent
= group
.getParent();
465 while (parent
!= null)
468 parent
= group
.getParent();
470 return group
; // This group was the root