Frames | No Frames |
1: /* Jdwp.java -- Virtual machine to JDWP back-end programming interface 2: Copyright (C) 2005, 2006 Free Software Foundation 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 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; 41: 42: import gnu.classpath.jdwp.event.Event; 43: import gnu.classpath.jdwp.event.EventManager; 44: import gnu.classpath.jdwp.event.EventRequest; 45: import gnu.classpath.jdwp.exception.JdwpException; 46: import gnu.classpath.jdwp.processor.PacketProcessor; 47: import gnu.classpath.jdwp.transport.ITransport; 48: import gnu.classpath.jdwp.transport.JdwpConnection; 49: import gnu.classpath.jdwp.transport.TransportException; 50: import gnu.classpath.jdwp.transport.TransportFactory; 51: 52: import java.io.IOException; 53: import java.security.AccessController; 54: import java.util.HashMap; 55: 56: /** 57: * Main interface from the virtual machine to the JDWP back-end. 58: * 59: * The thread created by this class is only used for initialization. 60: * Once it exits, the JDWP backend is fully initialized. 61: * 62: * @author Keith Seitz (keiths@redhat.com) 63: */ 64: public class Jdwp 65: extends Thread 66: { 67: // The single instance of the back-end 68: private static Jdwp _instance = null; 69: 70: /** 71: * Are we debugging? Only true if debugging 72: * *and* initialized. 73: */ 74: public static boolean isDebugging = false; 75: 76: // Packet processor 77: private PacketProcessor _packetProcessor; 78: private Thread _ppThread; 79: 80: // JDWP configuration properties 81: private HashMap _properties; 82: 83: // The suspend property of the configure string 84: // (-Xrunjdwp:..suspend=<boolean>) 85: private static final String _PROPERTY_SUSPEND = "suspend"; 86: 87: // Connection to debugger 88: private JdwpConnection _connection; 89: 90: // Are we shutting down the current session? 91: private boolean _shutdown; 92: 93: // A thread group for the JDWP threads 94: private ThreadGroup _group; 95: 96: // Initialization synchronization 97: private Object _initLock = new Object (); 98: private int _initCount = 0; 99: 100: /** 101: * constructor 102: */ 103: public Jdwp () 104: { 105: _shutdown = false; 106: _instance = this; 107: } 108: 109: /** 110: * Returns the JDWP back-end, creating an instance of it 111: * if one does not already exist. 112: */ 113: public static Jdwp getDefault () 114: { 115: return _instance; 116: } 117: 118: /** 119: * Get the thread group used by JDWP threads 120: * 121: * @return the thread group 122: */ 123: public ThreadGroup getJdwpThreadGroup() 124: { 125: return _group; 126: } 127: 128: /** 129: * Should the virtual machine suspend on startup? 130: */ 131: public static boolean suspendOnStartup () 132: { 133: Jdwp jdwp = getDefault (); 134: if (jdwp != null) 135: { 136: String suspend = (String) jdwp._properties.get (_PROPERTY_SUSPEND); 137: if (suspend != null && suspend.equals ("y")) 138: return true; 139: } 140: 141: return false; 142: } 143: 144: /** 145: * Configures the back-end 146: * 147: * @param configArgs a string of configury options 148: */ 149: public void configure (String configArgs) 150: { 151: _processConfigury (configArgs); 152: } 153: 154: // A helper function to initialize the transport layer 155: private void _doInitialization () 156: throws TransportException 157: { 158: _group = new ThreadGroup ("JDWP threads"); 159: // initialize transport 160: ITransport transport = TransportFactory.newInstance (_properties); 161: _connection = new JdwpConnection (_group, transport); 162: _connection.initialize (); 163: _connection.start (); 164: 165: // Create processor 166: _packetProcessor = new PacketProcessor (_connection); 167: _ppThread = new Thread (_group, new Runnable () 168: { 169: public void run () 170: { 171: AccessController.doPrivileged (_packetProcessor); 172: } 173: }, "packet processor"); 174: _ppThread.start (); 175: } 176: 177: /** 178: * Shutdown the JDWP back-end 179: * 180: * NOTE: This does not quite work properly. See notes in 181: * run() on this subject (catch of InterruptedException). 182: */ 183: public void shutdown () 184: { 185: if (!_shutdown) 186: { 187: _packetProcessor.shutdown (); 188: _ppThread.interrupt (); 189: _connection.shutdown (); 190: _shutdown = true; 191: isDebugging = false; 192: 193: /* FIXME: probably need to check state of user's 194: program -- if it is suspended, we need to either 195: resume or kill them. */ 196: 197: interrupt (); 198: } 199: } 200: 201: /** 202: * Notify the debugger of an event. This method should not 203: * be called if debugging is not active (but it would not 204: * cause any harm). Places where event notifications occur 205: * should check isDebugging before doing anything. 206: * 207: * The event is filtered through the event manager before being 208: * sent. 209: * 210: * FIXME: Probably need logic to send multiple events 211: * @param event the event to report 212: */ 213: public static void notify (Event event) 214: { 215: Jdwp jdwp = getDefault (); 216: if (jdwp != null) 217: { 218: EventManager em = EventManager.getDefault (); 219: EventRequest request = em.getEventRequest (event); 220: if (request != null) 221: { 222: try 223: { 224: System.out.println ("Jdwp.notify: sending event " + event); 225: sendEvent (request, event); 226: jdwp._enforceSuspendPolicy (request.getSuspendPolicy ()); 227: } 228: catch (Exception e) 229: { 230: /* Really not much we can do. For now, just print out 231: a warning to the user. */ 232: System.out.println ("Jdwp.notify: caught exception: " + e); 233: } 234: } 235: } 236: } 237: 238: /** 239: * Sends the event to the debugger. 240: * 241: * This method bypasses the event manager's filtering. 242: * 243: * @param request the debugger request for the event 244: * @param event the event to send 245: * @throws IOException if a communications failure occurs 246: */ 247: public static void sendEvent (EventRequest request, Event event) 248: throws IOException 249: { 250: Jdwp jdwp = getDefault (); 251: if (jdwp != null) 252: { 253: // !! May need to implement send queue? 254: synchronized (jdwp._connection) 255: { 256: jdwp._connection.sendEvent (request, event); 257: } 258: } 259: } 260: 261: // Helper function to enforce suspend policies on event notification 262: private void _enforceSuspendPolicy (byte suspendPolicy) 263: throws JdwpException 264: { 265: switch (suspendPolicy) 266: { 267: case EventRequest.SUSPEND_NONE: 268: // do nothing 269: break; 270: 271: case EventRequest.SUSPEND_THREAD: 272: VMVirtualMachine.suspendThread (Thread.currentThread ()); 273: break; 274: 275: case EventRequest.SUSPEND_ALL: 276: VMVirtualMachine.suspendAllThreads (); 277: break; 278: } 279: } 280: 281: /** 282: * Allows subcomponents to specify that they are 283: * initialized. 284: * 285: * Subcomponents include JdwpConnection and PacketProcessor. 286: */ 287: public void subcomponentInitialized () 288: { 289: synchronized (_initLock) 290: { 291: ++_initCount; 292: _initLock.notify (); 293: } 294: } 295: 296: public void run () 297: { 298: try 299: { 300: _doInitialization (); 301: 302: /* We need a little internal synchronization here, so that 303: when this thread dies, the back-end will be fully initialized, 304: ready to start servicing the VM and debugger. */ 305: synchronized (_initLock) 306: { 307: while (_initCount != 2) 308: _initLock.wait (); 309: } 310: _initLock = null; 311: } 312: catch (Throwable t) 313: { 314: System.out.println ("Exception in JDWP back-end: " + t); 315: System.exit (1); 316: } 317: 318: /* Force creation of the EventManager. If the event manager 319: has not been created when isDebugging is set, it is possible 320: that the VM will call Jdwp.notify (which uses EventManager) 321: while the EventManager is being created (or at least this is 322: a problem with gcj/gij). */ 323: EventManager.getDefault(); 324: 325: // Now we are finally ready and initialized 326: isDebugging = true; 327: } 328: 329: // A helper function to process the configure string "-Xrunjdwp:..." 330: private void _processConfigury (String configString) 331: { 332: // Loop through configuration arguments looking for a 333: // transport name 334: _properties = new HashMap (); 335: String[] options = configString.split (","); 336: for (int i = 0; i < options.length; ++i) 337: { 338: String[] property = options[i].split ("="); 339: if (property.length == 2) 340: _properties.put (property[0], property[1]); 341: // ignore malformed options 342: } 343: } 344: }