1 /*
   2  * Copyright 2000-2004 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  *  
  23  */
  24 
  25 package sun.jvm.hotspot.debugger.win32;
  26 
  27 import java.io.*;
  28 import java.net.*;
  29 import java.util.*;
  30 import sun.jvm.hotspot.debugger.*;
  31 import sun.jvm.hotspot.debugger.x86.*;
  32 import sun.jvm.hotspot.debugger.win32.coff.*;
  33 import sun.jvm.hotspot.debugger.cdbg.*;
  34 import sun.jvm.hotspot.debugger.cdbg.basic.BasicDebugEvent;
  35 import sun.jvm.hotspot.utilities.*;
  36 import sun.jvm.hotspot.utilities.memo.*;
  37 
  38 /** <P> An implementation of the JVMDebugger interface which talks to
  39     the Free Windows Debug Server (FwDbgSrv) over a socket to
  40     implement attach/detach and read from process memory. All DLL and
  41     symbol table management is done in Java. </P>
  42 
  43     <P> <B>NOTE</B> that since we have the notion of fetching "Java
  44     primitive types" from the remote process (which might have
  45     different sizes than we expect) we have a bootstrapping
  46     problem. We need to know the sizes of these types before we can
  47     fetch them. The current implementation solves this problem by
  48     requiring that it be configured with these type sizes before they
  49     can be fetched. The readJ(Type) routines here will throw a
  50     RuntimeException if they are called before the debugger is
  51     configured with the Java primitive type sizes. </P> */
  52 
  53 public class Win32DebuggerLocal extends DebuggerBase implements Win32Debugger {
  54   private Socket debuggerSocket;
  55   private boolean attached;
  56   // FIXME: update when core files supported
  57   private long pid;
  58   // Communication with debug server
  59   private PrintWriter out;
  60   private DataOutputStream rawOut;
  61   private InputLexer in;
  62   private static final int PORT = 27000;
  63   private PageCache cache;
  64   private static final long SHORT_TIMEOUT = 2000;
  65   private static final long LONG_TIMEOUT = 20000;
  66 
  67   // Symbol lookup support
  68   // This is a map of library names to DLLs
  69   private Map nameToDllMap;
  70 
  71   // C/C++ debugging support
  72   private List/*<LoadObject>*/ loadObjects;
  73   private CDebugger cdbg;
  74 
  75   // ProcessControl support
  76   private boolean suspended;
  77   // Maps Long objects (addresses) to Byte objects (original instructions)
  78   // (Longs used instead of Addresses to properly represent breakpoints at 0x0 if needed)
  79   private Map     breakpoints;
  80   // Current debug event, if any
  81   private DebugEvent curDebugEvent;
  82 
  83   //--------------------------------------------------------------------------------
  84   // Implementation of Debugger interface
  85   //
  86 
  87   /** <P> machDesc may not be null. </P>
  88 
  89       <P> useCache should be set to true if debugging is being done
  90       locally, and to false if the debugger is being created for the
  91       purpose of supporting remote debugging. </P> */
  92   public Win32DebuggerLocal(MachineDescription machDesc,
  93                             boolean useCache) throws DebuggerException {
  94     this.machDesc = machDesc;
  95     utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian());
  96     if (useCache) {
  97       // Cache portion of the remote process's address space.
  98       // Fetching data over the socket connection to dbx is slow.
  99       // Might be faster if we were using a binary protocol to talk to
 100       // dbx, but would have to test. For now, this cache works best
 101       // if it covers the entire heap of the remote process. FIXME: at
 102       // least should make this tunable from the outside, i.e., via
 103       // the UI. This is a cache of 4096 4K pages, or 16 MB. The page
 104       // size must be adjusted to be the hardware's page size.
 105       // (FIXME: should pick this up from the debugger.)
 106       initCache(4096, parseCacheNumPagesProperty(4096));
 107     }
 108     // FIXME: add instantiation of thread factory
 109 
 110     try {
 111       connectToDebugServer();
 112     } catch (IOException e) {
 113       throw new DebuggerException(e);
 114     }
 115   }
 116 
 117   /** From the Debugger interface via JVMDebugger */
 118   public boolean hasProcessList() throws DebuggerException {
 119     return true;
 120   }
 121 
 122   /** From the Debugger interface via JVMDebugger */
 123   public List getProcessList() throws DebuggerException {
 124     List processes = new ArrayList();
 125 
 126     try {
 127       printlnToOutput("proclist");
 128       int num = in.parseInt();
 129       for (int i = 0; i < num; i++) {
 130         int pid = in.parseInt();
 131         String name = parseString();
 132         // NOTE: Win32 hack
 133         if (name.equals("")) {
 134           name = "System Idle Process";
 135         }
 136         processes.add(new ProcessInfo(name, pid));
 137       }
 138       return processes;
 139     }
 140     catch (IOException e) {
 141       throw new DebuggerException(e);
 142     }
 143   }
 144 
 145   /** From the Debugger interface via JVMDebugger */
 146   public synchronized void attach(int processID) throws DebuggerException {
 147     if (attached) {
 148       // FIXME: update when core files supported
 149       throw new DebuggerException("Already attached to process " + pid);
 150     }
 151 
 152     try {
 153       printlnToOutput("attach " + processID);
 154       if (!in.parseBoolean()) {
 155         throw new DebuggerException("Error attaching to process, or no such process");
 156       }
 157 
 158       attached = true;
 159       pid = processID;
 160       suspended = true;
 161       breakpoints = new HashMap();
 162       curDebugEvent = null;
 163       nameToDllMap = null;
 164       loadObjects = null;
 165     }
 166     catch (IOException e) {
 167         throw new DebuggerException(e);
 168     }
 169   }
 170 
 171   /** From the Debugger interface via JVMDebugger */
 172   public synchronized void attach(String executableName, String coreFileName) throws DebuggerException {
 173     throw new DebuggerException("Core files not yet supported on Win32");
 174   }
 175 
 176   /** From the Debugger interface via JVMDebugger */
 177   public synchronized boolean detach() {
 178     if (!attached) {
 179       return false;
 180     }
 181 
 182     attached = false;
 183     suspended = false;
 184     breakpoints = null;
 185 
 186     // Close all open DLLs
 187     if (nameToDllMap != null) {
 188       for (Iterator iter = nameToDllMap.values().iterator(); iter.hasNext(); ) {
 189         DLL dll = (DLL) iter.next();
 190         dll.close();
 191       }
 192       nameToDllMap = null;
 193       loadObjects = null;
 194     }
 195 
 196     cdbg = null;
 197     clearCache();
 198 
 199     try {
 200       printlnToOutput("detach");
 201       return in.parseBoolean();
 202     }
 203     catch (IOException e) {
 204       throw new DebuggerException(e);
 205     }
 206   }
 207 
 208   /** From the Debugger interface via JVMDebugger */
 209   public Address parseAddress(String addressString) throws NumberFormatException {
 210     return newAddress(utils.scanAddress(addressString));
 211   }
 212 
 213   /** From the Debugger interface via JVMDebugger */
 214   public String getOS() {
 215     return PlatformInfo.getOS();
 216   }
 217 
 218   /** From the Debugger interface via JVMDebugger */
 219   public String getCPU() {
 220     return PlatformInfo.getCPU();
 221   }
 222 
 223   public boolean hasConsole() throws DebuggerException {
 224     return false;
 225   }
 226 
 227   public String consoleExecuteCommand(String cmd) throws DebuggerException {
 228     throw new DebuggerException("No debugger console available on Win32");
 229   }
 230 
 231   public String getConsolePrompt() throws DebuggerException {
 232     return null;
 233   }
 234 
 235   public CDebugger getCDebugger() throws DebuggerException {
 236     if (cdbg == null) {
 237       cdbg = new Win32CDebugger(this);
 238     }
 239     return cdbg;
 240   }
 241 
 242   /** From the SymbolLookup interface via Debugger and JVMDebugger */
 243   public synchronized Address lookup(String objectName, String symbol) {
 244     if (!attached) {
 245       return null;
 246     }
 247     return newAddress(lookupInProcess(objectName, symbol));
 248   }
 249 
 250   /** From the SymbolLookup interface via Debugger and JVMDebugger */
 251   public synchronized OopHandle lookupOop(String objectName, String symbol) {
 252     Address addr = lookup(objectName, symbol);
 253     if (addr == null) {
 254       return null;
 255     }
 256     return addr.addOffsetToAsOopHandle(0);
 257   }
 258 
 259   /** From the Debugger interface */
 260   public MachineDescription getMachineDescription() {
 261     return machDesc;
 262   }
 263 
 264   //--------------------------------------------------------------------------------
 265   // Implementation of ThreadAccess interface
 266   //
 267 
 268   /** From the ThreadAccess interface via Debugger and JVMDebugger */
 269   public ThreadProxy getThreadForIdentifierAddress(Address addr) {
 270     return new Win32Thread(this, addr);
 271   }
 272 
 273   public ThreadProxy getThreadForThreadId(long handle) {
 274     return new Win32Thread(this, handle);
 275   }
 276 
 277   //----------------------------------------------------------------------
 278   // Overridden from DebuggerBase because we need to relax alignment
 279   // constraints on x86
 280 
 281   public long readJLong(long address)
 282     throws UnmappedAddressException, UnalignedAddressException {
 283     checkJavaConfigured();
 284     // FIXME: allow this to be configurable. Undesirable to add a
 285     // dependency on the runtime package here, though, since this
 286     // package should be strictly underneath it.
 287     //    utils.checkAlignment(address, jlongSize);
 288     utils.checkAlignment(address, jintSize);
 289     byte[] data = readBytes(address, jlongSize);
 290     return utils.dataToJLong(data, jlongSize);
 291   }  
 292 
 293   //--------------------------------------------------------------------------------
 294   // Internal routines (for implementation of Win32Address).
 295   // These must not be called until the MachineDescription has been set up.
 296   //
 297 
 298   /** From the Win32Debugger interface */
 299   public String addressValueToString(long address) {
 300     return utils.addressValueToString(address);
 301   }
 302 
 303   /** From the Win32Debugger interface */
 304   public Win32Address readAddress(long address)
 305     throws UnmappedAddressException, UnalignedAddressException {
 306     return (Win32Address) newAddress(readAddressValue(address));
 307   }
 308 
 309   /** From the Win32Debugger interface */
 310   public Win32OopHandle readOopHandle(long address)
 311     throws UnmappedAddressException, UnalignedAddressException, NotInHeapException {
 312     long value = readAddressValue(address);
 313     return (value == 0 ? null : new Win32OopHandle(this, value));
 314   }
 315 
 316   /** From the Win32Debugger interface */
 317   public void writeAddress(long address, Win32Address value) {
 318     writeAddressValue(address, getAddressValue(value));
 319   }
 320 
 321   /** From the Win32Debugger interface */
 322   public void writeOopHandle(long address, Win32OopHandle value) {
 323     writeAddressValue(address, getAddressValue(value));
 324   }
 325 
 326   //--------------------------------------------------------------------------------
 327   // Thread context access
 328   //
 329 
 330   public synchronized long[] getThreadIntegerRegisterSet(int threadHandleValue,
 331                                                          boolean mustDuplicateHandle)
 332     throws DebuggerException {
 333     if (!suspended) {
 334       throw new DebuggerException("Process not suspended");
 335     }
 336 
 337     try {
 338       int handle = threadHandleValue;
 339       if (mustDuplicateHandle) {
 340         printlnToOutput("duphandle 0x" + Integer.toHexString(threadHandleValue));
 341         if (!in.parseBoolean()) {
 342           throw new DebuggerException("Error duplicating thread handle 0x" + threadHandleValue);
 343         } 
 344         handle = (int) in.parseAddress(); // Must close to avoid leaks
 345       }
 346       printlnToOutput("getcontext 0x" + Integer.toHexString(handle));
 347       if (!in.parseBoolean()) {
 348         if (mustDuplicateHandle) {
 349           printlnToOutput("closehandle 0x" + Integer.toHexString(handle));
 350         }
 351         String failMessage = "GetThreadContext failed for thread handle 0x" +
 352                              Integer.toHexString(handle);
 353         if (mustDuplicateHandle) {
 354           failMessage = failMessage + ", duplicated from thread handle " +
 355                         Integer.toHexString(threadHandleValue);
 356         }
 357         throw new DebuggerException(failMessage);
 358       }
 359       // Otherwise, parse all registers. See
 360       // src/os/win32/agent/README-commands.txt for the format.
 361       // Note the array we have to return has to match that specified by
 362       // X86ThreadContext.java.
 363       int numRegs = 22;
 364       long[] winRegs = new long[numRegs];
 365       for (int i = 0; i < numRegs; i++) {
 366         winRegs[i] = in.parseAddress();
 367       }
 368       if (mustDuplicateHandle) {
 369         // Clean up after ourselves
 370         printlnToOutput("closehandle 0x" + Integer.toHexString(handle));
 371       }
 372       // Now create the real return value
 373       long[] retval = new long[X86ThreadContext.NPRGREG];
 374       retval[X86ThreadContext.EAX] = winRegs[0];
 375       retval[X86ThreadContext.EBX] = winRegs[1];
 376       retval[X86ThreadContext.ECX] = winRegs[2];
 377       retval[X86ThreadContext.EDX] = winRegs[3];
 378       retval[X86ThreadContext.ESI] = winRegs[4];
 379       retval[X86ThreadContext.EDI] = winRegs[5];
 380       retval[X86ThreadContext.EBP] = winRegs[6];
 381       retval[X86ThreadContext.ESP] = winRegs[7];
 382       retval[X86ThreadContext.EIP] = winRegs[8];
 383       retval[X86ThreadContext.DS]  = winRegs[9];
 384       retval[X86ThreadContext.ES]  = winRegs[10];
 385       retval[X86ThreadContext.FS]  = winRegs[11];
 386       retval[X86ThreadContext.GS]  = winRegs[12];
 387       retval[X86ThreadContext.CS]  = winRegs[13];
 388       retval[X86ThreadContext.SS]  = winRegs[14];
 389       retval[X86ThreadContext.EFL] = winRegs[15];
 390       retval[X86ThreadContext.DR0] = winRegs[16];
 391       retval[X86ThreadContext.DR1] = winRegs[17];
 392       retval[X86ThreadContext.DR2] = winRegs[18];
 393       retval[X86ThreadContext.DR3] = winRegs[19];
 394       retval[X86ThreadContext.DR6] = winRegs[20];
 395       retval[X86ThreadContext.DR7] = winRegs[21];
 396       return retval;
 397     } catch (IOException e) {
 398       throw new DebuggerException(e);
 399     }
 400   }
 401 
 402   public synchronized void setThreadIntegerRegisterSet(int threadHandleValue,
 403                                                        boolean mustDuplicateHandle,
 404                                                        long[] context)
 405     throws DebuggerException {
 406     if (!suspended) {
 407       throw new DebuggerException("Process not suspended");
 408     }
 409 
 410     try {
 411       int handle = threadHandleValue;
 412       if (mustDuplicateHandle) {
 413         printlnToOutput("duphandle 0x" + Integer.toHexString(threadHandleValue));
 414         if (!in.parseBoolean()) {
 415           throw new DebuggerException("Error duplicating thread handle 0x" + threadHandleValue);
 416         } 
 417         handle = (int) in.parseAddress(); // Must close to avoid leaks
 418       }
 419       // Change order of registers to match that of debug server
 420       long[] winRegs = new long[context.length];
 421       winRegs[0] = context[X86ThreadContext.EAX];
 422       winRegs[1] = context[X86ThreadContext.EBX];
 423       winRegs[2] = context[X86ThreadContext.ECX];
 424       winRegs[3] = context[X86ThreadContext.EDX];
 425       winRegs[4] = context[X86ThreadContext.ESI];
 426       winRegs[5] = context[X86ThreadContext.EDI];
 427       winRegs[6] = context[X86ThreadContext.EBP];
 428       winRegs[7] = context[X86ThreadContext.ESP];
 429       winRegs[8] = context[X86ThreadContext.EIP];
 430       winRegs[9] = context[X86ThreadContext.DS];
 431       winRegs[10] = context[X86ThreadContext.ES];
 432       winRegs[11] = context[X86ThreadContext.FS];
 433       winRegs[12] = context[X86ThreadContext.GS];
 434       winRegs[13] = context[X86ThreadContext.CS];
 435       winRegs[14] = context[X86ThreadContext.SS];
 436       winRegs[15] = context[X86ThreadContext.EFL];
 437       winRegs[16] = context[X86ThreadContext.DR0];
 438       winRegs[17] = context[X86ThreadContext.DR1];
 439       winRegs[18] = context[X86ThreadContext.DR2];
 440       winRegs[19] = context[X86ThreadContext.DR3];
 441       winRegs[20] = context[X86ThreadContext.DR6];
 442       winRegs[21] = context[X86ThreadContext.DR7];
 443       StringBuffer cmd = new StringBuffer();
 444       cmd.append("setcontext 0x");
 445       cmd.append(Integer.toHexString(threadHandleValue));
 446       for (int i = 0; i < context.length; i++) {
 447         cmd.append(" 0x");
 448         cmd.append(Long.toHexString(winRegs[i]));
 449       }
 450       printlnToOutput(cmd.toString());
 451       boolean res = in.parseBoolean();
 452       if (mustDuplicateHandle) {
 453         printlnToOutput("closehandle 0x" + Integer.toHexString(handle));
 454       }
 455       if (!res) {
 456         String failMessage = "SetThreadContext failed for thread handle 0x" +
 457           Integer.toHexString(handle);
 458         if (mustDuplicateHandle) {
 459           failMessage = failMessage + ", duplicated from thread handle " +
 460             Integer.toHexString(threadHandleValue);
 461         }
 462         throw new DebuggerException(failMessage);
 463       }
 464     } catch (IOException e) {
 465       throw new DebuggerException(e);
 466     }
 467   }
 468 
 469   /** Fetches the Win32 LDT_ENTRY for the given thread and selector.
 470       This data structure allows the conversion of a segment-relative
 471       address to a linear virtual address. For example, it allows the
 472       expression of operations like "mov eax, fs:[18h]", which fetches
 473       the thread information block, allowing access to the thread
 474       ID. */
 475   public synchronized Win32LDTEntry getThreadSelectorEntry(int threadHandleValue,
 476                                                            boolean mustDuplicateHandle,
 477                                                            int selector)
 478     throws DebuggerException {
 479     try {
 480       int handle = threadHandleValue;
 481       if (mustDuplicateHandle) {
 482         printlnToOutput("duphandle 0x" + Integer.toHexString(threadHandleValue));
 483         if (!in.parseBoolean()) {
 484           throw new DebuggerException("Error duplicating thread handle 0x" + threadHandleValue);
 485         } 
 486         handle = (int) in.parseAddress(); // Must close to avoid leaks
 487       }
 488       printlnToOutput("selectorentry 0x" + Integer.toHexString(handle) + " " + selector);
 489       if (!in.parseBoolean()) {
 490         if (mustDuplicateHandle) {
 491           printlnToOutput("closehandle 0x" + Integer.toHexString(handle));
 492         }
 493         throw new DebuggerException("GetThreadContext failed for thread handle 0x" + handle +
 494                                     ", duplicated from thread handle " + threadHandleValue);
 495       }
 496       // Parse result. See
 497       // src/os/win32/agent/README-commands.txt for the format.
 498       short limitLow = (short) in.parseAddress();
 499       short baseLow  = (short) in.parseAddress();
 500       byte  baseMid  = (byte)  in.parseAddress();
 501       byte  flags1   = (byte)  in.parseAddress();
 502       byte  flags2   = (byte)  in.parseAddress();
 503       byte  baseHi   = (byte)  in.parseAddress();
 504       return new Win32LDTEntry(limitLow, baseLow, baseMid, flags1, flags2, baseHi);
 505     } catch (IOException e) {
 506       throw new DebuggerException(e);
 507     }
 508   }
 509 
 510   public synchronized List getThreadList() throws DebuggerException {
 511     if (!suspended) {
 512       throw new DebuggerException("Process not suspended");
 513     }
 514 
 515     try {
 516       printlnToOutput("threadlist");
 517       List ret = new ArrayList();
 518       int numThreads = in.parseInt();
 519       for (int i = 0; i < numThreads; i++) {
 520         int handle = (int) in.parseAddress();
 521         ret.add(new Win32Thread(this, handle));
 522       }
 523       return ret;
 524     } catch (IOException e) {
 525       throw new DebuggerException(e);
 526     }
 527   }
 528 
 529   public synchronized List getLoadObjectList() throws DebuggerException {
 530     if (!suspended) {
 531       throw new DebuggerException("Process not suspended");
 532     }
 533 
 534     try {
 535       if (loadObjects == null) {
 536         loadObjects  = new ArrayList();
 537         nameToDllMap = new HashMap();
 538         // Get list of library names and base addresses
 539         printlnToOutput("libinfo");
 540         int numInfo = in.parseInt();
 541 
 542         for (int i = 0; i < numInfo; i++) {
 543           // NOTE: because Win32 is case insensitive, we standardize on
 544           // lowercase file names.
 545           String  fullPathName = parseString().toLowerCase();
 546           Address base         = newAddress(in.parseAddress());
 547 
 548           File   file = new File(fullPathName);
 549           long   size = file.length();
 550           DLL    dll  = new DLL(this, fullPathName, size, base);
 551           String name = file.getName();
 552           nameToDllMap.put(name, dll);
 553           loadObjects.add(dll);
 554         }
 555       }
 556     } catch (IOException e) {
 557       throw new DebuggerException(e);
 558     }
 559 
 560     return loadObjects;
 561   }
 562 
 563   //----------------------------------------------------------------------
 564   // Process control access
 565   //
 566 
 567   public synchronized void writeBytesToProcess(long startAddress, long numBytes, byte[] data)
 568     throws UnmappedAddressException, DebuggerException {
 569     try {
 570       printToOutput("poke 0x" + Long.toHexString(startAddress) +
 571                     " |");
 572       writeIntToOutput((int) numBytes);
 573       writeToOutput(data, 0, (int) numBytes);
 574       printlnToOutput("");
 575       if (!in.parseBoolean()) {
 576         throw new UnmappedAddressException(startAddress);
 577       }
 578     } catch (IOException e) {
 579       throw new DebuggerException(e);
 580     }
 581   }
 582   
 583   public synchronized void suspend() throws DebuggerException {
 584     try {
 585       if (suspended) {
 586         throw new DebuggerException("Process already suspended");
 587       }
 588       printlnToOutput("suspend");
 589       suspended = true;
 590       enableCache();
 591       reresolveLoadObjects();
 592     } catch (IOException e) {
 593       throw new DebuggerException(e);
 594     }
 595   }
 596 
 597   public synchronized void resume() throws DebuggerException {
 598     try {
 599       if (!suspended) {
 600         throw new DebuggerException("Process not suspended");
 601       }
 602       disableCache();
 603       printlnToOutput("resume");
 604       suspended = false;
 605     } catch (IOException e) {
 606       throw new DebuggerException(e);
 607     }
 608   }
 609 
 610   public synchronized boolean isSuspended() throws DebuggerException {
 611     return suspended;
 612   }
 613   
 614   public synchronized void setBreakpoint(Address addr) throws DebuggerException {
 615     if (!suspended) {
 616       throw new DebuggerException("Process not suspended");
 617     }
 618 
 619     long addrVal = getAddressValue(addr);
 620     Long where = new Long(addrVal);
 621     if (breakpoints.get(where) != null) {
 622       throw new DebuggerException("Breakpoint already set at " + addr);
 623     }
 624     Byte what = new Byte(readBytes(addrVal, 1)[0]);
 625     // Now put 0xCC (int 3) at the target address, fail if can not
 626     writeBytesToProcess(addrVal, 1, new byte[] { (byte) 0xCC });
 627     // OK, the breakpoint is set.
 628     breakpoints.put(where, what);
 629   }
 630 
 631   public synchronized void clearBreakpoint(Address addr) throws DebuggerException {
 632     if (!suspended) {
 633       throw new DebuggerException("Process not suspended");
 634     }
 635 
 636     long addrVal = getAddressValue(addr);
 637     Long where = new Long(addrVal);
 638     Byte what = (Byte) breakpoints.get(where);
 639     if (what == null) {
 640       throw new DebuggerException("Breakpoint not set at " + addr);
 641     }
 642     // Put original data back at address
 643     writeBytesToProcess(addrVal, 1, new byte[] { what.byteValue() });
 644     // OK, breakpoint is cleared
 645     breakpoints.remove(where);
 646   }
 647 
 648   public synchronized boolean isBreakpointSet(Address addr) throws DebuggerException {
 649     return (breakpoints.get(new Long(getAddressValue(addr))) != null);
 650   }
 651 
 652   // Following constants taken from winnt.h
 653   private static final int EXCEPTION_DEBUG_EVENT  = 1;
 654   private static final int LOAD_DLL_DEBUG_EVENT   = 6;
 655   private static final int UNLOAD_DLL_DEBUG_EVENT = 7;
 656   private static final int EXCEPTION_ACCESS_VIOLATION = 0xC0000005;
 657   private static final int EXCEPTION_BREAKPOINT       = 0x80000003;
 658   private static final int EXCEPTION_SINGLE_STEP      = 0x80000004;
 659 
 660   public synchronized DebugEvent debugEventPoll() throws DebuggerException {
 661     if (curDebugEvent != null) {
 662       return curDebugEvent;
 663     }
 664 
 665     try {
 666       printlnToOutput("pollevent");
 667       if (!in.parseBoolean()) {
 668         return null;
 669       }
 670       // Otherwise, got a debug event. Need to figure out what kind it is.
 671       int handle = (int) in.parseAddress();
 672       ThreadProxy thread = new Win32Thread(this, handle);
 673       int code = in.parseInt();
 674       DebugEvent ev = null;
 675       switch (code) {
 676       case LOAD_DLL_DEBUG_EVENT: {
 677         Address addr = newAddress(in.parseAddress());
 678         ev = BasicDebugEvent.newLoadObjectLoadEvent(thread, addr);
 679         break;
 680       }
 681 
 682       case UNLOAD_DLL_DEBUG_EVENT: {
 683         Address addr = newAddress(in.parseAddress());
 684         ev = BasicDebugEvent.newLoadObjectUnloadEvent(thread, addr);
 685         break;
 686       }
 687 
 688       case EXCEPTION_DEBUG_EVENT: {
 689         int exceptionCode = in.parseInt();
 690         Address pc = newAddress(in.parseAddress());
 691         switch (exceptionCode) {
 692         case EXCEPTION_ACCESS_VIOLATION:
 693           boolean wasWrite = in.parseBoolean();
 694           Address addr = newAddress(in.parseAddress());
 695           ev = BasicDebugEvent.newAccessViolationEvent(thread, pc, wasWrite, addr);
 696           break;
 697 
 698         case EXCEPTION_BREAKPOINT:
 699           ev = BasicDebugEvent.newBreakpointEvent(thread, pc);
 700           break;
 701 
 702         case EXCEPTION_SINGLE_STEP:
 703           ev = BasicDebugEvent.newSingleStepEvent(thread, pc);
 704           break;
 705 
 706         default:
 707           ev = BasicDebugEvent.newUnknownEvent(thread,
 708                                                "Exception 0x" + Integer.toHexString(exceptionCode) +
 709                                                " at PC " + pc);
 710           break;
 711         }
 712         break;
 713       }
 714 
 715       default:
 716         ev = BasicDebugEvent.newUnknownEvent(thread,
 717                                              "Debug event " + code + " occurred");
 718         break;
 719       }
 720       if (Assert.ASSERTS_ENABLED) {
 721         Assert.that(ev != null, "Must have created event");
 722       }
 723       curDebugEvent = ev;
 724     } catch (IOException e) {
 725       throw new DebuggerException(e);
 726     }
 727 
 728     return curDebugEvent;
 729   }
 730 
 731   public synchronized void debugEventContinue() throws DebuggerException {
 732     if (curDebugEvent == null) {
 733       throw new DebuggerException("No debug event pending");
 734     }
 735 
 736     try {
 737       ///////////////////////////////////////////////////////////////////
 738       //                                                               //
 739       // FIXME: this **must** be modified to handle breakpoint events
 740       // properly. Must temporarily remove the breakpoint and enable
 741       // single-stepping mode (hiding those single-step events from
 742       // the user unless they have been requested; currently there is
 743       // no way to request single-step events; and it isn't clear how
 744       // to enable them or how the hardware and/or OS typically
 745       // supports them, i.e., are they on a per-process or per-thread
 746       // level?) until the process steps past the breakpoint, then put
 747       // the breakpoint back.
 748       //                                                               //
 749       ///////////////////////////////////////////////////////////////////
 750       
 751       DebugEvent.Type t = curDebugEvent.getType();
 752       boolean shouldPassOn = true;
 753       if (t == DebugEvent.Type.BREAKPOINT) {
 754         // FIXME: correct algorithm appears to be as follows:
 755         //
 756         // 1. Check to see whether we know about this breakpoint. If
 757         // not, it's requested by the user's program and we should
 758         // ignore it (not pass it on to the program).
 759         //
 760         // 2. Replace the original opcode.
 761         //
 762         // 3. Set single-stepping mode in the debug registers.
 763         //
 764         // 4. Back up the PC.
 765         //
 766         // 5. In debugEventPoll(), watch for a single-step event on
 767         // this thread. When we get it, put the breakpoint back. Only
 768         // deliver that single-step event if the user has requested
 769         // single-step events (FIXME: must figure out whether they are
 770         // per-thread or per-process, and also expose a way to turn
 771         // them on.)
 772 
 773         // To make breakpoints work for now, we will just back up the
 774         // PC, which we have to do in order to not disrupt the program
 775         // execution in case the user decides to disable the breakpoint.
 776 
 777         if (breakpoints.get(new Long(getAddressValue(curDebugEvent.getPC()))) != null) {
 778           System.err.println("Backing up PC due to breakpoint");
 779           X86ThreadContext ctx = (X86ThreadContext) curDebugEvent.getThread().getContext();
 780           ctx.setRegister(X86ThreadContext.EIP, ctx.getRegister(X86ThreadContext.EIP) - 1);
 781           curDebugEvent.getThread().setContext(ctx);
 782         } else {
 783           System.err.println("Skipping back up of PC since I didn't know about this breakpoint");
 784           System.err.println("Known breakpoints:");
 785           for (Iterator iter = breakpoints.keySet().iterator(); iter.hasNext(); ) {
 786             System.err.println("  0x" + Long.toHexString(((Long) iter.next()).longValue()));
 787           }
 788         }
 789         shouldPassOn = false;
 790       } else if (t == DebugEvent.Type.SINGLE_STEP) {
 791         shouldPassOn = false;
 792       }
 793       // Other kinds of debug events are either ignored if passed on
 794       // or probably should be passed on so the program exits
 795       // FIXME: generate process exiting events (should be easy)
 796       
 797       int val = (shouldPassOn ? 1 : 0);
 798       printlnToOutput("continueevent " + val);
 799       if (!in.parseBoolean()) {
 800         throw new DebuggerException("Unknown error while attempting to continue past debug event");
 801       }
 802       curDebugEvent = null;
 803     } catch (IOException e) {
 804       throw new DebuggerException(e);
 805     }
 806   }
 807 
 808   //--------------------------------------------------------------------------------
 809   // Address access
 810   //
 811 
 812   /** From the Debugger interface */
 813   public long getAddressValue(Address addr) {
 814     if (addr == null) return 0;
 815     return ((Win32Address) addr).getValue();
 816   }
 817 
 818   /** From the Win32Debugger interface */
 819   public Address newAddress(long value) {
 820     if (value == 0) return null;
 821     return new Win32Address(this, value);
 822   }
 823 
 824   //--------------------------------------------------------------------------------
 825   // Internals only below this point
 826   //
 827 
 828   private String parseString() throws IOException {
 829     int charSize = in.parseInt();
 830     int numChars = in.parseInt();
 831     in.skipByte();
 832     String str;
 833     if (charSize == 1) {
 834       str = in.readByteString(numChars);
 835     } else {
 836       str = in.readCharString(numChars);
 837     }
 838     return str;
 839   }
 840 
 841   /** Looks up an address in the remote process's address space.
 842       Returns 0 if symbol not found or upon error. Package private to
 843       allow Win32DebuggerRemoteIntfImpl access. NOTE that this returns
 844       a long instead of an Address because we do not want to serialize
 845       Addresses. */
 846   synchronized long lookupInProcess(String objectName, String symbol) {
 847     // NOTE: this assumes that process is suspended (which is probably
 848     // necessary assumption given that DLLs can be loaded/unloaded as
 849     // process runs). Should update documentation.
 850     if (nameToDllMap == null) {
 851       getLoadObjectList();
 852     }
 853     DLL dll = (DLL) nameToDllMap.get(objectName);
 854     // The DLL can be null because we use this to search through known
 855     // DLLs in HotSpotTypeDataBase (for example)
 856     if (dll != null) {
 857       Win32Address addr = (Win32Address) dll.lookupSymbol(symbol);
 858       if (addr != null) {
 859         return addr.getValue();
 860       }
 861     }
 862     return 0;
 863   }
 864 
 865   /** This reads bytes from the remote process. */
 866   public synchronized ReadResult readBytesFromProcess(long address, long numBytes)
 867     throws UnmappedAddressException, DebuggerException {
 868     try {
 869       String cmd = "peek " + utils.addressValueToString(address) + " " + numBytes;
 870       printlnToOutput(cmd);
 871       while (in.readByte() != 'B') {
 872       }
 873       byte res = in.readByte();
 874       if (res == 0) {
 875         System.err.println("Failing command: " + cmd);
 876         throw new DebuggerException("Read of remote process address space failed");
 877       }
 878       // NOTE: must read ALL of the data regardless of whether we need
 879       // to throw an UnmappedAddressException. Otherwise will corrupt
 880       // the input stream each time we have a failure. Not good. Do
 881       // not want to risk "flushing" the input stream in case a huge
 882       // read has a hangup in the middle and we leave data on the
 883       // stream.
 884       byte[] buf = new byte[(int) numBytes];
 885       boolean bailOut = false;
 886       long failureAddress = 0;
 887       while (numBytes > 0) {
 888         long len = in.readUnsignedInt();
 889         boolean isMapped = ((in.readByte() == 0) ? false : true);
 890         if (!isMapped) {
 891           if (!bailOut) {
 892             bailOut = true;
 893             failureAddress = address;
 894           }
 895         } else {
 896           // This won't work if we have unmapped regions, but if we do
 897           // then we're going to throw an exception anyway
 898 
 899           // NOTE: there is a factor of 20 speed difference between
 900           // these two ways of doing this read.
 901           in.readBytes(buf, 0, (int) len);
 902         }
 903 
 904         // Do NOT do this:
 905         //        for (int i = 0; i < (int) len; i++) {
 906         //          buf[i] = in.readByte();
 907         //        }
 908 
 909         numBytes -= len;
 910         address += len;
 911       }
 912       if (Assert.ASSERTS_ENABLED) {
 913         Assert.that(numBytes == 0, "Bug in debug server's implementation of peek");
 914       }
 915       if (bailOut) {
 916         return new ReadResult(failureAddress);
 917       }
 918       return new ReadResult(buf);
 919     }
 920     catch (IOException e) {
 921       throw new DebuggerException(e);
 922     }
 923   }
 924 
 925   /** Convenience routines */
 926   private void printlnToOutput(String s) throws IOException {
 927     out.println(s);
 928     if (out.checkError()) {
 929       throw new IOException("Error occurred while writing to debug server");
 930     }
 931   }
 932 
 933   private void printToOutput(String s) throws IOException {
 934     out.print(s);
 935     if (out.checkError()) {
 936       throw new IOException("Error occurred while writing to debug server");
 937     }
 938   }
 939 
 940   private void writeIntToOutput(int val) throws IOException {
 941     rawOut.writeInt(val);
 942     rawOut.flush();
 943   }
 944 
 945   private void writeToOutput(byte[] buf, int off, int len) throws IOException {
 946     rawOut.write(buf, off, len);
 947     rawOut.flush();
 948   }
 949 
 950   /** Connects to the debug server, setting up out and in streams. */
 951   private void connectToDebugServer() throws IOException {
 952     // Try for a short period of time to connect to debug server; time out
 953     // with failure if didn't succeed
 954     debuggerSocket = null;
 955     long endTime = System.currentTimeMillis() + SHORT_TIMEOUT;
 956 
 957     while ((debuggerSocket == null) && (System.currentTimeMillis() < endTime)) {
 958       try {
 959         // FIXME: this does not work if we are on a DHCP machine which
 960         // did not get an IP address this session. It appears to use
 961         // an old cached address and the connection does not actually
 962         // succeed. Must file a bug.
 963         // debuggerSocket = new Socket(InetAddress.getLocalHost(), PORT);
 964         debuggerSocket = new Socket(InetAddress.getByName("127.0.0.1"), PORT);
 965         debuggerSocket.setTcpNoDelay(true);
 966       }
 967       catch (IOException e) {
 968         // Swallow IO exceptions while attempting connection
 969         debuggerSocket = null;
 970         try {
 971           // Don't swamp the CPU
 972           Thread.sleep(750);
 973         }
 974         catch (InterruptedException ex) {
 975         }
 976       }
 977     }
 978 
 979     if (debuggerSocket == null) {
 980       // Failed to connect because of timeout
 981       throw new DebuggerException("Timed out while attempting to connect to debug server (please start SwDbgSrv.exe)");
 982     }
 983 
 984     out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(debuggerSocket.getOutputStream(), "US-ASCII")), true);
 985     rawOut = new DataOutputStream(new BufferedOutputStream(debuggerSocket.getOutputStream()));
 986     in = new InputLexer(new BufferedInputStream(debuggerSocket.getInputStream()));
 987   }
 988 
 989   private DLL findDLLByName(String fullPathName) {
 990     for (Iterator iter = loadObjects.iterator(); iter.hasNext(); ) {
 991       DLL dll = (DLL) iter.next();
 992       if (dll.getName().equals(fullPathName)) {
 993         return dll;
 994       }
 995     }
 996     return null;
 997   }
 998 
 999   private void reresolveLoadObjects() throws DebuggerException {
1000     try {
1001       // It is too expensive to throw away the loadobject list every
1002       // time the process is suspended, largely because of debug
1003       // information re-parsing. When we suspend the target process we
1004       // instead fetch the list of loaded libraries in the target and
1005       // see whether any loadobject needs to be thrown away (because it
1006       // was unloaded) or invalidated (because it was unloaded and
1007       // reloaded at a different target address). Note that we don't
1008       // properly handle the case of a loaded DLL being unloaded,
1009       // recompiled, and reloaded. We could handle this by keeping a
1010       // time stamp.
1011 
1012       if (loadObjects == null) {
1013         return;
1014       }
1015 
1016       // Need to create new list since have to figure out which ones
1017       // were unloaded
1018       List newLoadObjects = new ArrayList();
1019 
1020     // Get list of library names and base addresses
1021       printlnToOutput("libinfo");
1022       int numInfo = in.parseInt();
1023 
1024       for (int i = 0; i < numInfo; i++) {
1025         // NOTE: because Win32 is case insensitive, we standardize on
1026         // lowercase file names.
1027         String  fullPathName = parseString().toLowerCase();
1028         Address base         = newAddress(in.parseAddress());
1029 
1030         // Look for full path name in DLL list
1031         DLL dll = findDLLByName(fullPathName);
1032         boolean mustLoad = true;
1033         if (dll != null) {
1034           loadObjects.remove(dll);
1035 
1036           // See whether base addresses match; otherwise, need to reload
1037           if (AddressOps.equal(base, dll.getBase())) {
1038             mustLoad = false;
1039           }
1040         }
1041 
1042         if (mustLoad) {
1043           // Create new DLL
1044           File   file = new File(fullPathName);
1045           long   size = file.length();
1046           String name = file.getName();
1047           dll  = new DLL(this, fullPathName, size, base);
1048           nameToDllMap.put(name, dll);
1049         }
1050         newLoadObjects.add(dll);
1051       }
1052 
1053       // All remaining entries in loadObjects have to be removed from
1054       // the nameToDllMap
1055       for (Iterator dllIter = loadObjects.iterator(); dllIter.hasNext(); ) {
1056         DLL dll = (DLL) dllIter.next();
1057         for (Iterator iter = nameToDllMap.keySet().iterator(); iter.hasNext(); ) {
1058           String name = (String) iter.next();
1059           if (nameToDllMap.get(name) == dll) {
1060             nameToDllMap.remove(name);
1061             break;
1062           }
1063         }
1064       }
1065 
1066       loadObjects = newLoadObjects;
1067     } catch (IOException e) {
1068       loadObjects = null;
1069       nameToDllMap = null;
1070       throw new DebuggerException(e);
1071     }
1072   }
1073 }