Frames | No Frames |
1: /* Jdwp.java -- Virtual machine to JDWP back-end programming interface 2: Copyright (C) 2005 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.id.ThreadId; 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: * @author Keith Seitz (keiths@redhat.com) 60: */ 61: public class Jdwp 62: extends Thread 63: { 64: // The single instance of the back-end 65: private static Jdwp _instance = null; 66: 67: /** 68: * Are we debugging? 69: */ 70: public static boolean isDebugging = false; 71: 72: // Packet processor 73: private PacketProcessor _packetProcessor; 74: private Thread _ppThread; 75: 76: // JDWP configuration properties 77: private HashMap _properties; 78: 79: // The suspend property of the configure string 80: // (-Xrunjdwp:..suspend=<boolean>) 81: private static final String _PROPERTY_SUSPEND = "suspend"; 82: 83: // User's main application thread 84: private Thread _mainThread; 85: 86: // Connection to debugger 87: private JdwpConnection _connection; 88: 89: // Are we shutting down the current session? 90: private boolean _shutdown; 91: 92: // A thread group for the JDWP threads 93: private ThreadGroup _group; 94: 95: /** 96: * constructor 97: */ 98: public Jdwp () 99: { 100: _shutdown = false; 101: isDebugging = true; 102: _instance = this; 103: } 104: 105: /** 106: * Returns the JDWP back-end, creating an instance of it 107: * if one does not already exist. 108: */ 109: public static Jdwp getDefault () 110: { 111: return _instance; 112: } 113: 114: /** 115: * Should the virtual machine suspend on startup? 116: */ 117: public static boolean suspendOnStartup () 118: { 119: Jdwp jdwp = getDefault (); 120: if (jdwp != null) 121: { 122: String suspend = (String) jdwp._properties.get (_PROPERTY_SUSPEND); 123: if (suspend != null && suspend.equals ("y")) 124: return true; 125: } 126: 127: return false; 128: } 129: 130: /** 131: * Configures the back-end 132: * 133: * @param configArgs a string of configury options 134: * @param mainThread the main application thread 135: */ 136: public void configure (String configArgs, Thread mainThread) 137: { 138: _mainThread = mainThread; 139: _processConfigury (configArgs); 140: } 141: 142: // A helper function to initialize the transport layer 143: private void _doInitialization () 144: throws TransportException 145: { 146: _group = new ThreadGroup ("JDWP threads"); 147: // initialize transport 148: ITransport transport = TransportFactory.newInstance (_properties); 149: _connection = new JdwpConnection (_group, transport); 150: _connection.initialize (); 151: _connection.start (); 152: 153: // Create processor 154: _packetProcessor = new PacketProcessor (_connection); 155: _ppThread = new Thread (_group, new Runnable () 156: { 157: public void run () 158: { 159: AccessController.doPrivileged (_packetProcessor); 160: } 161: }); 162: _ppThread.start (); 163: } 164: 165: /** 166: * Shutdown the JDWP back-end 167: * 168: * NOTE: This does not quite work properly. See notes in 169: * run() on this subject (catch of InterruptedException). 170: */ 171: public void shutdown () 172: { 173: if (!_shutdown) 174: { 175: _packetProcessor.shutdown (); 176: _ppThread.interrupt (); 177: _connection.shutdown (); 178: _shutdown = true; 179: isDebugging = false; 180: 181: /* FIXME: probably need to check state of user's 182: program -- if it is suspended, we need to either 183: resume or kill them. */ 184: 185: interrupt (); 186: } 187: } 188: 189: /** 190: * Notify the debugger of an event. This method should not 191: * be called if debugging is not active (but it would not 192: * cause any harm). Places where event notifications occur 193: * should check isDebugging before doing anything. 194: * 195: * The event is filtered through the event manager before being 196: * sent. 197: * 198: * FIXME: Probably need logic to send multiple events 199: * @param event the event to report 200: */ 201: public static void notify (Event event) 202: { 203: Jdwp jdwp = getDefault (); 204: if (jdwp != null) 205: { 206: EventManager em = EventManager.getDefault (); 207: EventRequest request = em.getEventRequest (event); 208: if (request != null) 209: sendEvent (request, event); 210: } 211: } 212: 213: /** 214: * Sends the event to the debugger. 215: * 216: * This method bypasses the event manager's filtering. 217: * 218: * @param request the debugger request for the event 219: * @param event the event to send 220: */ 221: public static void sendEvent (EventRequest request, Event event) 222: { 223: Jdwp jdwp = getDefault (); 224: if (jdwp != null) 225: { 226: try 227: { 228: // !! May need to implement send queue? 229: synchronized (jdwp._connection) 230: { 231: jdwp._connection.sendEvent (request, event); 232: } 233: 234: // Follow suspend policy 235: jdwp._enforceSuspendPolicy (request.getSuspendPolicy ()); 236: } 237: catch (IOException ie) 238: { 239: System.out.println ("Jdwp.notify: caught exception: " + ie); 240: } 241: } 242: } 243: 244: // Helper function to enforce suspend policies on event notification 245: private void _enforceSuspendPolicy (byte suspendPolicy) 246: { 247: switch (suspendPolicy) 248: { 249: case EventRequest.SUSPEND_NONE: 250: // do nothing 251: break; 252: 253: case EventRequest.SUSPEND_THREAD: 254: VMVirtualMachine.suspendThread (this); 255: break; 256: 257: case EventRequest.SUSPEND_ALL: 258: VMVirtualMachine.suspendAllThreads (); 259: break; 260: } 261: } 262: 263: public void run () 264: { 265: try 266: { 267: _doInitialization (); 268: 269: _mainThread.start (); 270: 271: _mainThread.join (); 272: } 273: catch (InterruptedException ie) 274: { 275: /* Shutting down. If we're in server mode, we should 276: prepare for a new connection. Otherwise, we should 277: simply exit. */ 278: // FIXME 279: } 280: catch (Throwable t) 281: { 282: System.out.println ("Exception in JDWP back-end: " + t); 283: System.exit (1); 284: } 285: } 286: 287: // A helper function to process the configure string "-Xrunjdwp:..." 288: private void _processConfigury (String configString) 289: { 290: // Loop through configuration arguments looking for a 291: // transport name 292: _properties = new HashMap (); 293: String[] options = configString.split (","); 294: for (int i = 0; i < options.length; ++i) 295: { 296: String[] property = options[i].split ("="); 297: if (property.length == 2) 298: _properties.put (property[0], property[1]); 299: // ignore malformed options 300: } 301: } 302: }