hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/Win32DebuggerLocal.java
changeset 10864 17307b96ae38
parent 10779 5037da29fa26
parent 10762 cc1f5ce8e504
child 10865 7f8dd1713604
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/win32/Win32DebuggerLocal.java	Mon Oct 24 09:58:47 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1083 +0,0 @@
-/*
- * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-package sun.jvm.hotspot.debugger.win32;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.debugger.x86.*;
-import sun.jvm.hotspot.debugger.win32.coff.*;
-import sun.jvm.hotspot.debugger.cdbg.*;
-import sun.jvm.hotspot.debugger.cdbg.basic.BasicDebugEvent;
-import sun.jvm.hotspot.utilities.*;
-import sun.jvm.hotspot.utilities.memo.*;
-
-/** <P> An implementation of the JVMDebugger interface which talks to
-    the Free Windows Debug Server (FwDbgSrv) over a socket to
-    implement attach/detach and read from process memory. All DLL and
-    symbol table management is done in Java. </P>
-
-    <P> <B>NOTE</B> that since we have the notion of fetching "Java
-    primitive types" from the remote process (which might have
-    different sizes than we expect) we have a bootstrapping
-    problem. We need to know the sizes of these types before we can
-    fetch them. The current implementation solves this problem by
-    requiring that it be configured with these type sizes before they
-    can be fetched. The readJ(Type) routines here will throw a
-    RuntimeException if they are called before the debugger is
-    configured with the Java primitive type sizes. </P> */
-
-public class Win32DebuggerLocal extends DebuggerBase implements Win32Debugger {
-  private Socket debuggerSocket;
-  private boolean attached;
-  // FIXME: update when core files supported
-  private long pid;
-  // Communication with debug server
-  private PrintWriter out;
-  private DataOutputStream rawOut;
-  private InputLexer in;
-  private static final int PORT = 27000;
-  private PageCache cache;
-  private static final long SHORT_TIMEOUT = 2000;
-  private static final long LONG_TIMEOUT = 20000;
-
-  // Symbol lookup support
-  // This is a map of library names to DLLs
-  private Map nameToDllMap;
-
-  // C/C++ debugging support
-  private List/*<LoadObject>*/ loadObjects;
-  private CDebugger cdbg;
-
-  // ProcessControl support
-  private boolean suspended;
-  // Maps Long objects (addresses) to Byte objects (original instructions)
-  // (Longs used instead of Addresses to properly represent breakpoints at 0x0 if needed)
-  private Map     breakpoints;
-  // Current debug event, if any
-  private DebugEvent curDebugEvent;
-
-  //--------------------------------------------------------------------------------
-  // Implementation of Debugger interface
-  //
-
-  /** <P> machDesc may not be null. </P>
-
-      <P> useCache should be set to true if debugging is being done
-      locally, and to false if the debugger is being created for the
-      purpose of supporting remote debugging. </P> */
-  public Win32DebuggerLocal(MachineDescription machDesc,
-                            boolean useCache) throws DebuggerException {
-    this.machDesc = machDesc;
-    utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian());
-    if (useCache) {
-      // Cache portion of the remote process's address space.
-      // Fetching data over the socket connection to dbx is slow.
-      // Might be faster if we were using a binary protocol to talk to
-      // dbx, but would have to test. For now, this cache works best
-      // if it covers the entire heap of the remote process. FIXME: at
-      // least should make this tunable from the outside, i.e., via
-      // the UI. This is a cache of 4096 4K pages, or 16 MB. The page
-      // size must be adjusted to be the hardware's page size.
-      // (FIXME: should pick this up from the debugger.)
-      initCache(4096, parseCacheNumPagesProperty(4096));
-    }
-    // FIXME: add instantiation of thread factory
-
-    try {
-      connectToDebugServer();
-    } catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-  }
-
-  /** From the Debugger interface via JVMDebugger */
-  public boolean hasProcessList() throws DebuggerException {
-    return true;
-  }
-
-  /** From the Debugger interface via JVMDebugger */
-  public List getProcessList() throws DebuggerException {
-    List processes = new ArrayList();
-
-    try {
-      printlnToOutput("proclist");
-      int num = in.parseInt();
-      for (int i = 0; i < num; i++) {
-        int pid = in.parseInt();
-        String name = parseString();
-        // NOTE: Win32 hack
-        if (name.equals("")) {
-          name = "System Idle Process";
-        }
-        processes.add(new ProcessInfo(name, pid));
-      }
-      return processes;
-    }
-    catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-  }
-
-  /** From the Debugger interface via JVMDebugger */
-  public synchronized void attach(int processID) throws DebuggerException {
-    if (attached) {
-      // FIXME: update when core files supported
-      throw new DebuggerException("Already attached to process " + pid);
-    }
-
-    try {
-      printlnToOutput("attach " + processID);
-      if (!in.parseBoolean()) {
-        throw new DebuggerException("Error attaching to process, or no such process");
-      }
-
-      attached = true;
-      pid = processID;
-      suspended = true;
-      breakpoints = new HashMap();
-      curDebugEvent = null;
-      nameToDllMap = null;
-      loadObjects = null;
-    }
-    catch (IOException e) {
-        throw new DebuggerException(e);
-    }
-  }
-
-  /** From the Debugger interface via JVMDebugger */
-  public synchronized void attach(String executableName, String coreFileName) throws DebuggerException {
-    throw new DebuggerException("Core files not yet supported on Win32");
-  }
-
-  /** From the Debugger interface via JVMDebugger */
-  public synchronized boolean detach() {
-    if (!attached) {
-      return false;
-    }
-
-    attached = false;
-    suspended = false;
-    breakpoints = null;
-
-    // Close all open DLLs
-    if (nameToDllMap != null) {
-      for (Iterator iter = nameToDllMap.values().iterator(); iter.hasNext(); ) {
-        DLL dll = (DLL) iter.next();
-        dll.close();
-      }
-      nameToDllMap = null;
-      loadObjects = null;
-    }
-
-    cdbg = null;
-    clearCache();
-
-    try {
-      printlnToOutput("detach");
-      return in.parseBoolean();
-    }
-    catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-  }
-
-  /** From the Debugger interface via JVMDebugger */
-  public Address parseAddress(String addressString) throws NumberFormatException {
-    return newAddress(utils.scanAddress(addressString));
-  }
-
-  /** From the Debugger interface via JVMDebugger */
-  public String getOS() {
-    return PlatformInfo.getOS();
-  }
-
-  /** From the Debugger interface via JVMDebugger */
-  public String getCPU() {
-    return PlatformInfo.getCPU();
-  }
-
-  public boolean hasConsole() throws DebuggerException {
-    return false;
-  }
-
-  public String consoleExecuteCommand(String cmd) throws DebuggerException {
-    throw new DebuggerException("No debugger console available on Win32");
-  }
-
-  public String getConsolePrompt() throws DebuggerException {
-    return null;
-  }
-
-  public CDebugger getCDebugger() throws DebuggerException {
-    if (cdbg == null) {
-      cdbg = new Win32CDebugger(this);
-    }
-    return cdbg;
-  }
-
-  /** From the SymbolLookup interface via Debugger and JVMDebugger */
-  public synchronized Address lookup(String objectName, String symbol) {
-    if (!attached) {
-      return null;
-    }
-    return newAddress(lookupInProcess(objectName, symbol));
-  }
-
-  /** From the SymbolLookup interface via Debugger and JVMDebugger */
-  public synchronized OopHandle lookupOop(String objectName, String symbol) {
-    Address addr = lookup(objectName, symbol);
-    if (addr == null) {
-      return null;
-    }
-    return addr.addOffsetToAsOopHandle(0);
-  }
-
-  /** From the Debugger interface */
-  public MachineDescription getMachineDescription() {
-    return machDesc;
-  }
-
-  //--------------------------------------------------------------------------------
-  // Implementation of ThreadAccess interface
-  //
-
-  /** From the ThreadAccess interface via Debugger and JVMDebugger */
-  public ThreadProxy getThreadForIdentifierAddress(Address addr) {
-    return new Win32Thread(this, addr);
-  }
-
-  public ThreadProxy getThreadForThreadId(long handle) {
-    return new Win32Thread(this, handle);
-  }
-
-  //----------------------------------------------------------------------
-  // Overridden from DebuggerBase because we need to relax alignment
-  // constraints on x86
-
-  public long readJLong(long address)
-    throws UnmappedAddressException, UnalignedAddressException {
-    checkJavaConfigured();
-    // FIXME: allow this to be configurable. Undesirable to add a
-    // dependency on the runtime package here, though, since this
-    // package should be strictly underneath it.
-    //    utils.checkAlignment(address, jlongSize);
-    utils.checkAlignment(address, jintSize);
-    byte[] data = readBytes(address, jlongSize);
-    return utils.dataToJLong(data, jlongSize);
-  }
-
-  //--------------------------------------------------------------------------------
-  // Internal routines (for implementation of Win32Address).
-  // These must not be called until the MachineDescription has been set up.
-  //
-
-  /** From the Win32Debugger interface */
-  public String addressValueToString(long address) {
-    return utils.addressValueToString(address);
-  }
-
-  /** From the Win32Debugger interface */
-  public Win32Address readAddress(long address)
-    throws UnmappedAddressException, UnalignedAddressException {
-    return (Win32Address) newAddress(readAddressValue(address));
-  }
-
-  public Win32Address readCompOopAddress(long address)
-    throws UnmappedAddressException, UnalignedAddressException {
-    return (Win32Address) newAddress(readCompOopAddressValue(address));
-  }
-
-  /** From the Win32Debugger interface */
-  public Win32OopHandle readOopHandle(long address)
-    throws UnmappedAddressException, UnalignedAddressException, NotInHeapException {
-    long value = readAddressValue(address);
-    return (value == 0 ? null : new Win32OopHandle(this, value));
-  }
-  public Win32OopHandle readCompOopHandle(long address)
-    throws UnmappedAddressException, UnalignedAddressException, NotInHeapException {
-    long value = readCompOopAddressValue(address);
-    return (value == 0 ? null : new Win32OopHandle(this, value));
-  }
-
-  /** From the Win32Debugger interface */
-  public void writeAddress(long address, Win32Address value) {
-    writeAddressValue(address, getAddressValue(value));
-  }
-
-  /** From the Win32Debugger interface */
-  public void writeOopHandle(long address, Win32OopHandle value) {
-    writeAddressValue(address, getAddressValue(value));
-  }
-
-  //--------------------------------------------------------------------------------
-  // Thread context access
-  //
-
-  public synchronized long[] getThreadIntegerRegisterSet(int threadHandleValue,
-                                                         boolean mustDuplicateHandle)
-    throws DebuggerException {
-    if (!suspended) {
-      throw new DebuggerException("Process not suspended");
-    }
-
-    try {
-      int handle = threadHandleValue;
-      if (mustDuplicateHandle) {
-        printlnToOutput("duphandle 0x" + Integer.toHexString(threadHandleValue));
-        if (!in.parseBoolean()) {
-          throw new DebuggerException("Error duplicating thread handle 0x" + threadHandleValue);
-        }
-        handle = (int) in.parseAddress(); // Must close to avoid leaks
-      }
-      printlnToOutput("getcontext 0x" + Integer.toHexString(handle));
-      if (!in.parseBoolean()) {
-        if (mustDuplicateHandle) {
-          printlnToOutput("closehandle 0x" + Integer.toHexString(handle));
-        }
-        String failMessage = "GetThreadContext failed for thread handle 0x" +
-                             Integer.toHexString(handle);
-        if (mustDuplicateHandle) {
-          failMessage = failMessage + ", duplicated from thread handle " +
-                        Integer.toHexString(threadHandleValue);
-        }
-        throw new DebuggerException(failMessage);
-      }
-      // Otherwise, parse all registers. See
-      // src/os/win32/agent/README-commands.txt for the format.
-      // Note the array we have to return has to match that specified by
-      // X86ThreadContext.java.
-      int numRegs = 22;
-      long[] winRegs = new long[numRegs];
-      for (int i = 0; i < numRegs; i++) {
-        winRegs[i] = in.parseAddress();
-      }
-      if (mustDuplicateHandle) {
-        // Clean up after ourselves
-        printlnToOutput("closehandle 0x" + Integer.toHexString(handle));
-      }
-      // Now create the real return value
-      long[] retval = new long[X86ThreadContext.NPRGREG];
-      retval[X86ThreadContext.EAX] = winRegs[0];
-      retval[X86ThreadContext.EBX] = winRegs[1];
-      retval[X86ThreadContext.ECX] = winRegs[2];
-      retval[X86ThreadContext.EDX] = winRegs[3];
-      retval[X86ThreadContext.ESI] = winRegs[4];
-      retval[X86ThreadContext.EDI] = winRegs[5];
-      retval[X86ThreadContext.EBP] = winRegs[6];
-      retval[X86ThreadContext.ESP] = winRegs[7];
-      retval[X86ThreadContext.EIP] = winRegs[8];
-      retval[X86ThreadContext.DS]  = winRegs[9];
-      retval[X86ThreadContext.ES]  = winRegs[10];
-      retval[X86ThreadContext.FS]  = winRegs[11];
-      retval[X86ThreadContext.GS]  = winRegs[12];
-      retval[X86ThreadContext.CS]  = winRegs[13];
-      retval[X86ThreadContext.SS]  = winRegs[14];
-      retval[X86ThreadContext.EFL] = winRegs[15];
-      retval[X86ThreadContext.DR0] = winRegs[16];
-      retval[X86ThreadContext.DR1] = winRegs[17];
-      retval[X86ThreadContext.DR2] = winRegs[18];
-      retval[X86ThreadContext.DR3] = winRegs[19];
-      retval[X86ThreadContext.DR6] = winRegs[20];
-      retval[X86ThreadContext.DR7] = winRegs[21];
-      return retval;
-    } catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-  }
-
-  public synchronized void setThreadIntegerRegisterSet(int threadHandleValue,
-                                                       boolean mustDuplicateHandle,
-                                                       long[] context)
-    throws DebuggerException {
-    if (!suspended) {
-      throw new DebuggerException("Process not suspended");
-    }
-
-    try {
-      int handle = threadHandleValue;
-      if (mustDuplicateHandle) {
-        printlnToOutput("duphandle 0x" + Integer.toHexString(threadHandleValue));
-        if (!in.parseBoolean()) {
-          throw new DebuggerException("Error duplicating thread handle 0x" + threadHandleValue);
-        }
-        handle = (int) in.parseAddress(); // Must close to avoid leaks
-      }
-      // Change order of registers to match that of debug server
-      long[] winRegs = new long[context.length];
-      winRegs[0] = context[X86ThreadContext.EAX];
-      winRegs[1] = context[X86ThreadContext.EBX];
-      winRegs[2] = context[X86ThreadContext.ECX];
-      winRegs[3] = context[X86ThreadContext.EDX];
-      winRegs[4] = context[X86ThreadContext.ESI];
-      winRegs[5] = context[X86ThreadContext.EDI];
-      winRegs[6] = context[X86ThreadContext.EBP];
-      winRegs[7] = context[X86ThreadContext.ESP];
-      winRegs[8] = context[X86ThreadContext.EIP];
-      winRegs[9] = context[X86ThreadContext.DS];
-      winRegs[10] = context[X86ThreadContext.ES];
-      winRegs[11] = context[X86ThreadContext.FS];
-      winRegs[12] = context[X86ThreadContext.GS];
-      winRegs[13] = context[X86ThreadContext.CS];
-      winRegs[14] = context[X86ThreadContext.SS];
-      winRegs[15] = context[X86ThreadContext.EFL];
-      winRegs[16] = context[X86ThreadContext.DR0];
-      winRegs[17] = context[X86ThreadContext.DR1];
-      winRegs[18] = context[X86ThreadContext.DR2];
-      winRegs[19] = context[X86ThreadContext.DR3];
-      winRegs[20] = context[X86ThreadContext.DR6];
-      winRegs[21] = context[X86ThreadContext.DR7];
-      StringBuffer cmd = new StringBuffer();
-      cmd.append("setcontext 0x");
-      cmd.append(Integer.toHexString(threadHandleValue));
-      for (int i = 0; i < context.length; i++) {
-        cmd.append(" 0x");
-        cmd.append(Long.toHexString(winRegs[i]));
-      }
-      printlnToOutput(cmd.toString());
-      boolean res = in.parseBoolean();
-      if (mustDuplicateHandle) {
-        printlnToOutput("closehandle 0x" + Integer.toHexString(handle));
-      }
-      if (!res) {
-        String failMessage = "SetThreadContext failed for thread handle 0x" +
-          Integer.toHexString(handle);
-        if (mustDuplicateHandle) {
-          failMessage = failMessage + ", duplicated from thread handle " +
-            Integer.toHexString(threadHandleValue);
-        }
-        throw new DebuggerException(failMessage);
-      }
-    } catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-  }
-
-  /** Fetches the Win32 LDT_ENTRY for the given thread and selector.
-      This data structure allows the conversion of a segment-relative
-      address to a linear virtual address. For example, it allows the
-      expression of operations like "mov eax, fs:[18h]", which fetches
-      the thread information block, allowing access to the thread
-      ID. */
-  public synchronized Win32LDTEntry getThreadSelectorEntry(int threadHandleValue,
-                                                           boolean mustDuplicateHandle,
-                                                           int selector)
-    throws DebuggerException {
-    try {
-      int handle = threadHandleValue;
-      if (mustDuplicateHandle) {
-        printlnToOutput("duphandle 0x" + Integer.toHexString(threadHandleValue));
-        if (!in.parseBoolean()) {
-          throw new DebuggerException("Error duplicating thread handle 0x" + threadHandleValue);
-        }
-        handle = (int) in.parseAddress(); // Must close to avoid leaks
-      }
-      printlnToOutput("selectorentry 0x" + Integer.toHexString(handle) + " " + selector);
-      if (!in.parseBoolean()) {
-        if (mustDuplicateHandle) {
-          printlnToOutput("closehandle 0x" + Integer.toHexString(handle));
-        }
-        throw new DebuggerException("GetThreadContext failed for thread handle 0x" + handle +
-                                    ", duplicated from thread handle " + threadHandleValue);
-      }
-      // Parse result. See
-      // src/os/win32/agent/README-commands.txt for the format.
-      short limitLow = (short) in.parseAddress();
-      short baseLow  = (short) in.parseAddress();
-      byte  baseMid  = (byte)  in.parseAddress();
-      byte  flags1   = (byte)  in.parseAddress();
-      byte  flags2   = (byte)  in.parseAddress();
-      byte  baseHi   = (byte)  in.parseAddress();
-      return new Win32LDTEntry(limitLow, baseLow, baseMid, flags1, flags2, baseHi);
-    } catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-  }
-
-  public synchronized List getThreadList() throws DebuggerException {
-    if (!suspended) {
-      throw new DebuggerException("Process not suspended");
-    }
-
-    try {
-      printlnToOutput("threadlist");
-      List ret = new ArrayList();
-      int numThreads = in.parseInt();
-      for (int i = 0; i < numThreads; i++) {
-        int handle = (int) in.parseAddress();
-        ret.add(new Win32Thread(this, handle));
-      }
-      return ret;
-    } catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-  }
-
-  public synchronized List getLoadObjectList() throws DebuggerException {
-    if (!suspended) {
-      throw new DebuggerException("Process not suspended");
-    }
-
-    try {
-      if (loadObjects == null) {
-        loadObjects  = new ArrayList();
-        nameToDllMap = new HashMap();
-        // Get list of library names and base addresses
-        printlnToOutput("libinfo");
-        int numInfo = in.parseInt();
-
-        for (int i = 0; i < numInfo; i++) {
-          // NOTE: because Win32 is case insensitive, we standardize on
-          // lowercase file names.
-          String  fullPathName = parseString().toLowerCase();
-          Address base         = newAddress(in.parseAddress());
-
-          File   file = new File(fullPathName);
-          long   size = file.length();
-          DLL    dll  = new DLL(this, fullPathName, size, base);
-          String name = file.getName();
-          nameToDllMap.put(name, dll);
-          loadObjects.add(dll);
-        }
-      }
-    } catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-
-    return loadObjects;
-  }
-
-  //----------------------------------------------------------------------
-  // Process control access
-  //
-
-  public synchronized void writeBytesToProcess(long startAddress, long numBytes, byte[] data)
-    throws UnmappedAddressException, DebuggerException {
-    try {
-      printToOutput("poke 0x" + Long.toHexString(startAddress) +
-                    " |");
-      writeIntToOutput((int) numBytes);
-      writeToOutput(data, 0, (int) numBytes);
-      printlnToOutput("");
-      if (!in.parseBoolean()) {
-        throw new UnmappedAddressException(startAddress);
-      }
-    } catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-  }
-
-  public synchronized void suspend() throws DebuggerException {
-    try {
-      if (suspended) {
-        throw new DebuggerException("Process already suspended");
-      }
-      printlnToOutput("suspend");
-      suspended = true;
-      enableCache();
-      reresolveLoadObjects();
-    } catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-  }
-
-  public synchronized void resume() throws DebuggerException {
-    try {
-      if (!suspended) {
-        throw new DebuggerException("Process not suspended");
-      }
-      disableCache();
-      printlnToOutput("resume");
-      suspended = false;
-    } catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-  }
-
-  public synchronized boolean isSuspended() throws DebuggerException {
-    return suspended;
-  }
-
-  public synchronized void setBreakpoint(Address addr) throws DebuggerException {
-    if (!suspended) {
-      throw new DebuggerException("Process not suspended");
-    }
-
-    long addrVal = getAddressValue(addr);
-    Long where = new Long(addrVal);
-    if (breakpoints.get(where) != null) {
-      throw new DebuggerException("Breakpoint already set at " + addr);
-    }
-    Byte what = new Byte(readBytes(addrVal, 1)[0]);
-    // Now put 0xCC (int 3) at the target address, fail if can not
-    writeBytesToProcess(addrVal, 1, new byte[] { (byte) 0xCC });
-    // OK, the breakpoint is set.
-    breakpoints.put(where, what);
-  }
-
-  public synchronized void clearBreakpoint(Address addr) throws DebuggerException {
-    if (!suspended) {
-      throw new DebuggerException("Process not suspended");
-    }
-
-    long addrVal = getAddressValue(addr);
-    Long where = new Long(addrVal);
-    Byte what = (Byte) breakpoints.get(where);
-    if (what == null) {
-      throw new DebuggerException("Breakpoint not set at " + addr);
-    }
-    // Put original data back at address
-    writeBytesToProcess(addrVal, 1, new byte[] { what.byteValue() });
-    // OK, breakpoint is cleared
-    breakpoints.remove(where);
-  }
-
-  public synchronized boolean isBreakpointSet(Address addr) throws DebuggerException {
-    return (breakpoints.get(new Long(getAddressValue(addr))) != null);
-  }
-
-  // Following constants taken from winnt.h
-  private static final int EXCEPTION_DEBUG_EVENT  = 1;
-  private static final int LOAD_DLL_DEBUG_EVENT   = 6;
-  private static final int UNLOAD_DLL_DEBUG_EVENT = 7;
-  private static final int EXCEPTION_ACCESS_VIOLATION = 0xC0000005;
-  private static final int EXCEPTION_BREAKPOINT       = 0x80000003;
-  private static final int EXCEPTION_SINGLE_STEP      = 0x80000004;
-
-  public synchronized DebugEvent debugEventPoll() throws DebuggerException {
-    if (curDebugEvent != null) {
-      return curDebugEvent;
-    }
-
-    try {
-      printlnToOutput("pollevent");
-      if (!in.parseBoolean()) {
-        return null;
-      }
-      // Otherwise, got a debug event. Need to figure out what kind it is.
-      int handle = (int) in.parseAddress();
-      ThreadProxy thread = new Win32Thread(this, handle);
-      int code = in.parseInt();
-      DebugEvent ev = null;
-      switch (code) {
-      case LOAD_DLL_DEBUG_EVENT: {
-        Address addr = newAddress(in.parseAddress());
-        ev = BasicDebugEvent.newLoadObjectLoadEvent(thread, addr);
-        break;
-      }
-
-      case UNLOAD_DLL_DEBUG_EVENT: {
-        Address addr = newAddress(in.parseAddress());
-        ev = BasicDebugEvent.newLoadObjectUnloadEvent(thread, addr);
-        break;
-      }
-
-      case EXCEPTION_DEBUG_EVENT: {
-        int exceptionCode = in.parseInt();
-        Address pc = newAddress(in.parseAddress());
-        switch (exceptionCode) {
-        case EXCEPTION_ACCESS_VIOLATION:
-          boolean wasWrite = in.parseBoolean();
-          Address addr = newAddress(in.parseAddress());
-          ev = BasicDebugEvent.newAccessViolationEvent(thread, pc, wasWrite, addr);
-          break;
-
-        case EXCEPTION_BREAKPOINT:
-          ev = BasicDebugEvent.newBreakpointEvent(thread, pc);
-          break;
-
-        case EXCEPTION_SINGLE_STEP:
-          ev = BasicDebugEvent.newSingleStepEvent(thread, pc);
-          break;
-
-        default:
-          ev = BasicDebugEvent.newUnknownEvent(thread,
-                                               "Exception 0x" + Integer.toHexString(exceptionCode) +
-                                               " at PC " + pc);
-          break;
-        }
-        break;
-      }
-
-      default:
-        ev = BasicDebugEvent.newUnknownEvent(thread,
-                                             "Debug event " + code + " occurred");
-        break;
-      }
-      if (Assert.ASSERTS_ENABLED) {
-        Assert.that(ev != null, "Must have created event");
-      }
-      curDebugEvent = ev;
-    } catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-
-    return curDebugEvent;
-  }
-
-  public synchronized void debugEventContinue() throws DebuggerException {
-    if (curDebugEvent == null) {
-      throw new DebuggerException("No debug event pending");
-    }
-
-    try {
-      ///////////////////////////////////////////////////////////////////
-      //                                                               //
-      // FIXME: this **must** be modified to handle breakpoint events
-      // properly. Must temporarily remove the breakpoint and enable
-      // single-stepping mode (hiding those single-step events from
-      // the user unless they have been requested; currently there is
-      // no way to request single-step events; and it isn't clear how
-      // to enable them or how the hardware and/or OS typically
-      // supports them, i.e., are they on a per-process or per-thread
-      // level?) until the process steps past the breakpoint, then put
-      // the breakpoint back.
-      //                                                               //
-      ///////////////////////////////////////////////////////////////////
-
-      DebugEvent.Type t = curDebugEvent.getType();
-      boolean shouldPassOn = true;
-      if (t == DebugEvent.Type.BREAKPOINT) {
-        // FIXME: correct algorithm appears to be as follows:
-        //
-        // 1. Check to see whether we know about this breakpoint. If
-        // not, it's requested by the user's program and we should
-        // ignore it (not pass it on to the program).
-        //
-        // 2. Replace the original opcode.
-        //
-        // 3. Set single-stepping mode in the debug registers.
-        //
-        // 4. Back up the PC.
-        //
-        // 5. In debugEventPoll(), watch for a single-step event on
-        // this thread. When we get it, put the breakpoint back. Only
-        // deliver that single-step event if the user has requested
-        // single-step events (FIXME: must figure out whether they are
-        // per-thread or per-process, and also expose a way to turn
-        // them on.)
-
-        // To make breakpoints work for now, we will just back up the
-        // PC, which we have to do in order to not disrupt the program
-        // execution in case the user decides to disable the breakpoint.
-
-        if (breakpoints.get(new Long(getAddressValue(curDebugEvent.getPC()))) != null) {
-          System.err.println("Backing up PC due to breakpoint");
-          X86ThreadContext ctx = (X86ThreadContext) curDebugEvent.getThread().getContext();
-          ctx.setRegister(X86ThreadContext.EIP, ctx.getRegister(X86ThreadContext.EIP) - 1);
-          curDebugEvent.getThread().setContext(ctx);
-        } else {
-          System.err.println("Skipping back up of PC since I didn't know about this breakpoint");
-          System.err.println("Known breakpoints:");
-          for (Iterator iter = breakpoints.keySet().iterator(); iter.hasNext(); ) {
-            System.err.println("  0x" + Long.toHexString(((Long) iter.next()).longValue()));
-          }
-        }
-        shouldPassOn = false;
-      } else if (t == DebugEvent.Type.SINGLE_STEP) {
-        shouldPassOn = false;
-      }
-      // Other kinds of debug events are either ignored if passed on
-      // or probably should be passed on so the program exits
-      // FIXME: generate process exiting events (should be easy)
-
-      int val = (shouldPassOn ? 1 : 0);
-      printlnToOutput("continueevent " + val);
-      if (!in.parseBoolean()) {
-        throw new DebuggerException("Unknown error while attempting to continue past debug event");
-      }
-      curDebugEvent = null;
-    } catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-  }
-
-  //--------------------------------------------------------------------------------
-  // Address access
-  //
-
-  /** From the Debugger interface */
-  public long getAddressValue(Address addr) {
-    if (addr == null) return 0;
-    return ((Win32Address) addr).getValue();
-  }
-
-  /** From the Win32Debugger interface */
-  public Address newAddress(long value) {
-    if (value == 0) return null;
-    return new Win32Address(this, value);
-  }
-
-  //--------------------------------------------------------------------------------
-  // Internals only below this point
-  //
-
-  private String parseString() throws IOException {
-    int charSize = in.parseInt();
-    int numChars = in.parseInt();
-    in.skipByte();
-    String str;
-    if (charSize == 1) {
-      str = in.readByteString(numChars);
-    } else {
-      str = in.readCharString(numChars);
-    }
-    return str;
-  }
-
-  /** Looks up an address in the remote process's address space.
-      Returns 0 if symbol not found or upon error. Package private to
-      allow Win32DebuggerRemoteIntfImpl access. NOTE that this returns
-      a long instead of an Address because we do not want to serialize
-      Addresses. */
-  synchronized long lookupInProcess(String objectName, String symbol) {
-    // NOTE: this assumes that process is suspended (which is probably
-    // necessary assumption given that DLLs can be loaded/unloaded as
-    // process runs). Should update documentation.
-    if (nameToDllMap == null) {
-      getLoadObjectList();
-    }
-    DLL dll = (DLL) nameToDllMap.get(objectName);
-    // The DLL can be null because we use this to search through known
-    // DLLs in HotSpotTypeDataBase (for example)
-    if (dll != null) {
-      Win32Address addr = (Win32Address) dll.lookupSymbol(symbol);
-      if (addr != null) {
-        return addr.getValue();
-      }
-    }
-    return 0;
-  }
-
-  /** This reads bytes from the remote process. */
-  public synchronized ReadResult readBytesFromProcess(long address, long numBytes)
-    throws UnmappedAddressException, DebuggerException {
-    try {
-      String cmd = "peek " + utils.addressValueToString(address) + " " + numBytes;
-      printlnToOutput(cmd);
-      while (in.readByte() != 'B') {
-      }
-      byte res = in.readByte();
-      if (res == 0) {
-        System.err.println("Failing command: " + cmd);
-        throw new DebuggerException("Read of remote process address space failed");
-      }
-      // NOTE: must read ALL of the data regardless of whether we need
-      // to throw an UnmappedAddressException. Otherwise will corrupt
-      // the input stream each time we have a failure. Not good. Do
-      // not want to risk "flushing" the input stream in case a huge
-      // read has a hangup in the middle and we leave data on the
-      // stream.
-      byte[] buf = new byte[(int) numBytes];
-      boolean bailOut = false;
-      long failureAddress = 0;
-      while (numBytes > 0) {
-        long len = in.readUnsignedInt();
-        boolean isMapped = ((in.readByte() == 0) ? false : true);
-        if (!isMapped) {
-          if (!bailOut) {
-            bailOut = true;
-            failureAddress = address;
-          }
-        } else {
-          // This won't work if we have unmapped regions, but if we do
-          // then we're going to throw an exception anyway
-
-          // NOTE: there is a factor of 20 speed difference between
-          // these two ways of doing this read.
-          in.readBytes(buf, 0, (int) len);
-        }
-
-        // Do NOT do this:
-        //        for (int i = 0; i < (int) len; i++) {
-        //          buf[i] = in.readByte();
-        //        }
-
-        numBytes -= len;
-        address += len;
-      }
-      if (Assert.ASSERTS_ENABLED) {
-        Assert.that(numBytes == 0, "Bug in debug server's implementation of peek");
-      }
-      if (bailOut) {
-        return new ReadResult(failureAddress);
-      }
-      return new ReadResult(buf);
-    }
-    catch (IOException e) {
-      throw new DebuggerException(e);
-    }
-  }
-
-  /** Convenience routines */
-  private void printlnToOutput(String s) throws IOException {
-    out.println(s);
-    if (out.checkError()) {
-      throw new IOException("Error occurred while writing to debug server");
-    }
-  }
-
-  private void printToOutput(String s) throws IOException {
-    out.print(s);
-    if (out.checkError()) {
-      throw new IOException("Error occurred while writing to debug server");
-    }
-  }
-
-  private void writeIntToOutput(int val) throws IOException {
-    rawOut.writeInt(val);
-    rawOut.flush();
-  }
-
-  private void writeToOutput(byte[] buf, int off, int len) throws IOException {
-    rawOut.write(buf, off, len);
-    rawOut.flush();
-  }
-
-  /** Connects to the debug server, setting up out and in streams. */
-  private void connectToDebugServer() throws IOException {
-    // Try for a short period of time to connect to debug server; time out
-    // with failure if didn't succeed
-    debuggerSocket = null;
-    long endTime = System.currentTimeMillis() + SHORT_TIMEOUT;
-
-    while ((debuggerSocket == null) && (System.currentTimeMillis() < endTime)) {
-      try {
-        // FIXME: this does not work if we are on a DHCP machine which
-        // did not get an IP address this session. It appears to use
-        // an old cached address and the connection does not actually
-        // succeed. Must file a bug.
-        // debuggerSocket = new Socket(InetAddress.getLocalHost(), PORT);
-        debuggerSocket = new Socket(InetAddress.getByName("127.0.0.1"), PORT);
-        debuggerSocket.setTcpNoDelay(true);
-      }
-      catch (IOException e) {
-        // Swallow IO exceptions while attempting connection
-        debuggerSocket = null;
-        try {
-          // Don't swamp the CPU
-          Thread.sleep(750);
-        }
-        catch (InterruptedException ex) {
-        }
-      }
-    }
-
-    if (debuggerSocket == null) {
-      // Failed to connect because of timeout
-      throw new DebuggerException("Timed out while attempting to connect to debug server (please start SwDbgSrv.exe)");
-    }
-
-    out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(debuggerSocket.getOutputStream(), "US-ASCII")), true);
-    rawOut = new DataOutputStream(new BufferedOutputStream(debuggerSocket.getOutputStream()));
-    in = new InputLexer(new BufferedInputStream(debuggerSocket.getInputStream()));
-  }
-
-  private DLL findDLLByName(String fullPathName) {
-    for (Iterator iter = loadObjects.iterator(); iter.hasNext(); ) {
-      DLL dll = (DLL) iter.next();
-      if (dll.getName().equals(fullPathName)) {
-        return dll;
-      }
-    }
-    return null;
-  }
-
-  private void reresolveLoadObjects() throws DebuggerException {
-    try {
-      // It is too expensive to throw away the loadobject list every
-      // time the process is suspended, largely because of debug
-      // information re-parsing. When we suspend the target process we
-      // instead fetch the list of loaded libraries in the target and
-      // see whether any loadobject needs to be thrown away (because it
-      // was unloaded) or invalidated (because it was unloaded and
-      // reloaded at a different target address). Note that we don't
-      // properly handle the case of a loaded DLL being unloaded,
-      // recompiled, and reloaded. We could handle this by keeping a
-      // time stamp.
-
-      if (loadObjects == null) {
-        return;
-      }
-
-      // Need to create new list since have to figure out which ones
-      // were unloaded
-      List newLoadObjects = new ArrayList();
-
-    // Get list of library names and base addresses
-      printlnToOutput("libinfo");
-      int numInfo = in.parseInt();
-
-      for (int i = 0; i < numInfo; i++) {
-        // NOTE: because Win32 is case insensitive, we standardize on
-        // lowercase file names.
-        String  fullPathName = parseString().toLowerCase();
-        Address base         = newAddress(in.parseAddress());
-
-        // Look for full path name in DLL list
-        DLL dll = findDLLByName(fullPathName);
-        boolean mustLoad = true;
-        if (dll != null) {
-          loadObjects.remove(dll);
-
-          // See whether base addresses match; otherwise, need to reload
-          if (AddressOps.equal(base, dll.getBase())) {
-            mustLoad = false;
-          }
-        }
-
-        if (mustLoad) {
-          // Create new DLL
-          File   file = new File(fullPathName);
-          long   size = file.length();
-          String name = file.getName();
-          dll  = new DLL(this, fullPathName, size, base);
-          nameToDllMap.put(name, dll);
-        }
-        newLoadObjects.add(dll);
-      }
-
-      // All remaining entries in loadObjects have to be removed from
-      // the nameToDllMap
-      for (Iterator dllIter = loadObjects.iterator(); dllIter.hasNext(); ) {
-        DLL dll = (DLL) dllIter.next();
-        for (Iterator iter = nameToDllMap.keySet().iterator(); iter.hasNext(); ) {
-          String name = (String) iter.next();
-          if (nameToDllMap.get(name) == dll) {
-            nameToDllMap.remove(name);
-            break;
-          }
-        }
-      }
-
-      loadObjects = newLoadObjects;
-    } catch (IOException e) {
-      loadObjects = null;
-      nameToDllMap = null;
-      throw new DebuggerException(e);
-    }
-  }
-}