OSDN Git Service

Classpath JDWP merge with upstream
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / classpath / jdwp / processor / VirtualMachineCommandSet.java
1 /* VirtualMachineCommandSet.java -- class to implement the VirtualMachine
2    Command Set
3    Copyright (C) 2005, 2006, 2007 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.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;
52
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;
60
61 /**
62  * A class representing the VirtualMachine Command Set.
63  * 
64  * @author Aaron Luchko <aluchko@redhat.com>
65  */
66 public class VirtualMachineCommandSet
67   extends CommandSet
68 {
69   public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command)
70     throws JdwpException
71   {
72     boolean shutdown = false;
73     try
74       {
75         switch (command)
76           {
77           case JdwpConstants.CommandSet.VirtualMachine.VERSION:
78             executeVersion(bb, os);
79             break;
80           case JdwpConstants.CommandSet.VirtualMachine.CLASSES_BY_SIGNATURE:
81             executeClassesBySignature(bb, os);
82             break;
83           case JdwpConstants.CommandSet.VirtualMachine.ALL_CLASSES:
84             executeAllClasses(bb, os);
85             break;
86           case JdwpConstants.CommandSet.VirtualMachine.ALL_THREADS:
87             executeAllThreads(bb, os);
88             break;
89           case JdwpConstants.CommandSet.VirtualMachine.TOP_LEVEL_THREAD_GROUPS:
90             executeTopLevelThreadGroups(bb, os);
91             break;
92           case JdwpConstants.CommandSet.VirtualMachine.IDSIZES:
93             executeIDsizes(bb, os);
94             break;
95           case JdwpConstants.CommandSet.VirtualMachine.DISPOSE:
96             shutdown = true;
97             executeDispose(bb, os);
98             break;
99           case JdwpConstants.CommandSet.VirtualMachine.SUSPEND:
100             executeSuspend(bb, os);
101             break;
102           case JdwpConstants.CommandSet.VirtualMachine.RESUME:
103             executeResume(bb, os);
104             break;
105           case JdwpConstants.CommandSet.VirtualMachine.EXIT:
106             shutdown = true;
107             executeExit(bb, os);
108             break;
109           case JdwpConstants.CommandSet.VirtualMachine.CREATE_STRING:
110             executeCreateString(bb, os);
111             break;
112           case JdwpConstants.CommandSet.VirtualMachine.CAPABILITIES:
113             executeCapabilities(bb, os);
114             break;
115           case JdwpConstants.CommandSet.VirtualMachine.CLASS_PATHS:
116             executeClassPaths(bb, os);
117             break;
118           case JdwpConstants.CommandSet.VirtualMachine.DISPOSE_OBJECTS:
119             executeDisposeObjects(bb, os);
120             break;
121           case JdwpConstants.CommandSet.VirtualMachine.HOLD_EVENTS:
122             executeHoldEvents(bb, os);
123             break;
124           case JdwpConstants.CommandSet.VirtualMachine.RELEASE_EVENTS:
125             executeReleaseEvents(bb, os);
126             break;
127           case JdwpConstants.CommandSet.VirtualMachine.CAPABILITIES_NEW:
128             executeCapabilitiesNew(bb, os);
129             break;
130           case JdwpConstants.CommandSet.VirtualMachine.REDEFINE_CLASSES:
131             executeRedefineClasses(bb, os);
132             break;
133           case JdwpConstants.CommandSet.VirtualMachine.SET_DEFAULT_STRATUM:
134             executeSetDefaultStratum(bb, os);
135             break;
136           case JdwpConstants.CommandSet.VirtualMachine.ALL_CLASSES_WITH_GENERIC:
137             executeAllClassesWithGeneric(bb, os);
138             break;
139           default:
140             throw new NotImplementedException("Command " + command +
141             " not found in VirtualMachine Command Set.");
142           }
143       }
144     catch (IOException ex)
145       {
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);
149       }
150
151     return shutdown;
152   }
153
154   private void executeVersion(ByteBuffer bb, DataOutputStream os)
155     throws JdwpException, IOException
156   {
157
158     Properties props = System.getProperties();
159
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);
174   }
175
176   private void executeClassesBySignature(ByteBuffer bb, DataOutputStream os)
177     throws JdwpException, IOException
178   {
179     String sig = JdwpString.readString(bb);
180     ArrayList allMatchingClasses = new ArrayList();
181
182     // This will be an Iterator over all loaded Classes
183     Collection classes = VMVirtualMachine.getAllLoadedClasses();
184     Iterator iter = classes.iterator ();
185
186     while (iter.hasNext())
187       {
188         Class clazz = (Class) iter.next();
189         String clazzSig = Signature.computeClassSignature(clazz);
190         if (clazzSig.equals(sig))
191           allMatchingClasses.add(clazz);
192       }
193
194     os.writeInt(allMatchingClasses.size());
195     for (int i = 0; i < allMatchingClasses.size(); i++)
196       {
197         Class clazz = (Class) allMatchingClasses.get(i);
198         ReferenceTypeId id = idMan.getReferenceTypeId(clazz);
199         id.writeTagged(os);
200         int status = VMVirtualMachine.getClassStatus(clazz);
201         os.writeInt(status);
202       }
203   }
204
205   private void executeAllClasses(ByteBuffer bb, DataOutputStream os)
206     throws JdwpException, IOException
207   {
208     Collection classes = VMVirtualMachine.getAllLoadedClasses();
209     os.writeInt(classes.size ());
210
211     Iterator iter = classes.iterator ();
212     while (iter.hasNext())
213       {
214         Class clazz = (Class) iter.next();
215         ReferenceTypeId id = idMan.getReferenceTypeId(clazz);
216         id.writeTagged(os);
217         String sig = Signature.computeClassSignature(clazz);
218         JdwpString.writeString(os, sig);
219         int status = VMVirtualMachine.getClassStatus(clazz);
220         os.writeInt(status);
221       }
222   }
223
224   private void executeAllThreads(ByteBuffer bb, DataOutputStream os)
225     throws JdwpException, IOException
226   {
227     ThreadGroup jdwpGroup = Thread.currentThread().getThreadGroup();
228     ThreadGroup root = getRootThreadGroup(jdwpGroup);
229
230     int numThreads = root.activeCount();
231     Thread allThreads[] = new Thread[numThreads];
232     root.enumerate(allThreads);
233
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
238     numThreads = 0;
239     for (int i = 0; i < allThreads.length; i++)
240       {
241         Thread thread = allThreads[i];
242         if (thread == null)
243           break; // No threads after this point
244         if (!thread.getThreadGroup().equals(jdwpGroup))
245           numThreads++;
246       }
247
248     os.writeInt(numThreads);
249
250     for (int i = 0; i < allThreads.length; i++)
251       {
252         Thread thread = allThreads[i];
253         if (thread == null)
254           break; // No threads after this point
255         if (!thread.getThreadGroup().equals(jdwpGroup))
256           idMan.getObjectId(thread).write(os);
257       }
258   }
259
260   private void executeTopLevelThreadGroups(ByteBuffer bb, DataOutputStream os)
261     throws JdwpException, IOException
262   {
263     ThreadGroup jdwpGroup = Thread.currentThread().getThreadGroup ();
264     ThreadGroup root = getRootThreadGroup(jdwpGroup);
265
266     os.writeInt(1); // Just one top level group allowed?
267     idMan.getObjectId(root);
268   }
269
270   private void executeDispose(ByteBuffer bb, DataOutputStream os)
271     throws JdwpException
272   {
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
276     // this purpose
277     // VMVirtualMachine.resumeAllThreads ();
278
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();
282
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");
287
288   }
289
290   private void executeIDsizes(ByteBuffer bb, DataOutputStream os)
291     throws JdwpException, IOException
292   {
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
298   }
299
300   private void executeSuspend(ByteBuffer bb, DataOutputStream os)
301     throws JdwpException
302   {
303     VMVirtualMachine.suspendAllThreads ();
304   }
305
306   private void executeResume(ByteBuffer bb, DataOutputStream os)
307     throws JdwpException
308   {
309     VMVirtualMachine.resumeAllThreads ();
310   }
311
312   private void executeExit(ByteBuffer bb, DataOutputStream os)
313     throws JdwpException, IOException
314   {
315     int exitCode = bb.getInt();
316     System.exit (exitCode);
317   }
318
319   private void executeCreateString(ByteBuffer bb, DataOutputStream os)
320     throws JdwpException, IOException
321   {
322     String string = JdwpString.readString(bb);
323     ObjectId stringId = idMan.getObjectId(string);
324     
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();
328     stringId.write(os);
329   }
330
331   private void executeCapabilities(ByteBuffer bb, DataOutputStream os)
332     throws JdwpException, IOException
333   {
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);
341   }
342
343   private void executeClassPaths(ByteBuffer bb, DataOutputStream os)
344     throws JdwpException, IOException
345   {
346     String baseDir = System.getProperty("user.dir");
347     JdwpString.writeString(os, baseDir);
348
349     // Find and write the classpath
350     String classPath = System.getProperty("java.class.path");
351     String[] paths = classPath.split(":");
352
353     os.writeInt(paths.length);
354     for (int i = 0; i < paths.length; i++)
355       JdwpString.writeString(os, paths[i]);
356
357     // Now the bootpath
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]);
363   }
364
365   private void executeDisposeObjects(ByteBuffer bb, DataOutputStream os)
366     throws JdwpException
367   {
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
370     //idMan.update();
371   }
372
373   private void executeHoldEvents(ByteBuffer bb, DataOutputStream os)
374     throws JdwpException
375   {
376     // Going to have to implement a send queue somewhere and do this without
377     // triggering events
378     // Until then just don't implement
379     throw new NotImplementedException(
380       "Command VirtualMachine.HoldEvents not implemented");
381   }
382
383   // Opposite of executeHoldEvents
384   private void executeReleaseEvents(ByteBuffer bb, DataOutputStream os)
385     throws JdwpException
386   {
387     throw new NotImplementedException(
388       "Command VirtualMachine.ReleaseEvents not implemented");
389   }
390
391   private void executeCapabilitiesNew(ByteBuffer bb, DataOutputStream os)
392     throws JdwpException, IOException
393   {
394     final int CAPABILITIES_NEW_SIZE = 32;
395
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++)
406       {
407         // Future capabilities (currently unused)
408         os.writeBoolean(false);
409       }
410   }
411
412   private void executeRedefineClasses(ByteBuffer bb, DataOutputStream os)
413     throws JdwpException
414   {
415     if (!VMVirtualMachine.canRedefineClasses)
416       {
417         String msg = "redefinition of classes is not supported";
418         throw new NotImplementedException(msg);
419       }
420
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)
425       {
426         ReferenceTypeId id = idMan.readReferenceTypeId(bb);
427         int classfile = bb.getInt();
428         byte[] bytecode = new byte[classfile];
429         bb.get(bytecode);
430         types[i] = id.getType();
431         bytecodes[i] = bytecode;
432       }
433
434     VMVirtualMachine.redefineClasses (types, bytecodes);
435   }
436
437   private void executeSetDefaultStratum(ByteBuffer bb, DataOutputStream os)
438     throws JdwpException
439   {
440     if (!VMVirtualMachine.canSetDefaultStratum)
441       {
442         String msg = "setting the default stratum is not supported";
443         throw new NotImplementedException(msg);
444       }
445
446     String stratum = JdwpString.readString(bb);
447     VMVirtualMachine.setDefaultStratum(stratum);
448   }
449
450   private void executeAllClassesWithGeneric(ByteBuffer bb, DataOutputStream os)
451     throws JdwpException
452   {
453     // We don't handle generics
454     throw new NotImplementedException(
455       "Command VirtualMachine.AllClassesWithGeneric not implemented");
456   }
457
458   /**
459    * Find the root ThreadGroup of this ThreadGroup
460    */
461   private ThreadGroup getRootThreadGroup(ThreadGroup group)
462   {
463     ThreadGroup parent = group.getParent();
464
465     while (parent != null)
466       {
467         group = parent;
468         parent = group.getParent();
469       }
470     return group; // This group was the root
471   }
472 }