1 /*
   2  * Copyright 2000-2008 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   public Win32Address readCompOopAddress(long address)
 310     throws UnmappedAddressException, UnalignedAddressException {
 311     return (Win32Address) newAddress(readCompOopAddressValue(address));
 312   }
 313 
 314   /** From the Win32Debugger interface */
 315   public Win32OopHandle readOopHandle(long address)
 316     throws UnmappedAddressException, UnalignedAddressException, NotInHeapException {
 317     long value = readAddressValue(address);
 318     return (value == 0 ? null : new Win32OopHandle(this, value));
 319   }
 320   public Win32OopHandle readCompOopHandle(long address)
 321     throws UnmappedAddressException, UnalignedAddressException, NotInHeapException {
 322     long value = readCompOopAddressValue(address);
 323     return (value == 0 ? null : new Win32OopHandle(this, value));
 324   }
 325 
 326   /** From the Win32Debugger interface */
 327   public void writeAddress(long address, Win32Address value) {
 328     writeAddressValue(address, getAddressValue(value));
 329   }
 330 
 331   /** From the Win32Debugger interface */
 332   public void writeOopHandle(long address, Win32OopHandle value) {
 333     writeAddressValue(address, getAddressValue(value));
 334   }
 335 
 336   //--------------------------------------------------------------------------------
 337   // Thread context access
 338   //
 339 
 340   public synchronized long[] getThreadIntegerRegisterSet(int threadHandleValue,
 341                                                          boolean mustDuplicateHandle)
 342     throws DebuggerException {
 343     if (!suspended) {
 344       throw new DebuggerException("Process not suspended");
 345     }
 346 
 347     try {
 348       int handle = threadHandleValue;
 349       if (mustDuplicateHandle) {
 350         printlnToOutput("duphandle 0x" + Integer.toHexString(threadHandleValue));
 351         if (!in.parseBoolean()) {
 352           throw new DebuggerException("Error duplicating thread handle 0x" + threadHandleValue);
 353         } 
 354         handle = (int) in.parseAddress(); // Must close to avoid leaks
 355       }
 356       printlnToOutput("getcontext 0x" + Integer.toHexString(handle));
 357       if (!in.parseBoolean()) {
 358         if (mustDuplicateHandle) {
 359           printlnToOutput("closehandle 0x" + Integer.toHexString(handle));
 360         }
 361         String failMessage = "GetThreadContext failed for thread handle 0x" +
 362                              Integer.toHexString(handle);
 363         if (mustDuplicateHandle) {
 364           failMessage = failMessage + ", duplicated from thread handle " +
 365                         Integer.toHexString(threadHandleValue);
 366         }
 367         throw new DebuggerException(failMessage);
 368       }
 369       // Otherwise, parse all registers. See
 370       // src/os/win32/agent/README-commands.txt for the format.
 371       // Note the array we have to return has to match that specified by
 372       // X86ThreadContext.java.
 373       int numRegs = 22;
 374       long[] winRegs = new long[numRegs];
 375       for (int i = 0; i < numRegs; i++) {
 376         winRegs[i] = in.parseAddress();
 377       }
 378       if (mustDuplicateHandle) {
 379         // Clean up after ourselves
 380         printlnToOutput("closehandle 0x" + Integer.toHexString(handle));
 381       }
 382       // Now create the real return value
 383       long[] retval = new long[X86ThreadContext.NPRGREG];
 384       retval[X86ThreadContext.EAX] = winRegs[0];
 385       retval[X86ThreadContext.EBX] = winRegs[1];
 386       retval[X86ThreadContext.ECX] = winRegs[2];
 387       retval[X86ThreadContext.EDX] = winRegs[3];
 388       retval[X86ThreadContext.ESI] = winRegs[4];
 389       retval[X86ThreadContext.EDI] = winRegs[5];
 390       retval[X86ThreadContext.EBP] = winRegs[6];
 391       retval[X86ThreadContext.ESP] = winRegs[7];
 392       retval[X86ThreadContext.EIP] = winRegs[8];
 393       retval[X86ThreadContext.DS]  = winRegs[9];
 394       retval[X86ThreadContext.ES]  = winRegs[10];
 395       retval[X86ThreadContext.FS]  = winRegs[11];
 396       retval[X86ThreadContext.GS]  = winRegs[12];
 397       retval[X86ThreadContext.CS]  = winRegs[13];
 398       retval[X86ThreadContext.SS]  = winRegs[14];
 399       retval[X86ThreadContext.EFL] = winRegs[15];
 400       retval[X86ThreadContext.DR0] = winRegs[16];
 401       retval[X86ThreadContext.DR1] = winRegs[17];
 402       retval[X86ThreadContext.DR2] = winRegs[18];
 403       retval[X86ThreadContext.DR3] = winRegs[19];
 404       retval[X86ThreadContext.DR6] = winRegs[20];
 405       retval[X86ThreadContext.DR7] = winRegs[21];
 406       return retval;
 407     } catch (IOException e) {
 408       throw new DebuggerException(e);
 409     }
 410   }
 411 
 412   public synchronized void setThreadIntegerRegisterSet(int threadHandleValue,
 413                                                        boolean mustDuplicateHandle,
 414                                                        long[] context)
 415     throws DebuggerException {
 416     if (!suspended) {
 417       throw new DebuggerException("Process not suspended");
 418     }
 419 
 420     try {
 421       int handle = threadHandleValue;
 422       if (mustDuplicateHandle) {
 423         printlnToOutput("duphandle 0x" + Integer.toHexString(threadHandleValue));
 424         if (!in.parseBoolean()) {
 425           throw new DebuggerException("Error duplicating thread handle 0x" + threadHandleValue);
 426         } 
 427         handle = (int) in.parseAddress(); // Must close to avoid leaks
 428       }
 429       // Change order of registers to match that of debug server
 430       long[] winRegs = new long[context.length];
 431       winRegs[0] = context[X86ThreadContext.EAX];
 432       winRegs[1] = context[X86ThreadContext.EBX];
 433       winRegs[2] = context[X86ThreadContext.ECX];
 434       winRegs[3] = context[X86ThreadContext.EDX];
 435       winRegs[4] = context[X86ThreadContext.ESI];
 436       winRegs[5] = context[X86ThreadContext.EDI];
 437       winRegs[6] = context[X86ThreadContext.EBP];
 438       winRegs[7] = context[X86ThreadContext.ESP];
 439       winRegs[8] = context[X86ThreadContext.EIP];
 440       winRegs[9] = context[X86ThreadContext.DS];
 441       winRegs[10] = context[X86ThreadContext.ES];
 442       winRegs[11] = context[X86ThreadContext.FS];
 443       winRegs[12] = context[X86ThreadContext.GS];
 444       winRegs[13] = context[X86ThreadContext.CS];
 445       winRegs[14] = context[X86ThreadContext.SS];
 446       winRegs[15] = context[X86ThreadContext.EFL];
 447       winRegs[16] = context[X86ThreadContext.DR0];
 448       winRegs[17] = context[X86ThreadContext.DR1];
 449       winRegs[18] = context[X86ThreadContext.DR2];
 450       winRegs[19] = context[X86ThreadContext.DR3];
 451       winRegs[20] = context[X86ThreadContext.DR6];
 452       winRegs[21] = context[X86ThreadContext.DR7];
 453       StringBuffer cmd = new StringBuffer();
 454       cmd.append("setcontext 0x");
 455       cmd.append(Integer.toHexString(threadHandleValue));
 456       for (int i = 0; i < context.length; i++) {
 457         cmd.append(" 0x");
 458         cmd.append(Long.toHexString(winRegs[i]));
 459       }
 460       printlnToOutput(cmd.toString());
 461       boolean res = in.parseBoolean();
 462       if (mustDuplicateHandle) {
 463         printlnToOutput("closehandle 0x" + Integer.toHexString(handle));
 464       }
 465       if (!res) {
 466         String failMessage = "SetThreadContext failed for thread handle 0x" +
 467           Integer.toHexString(handle);
 468         if (mustDuplicateHandle) {
 469           failMessage = failMessage + ", duplicated from thread handle " +
 470             Integer.toHexString(threadHandleValue);
 471         }
 472         throw new DebuggerException(failMessage);
 473       }
 474     } catch (IOException e) {
 475       throw new DebuggerException(e);
 476     }
 477   }
 478 
 479   /** Fetches the Win32 LDT_ENTRY for the given thread and selector.
 480       This data structure allows the conversion of a segment-relative
 481       address to a linear virtual address. For example, it allows the
 482       expression of operations like "mov eax, fs:[18h]", which fetches
 483       the thread information block, allowing access to the thread
 484       ID. */
 485   public synchronized Win32LDTEntry getThreadSelectorEntry(int threadHandleValue,
 486                                                            boolean mustDuplicateHandle,
 487                                                            int selector)
 488     throws DebuggerException {
 489     try {
 490       int handle = threadHandleValue;
 491       if (mustDuplicateHandle) {
 492         printlnToOutput("duphandle 0x" + Integer.toHexString(threadHandleValue));
 493         if (!in.parseBoolean()) {
 494           throw new DebuggerException("Error duplicating thread handle 0x" + threadHandleValue);
 495         } 
 496         handle = (int) in.parseAddress(); // Must close to avoid leaks
 497       }
 498       printlnToOutput("selectorentry 0x" + Integer.toHexString(handle) + " " + selector);
 499       if (!in.parseBoolean()) {
 500         if (mustDuplicateHandle) {
 501           printlnToOutput("closehandle 0x" + Integer.toHexString(handle));
 502         }
 503         throw new DebuggerException("GetThreadContext failed for thread handle 0x" + handle +
 504                                     ", duplicated from thread handle " + threadHandleValue);
 505       }
 506       // Parse result. See
 507       // src/os/win32/agent/README-commands.txt for the format.
 508       short limitLow = (short) in.parseAddress();
 509       short baseLow  = (short) in.parseAddress();
 510       byte  baseMid  = (byte)  in.parseAddress();
 511       byte  flags1   = (byte)  in.parseAddress();
 512       byte  flags2   = (byte)  in.parseAddress();
 513       byte  baseHi   = (byte)  in.parseAddress();
 514       return new Win32LDTEntry(limitLow, baseLow, baseMid, flags1, flags2, baseHi);
 515     } catch (IOException e) {
 516       throw new DebuggerException(e);
 517     }
 518   }
 519 
 520   public synchronized List getThreadList() throws DebuggerException {
 521     if (!suspended) {
 522       throw new DebuggerException("Process not suspended");
 523     }
 524 
 525     try {
 526       printlnToOutput("threadlist");
 527       List ret = new ArrayList();
 528       int numThreads = in.parseInt();
 529       for (int i = 0; i < numThreads; i++) {
 530         int handle = (int) in.parseAddress();
 531         ret.add(new Win32Thread(this, handle));
 532       }
 533       return ret;
 534     } catch (IOException e) {
 535       throw new DebuggerException(e);
 536     }
 537   }
 538 
 539   public synchronized List getLoadObjectList() throws DebuggerException {
 540     if (!suspended) {
 541       throw new DebuggerException("Process not suspended");
 542     }
 543 
 544     try {
 545       if (loadObjects == null) {
 546         loadObjects  = new ArrayList();
 547         nameToDllMap = new HashMap();
 548         // Get list of library names and base addresses
 549         printlnToOutput("libinfo");
 550         int numInfo = in.parseInt();
 551 
 552         for (int i = 0; i < numInfo; i++) {
 553           // NOTE: because Win32 is case insensitive, we standardize on
 554           // lowercase file names.
 555           String  fullPathName = parseString().toLowerCase();
 556           Address base         = newAddress(in.parseAddress());
 557 
 558           File   file = new File(fullPathName);
 559           long   size = file.length();
 560           DLL    dll  = new DLL(this, fullPathName, size, base);
 561           String name = file.getName();
 562           nameToDllMap.put(name, dll);
 563           loadObjects.add(dll);
 564         }
 565       }
 566     } catch (IOException e) {
 567       throw new DebuggerException(e);
 568     }
 569 
 570     return loadObjects;
 571   }
 572 
 573   //----------------------------------------------------------------------
 574   // Process control access
 575   //
 576 
 577   public synchronized void writeBytesToProcess(long startAddress, long numBytes, byte[] data)
 578     throws UnmappedAddressException, DebuggerException {
 579     try {
 580       printToOutput("poke 0x" + Long.toHexString(startAddress) +
 581                     " |");
 582       writeIntToOutput((int) numBytes);
 583       writeToOutput(data, 0, (int) numBytes);
 584       printlnToOutput("");
 585       if (!in.parseBoolean()) {
 586         throw new UnmappedAddressException(startAddress);
 587       }
 588     } catch (IOException e) {
 589       throw new DebuggerException(e);
 590     }
 591   }
 592   
 593   public synchronized void suspend() throws DebuggerException {
 594     try {
 595       if (suspended) {
 596         throw new DebuggerException("Process already suspended");
 597       }
 598       printlnToOutput("suspend");
 599       suspended = true;
 600       enableCache();
 601       reresolveLoadObjects();
 602     } catch (IOException e) {
 603       throw new DebuggerException(e);
 604     }
 605   }
 606 
 607   public synchronized void resume() throws DebuggerException {
 608     try {
 609       if (!suspended) {
 610         throw new DebuggerException("Process not suspended");
 611       }
 612       disableCache();
 613       printlnToOutput("resume");
 614       suspended = false;
 615     } catch (IOException e) {
 616       throw new DebuggerException(e);
 617     }
 618   }
 619 
 620   public synchronized boolean isSuspended() throws DebuggerException {
 621     return suspended;
 622   }
 623   
 624   public synchronized void setBreakpoint(Address addr) throws DebuggerException {
 625     if (!suspended) {
 626       throw new DebuggerException("Process not suspended");
 627     }
 628 
 629     long addrVal = getAddressValue(addr);
 630     Long where = new Long(addrVal);
 631     if (breakpoints.get(where) != null) {
 632       throw new DebuggerException("Breakpoint already set at " + addr);
 633     }
 634     Byte what = new Byte(readBytes(addrVal, 1)[0]);
 635     // Now put 0xCC (int 3) at the target address, fail if can not
 636     writeBytesToProcess(addrVal, 1, new byte[] { (byte) 0xCC });
 637     // OK, the breakpoint is set.
 638     breakpoints.put(where, what);
 639   }
 640 
 641   public synchronized void clearBreakpoint(Address addr) throws DebuggerException {
 642     if (!suspended) {
 643       throw new DebuggerException("Process not suspended");
 644     }
 645 
 646     long addrVal = getAddressValue(addr);
 647     Long where = new Long(addrVal);
 648     Byte what = (Byte) breakpoints.get(where);
 649     if (what == null) {
 650       throw new DebuggerException("Breakpoint not set at " + addr);
 651     }
 652     // Put original data back at address
 653     writeBytesToProcess(addrVal, 1, new byte[] { what.byteValue() });
 654     // OK, breakpoint is cleared
 655     breakpoints.remove(where);
 656   }
 657 
 658   public synchronized boolean isBreakpointSet(Address addr) throws DebuggerException {
 659     return (breakpoints.get(new Long(getAddressValue(addr))) != null);
 660   }
 661 
 662   // Following constants taken from winnt.h
 663   private static final int EXCEPTION_DEBUG_EVENT  = 1;
 664   private static final int LOAD_DLL_DEBUG_EVENT   = 6;
 665   private static final int UNLOAD_DLL_DEBUG_EVENT = 7;
 666   private static final int EXCEPTION_ACCESS_VIOLATION = 0xC0000005;
 667   private static final int EXCEPTION_BREAKPOINT       = 0x80000003;
 668   private static final int EXCEPTION_SINGLE_STEP      = 0x80000004;
 669 
 670   public synchronized DebugEvent debugEventPoll() throws DebuggerException {
 671     if (curDebugEvent != null) {
 672       return curDebugEvent;
 673     }
 674 
 675     try {
 676       printlnToOutput("pollevent");
 677       if (!in.parseBoolean()) {
 678         return null;
 679       }
 680       // Otherwise, got a debug event. Need to figure out what kind it is.
 681       int handle = (int) in.parseAddress();
 682       ThreadProxy thread = new Win32Thread(this, handle);
 683       int code = in.parseInt();
 684       DebugEvent ev = null;
 685       switch (code) {
 686       case LOAD_DLL_DEBUG_EVENT: {
 687         Address addr = newAddress(in.parseAddress());
 688         ev = BasicDebugEvent.newLoadObjectLoadEvent(thread, addr);
 689         break;
 690       }
 691 
 692       case UNLOAD_DLL_DEBUG_EVENT: {
 693         Address addr = newAddress(in.parseAddress());
 694         ev = BasicDebugEvent.newLoadObjectUnloadEvent(thread, addr);
 695         break;
 696       }
 697 
 698       case EXCEPTION_DEBUG_EVENT: {
 699         int exceptionCode = in.parseInt();
 700         Address pc = newAddress(in.parseAddress());
 701         switch (exceptionCode) {
 702         case EXCEPTION_ACCESS_VIOLATION:
 703           boolean wasWrite = in.parseBoolean();
 704           Address addr = newAddress(in.parseAddress());
 705           ev = BasicDebugEvent.newAccessViolationEvent(thread, pc, wasWrite, addr);
 706           break;
 707 
 708         case EXCEPTION_BREAKPOINT:
 709           ev = BasicDebugEvent.newBreakpointEvent(thread, pc);
 710           break;
 711 
 712         case EXCEPTION_SINGLE_STEP:
 713           ev = BasicDebugEvent.newSingleStepEvent(thread, pc);
 714           break;
 715 
 716         default:
 717           ev = BasicDebugEvent.newUnknownEvent(thread,
 718                                                "Exception 0x" + Integer.toHexString(exceptionCode) +
 719                                                " at PC " + pc);
 720           break;
 721         }
 722         break;
 723       }
 724 
 725       default:
 726         ev = BasicDebugEvent.newUnknownEvent(thread,
 727                                              "Debug event " + code + " occurred");
 728         break;
 729       }
 730       if (Assert.ASSERTS_ENABLED) {
 731         Assert.that(ev != null, "Must have created event");
 732       }
 733       curDebugEvent = ev;
 734     } catch (IOException e) {
 735       throw new DebuggerException(e);
 736     }
 737 
 738     return curDebugEvent;
 739   }
 740 
 741   public synchronized void debugEventContinue() throws DebuggerException {
 742     if (curDebugEvent == null) {
 743       throw new DebuggerException("No debug event pending");
 744     }
 745 
 746     try {
 747       ///////////////////////////////////////////////////////////////////
 748       //                                                               //
 749       // FIXME: this **must** be modified to handle breakpoint events
 750       // properly. Must temporarily remove the breakpoint and enable
 751       // single-stepping mode (hiding those single-step events from
 752       // the user unless they have been requested; currently there is
 753       // no way to request single-step events; and it isn't clear how
 754       // to enable them or how the hardware and/or OS typically
 755       // supports them, i.e., are they on a per-process or per-thread
 756       // level?) until the process steps past the breakpoint, then put
 757       // the breakpoint back.
 758       //                                                               //
 759       ///////////////////////////////////////////////////////////////////
 760       
 761       DebugEvent.Type t = curDebugEvent.getType();
 762       boolean shouldPassOn = true;
 763       if (t == DebugEvent.Type.BREAKPOINT) {
 764         // FIXME: correct algorithm appears to be as follows:
 765         //
 766         // 1. Check to see whether we know about this breakpoint. If
 767         // not, it's requested by the user's program and we should
 768         // ignore it (not pass it on to the program).
 769         //
 770         // 2. Replace the original opcode.
 771         //
 772         // 3. Set single-stepping mode in the debug registers.
 773         //
 774         // 4. Back up the PC.
 775         //
 776         // 5. In debugEventPoll(), watch for a single-step event on
 777         // this thread. When we get it, put the breakpoint back. Only
 778         // deliver that single-step event if the user has requested
 779         // single-step events (FIXME: must figure out whether they are
 780         // per-thread or per-process, and also expose a way to turn
 781         // them on.)
 782 
 783         // To make breakpoints work for now, we will just back up the
 784         // PC, which we have to do in order to not disrupt the program
 785         // execution in case the user decides to disable the breakpoint.
 786 
 787         if (breakpoints.get(new Long(getAddressValue(curDebugEvent.getPC()))) != null) {
 788           System.err.println("Backing up PC due to breakpoint");
 789           X86ThreadContext ctx = (X86ThreadContext) curDebugEvent.getThread().getContext();
 790           ctx.setRegister(X86ThreadContext.EIP, ctx.getRegister(X86ThreadContext.EIP) - 1);
 791           curDebugEvent.getThread().setContext(ctx);
 792         } else {
 793           System.err.println("Skipping back up of PC since I didn't know about this breakpoint");
 794           System.err.println("Known breakpoints:");
 795           for (Iterator iter = breakpoints.keySet().iterator(); iter.hasNext(); ) {
 796             System.err.println("  0x" + Long.toHexString(((Long) iter.next()).longValue()));
 797           }
 798         }
 799         shouldPassOn = false;
 800       } else if (t == DebugEvent.Type.SINGLE_STEP) {
 801         shouldPassOn = false;
 802       }
 803       // Other kinds of debug events are either ignored if passed on
 804       // or probably should be passed on so the program exits
 805       // FIXME: generate process exiting events (should be easy)
 806       
 807       int val = (shouldPassOn ? 1 : 0);
 808       printlnToOutput("continueevent " + val);
 809       if (!in.parseBoolean()) {
 810         throw new DebuggerException("Unknown error while attempting to continue past debug event");
 811       }
 812       curDebugEvent = null;
 813     } catch (IOException e) {
 814       throw new DebuggerException(e);
 815     }
 816   }
 817 
 818   //--------------------------------------------------------------------------------
 819   // Address access
 820   //
 821 
 822   /** From the Debugger interface */
 823   public long getAddressValue(Address addr) {
 824     if (addr == null) return 0;
 825     return ((Win32Address) addr).getValue();
 826   }
 827 
 828   /** From the Win32Debugger interface */
 829   public Address newAddress(long value) {
 830     if (value == 0) return null;
 831     return new Win32Address(this, value);
 832   }
 833 
 834   //--------------------------------------------------------------------------------
 835   // Internals only below this point
 836   //
 837 
 838   private String parseString() throws IOException {
 839     int charSize = in.parseInt();
 840     int numChars = in.parseInt();
 841     in.skipByte();
 842     String str;
 843     if (charSize == 1) {
 844       str = in.readByteString(numChars);
 845     } else {
 846       str = in.readCharString(numChars);
 847     }
 848     return str;
 849   }
 850 
 851   /** Looks up an address in the remote process's address space.
 852       Returns 0 if symbol not found or upon error. Package private to
 853       allow Win32DebuggerRemoteIntfImpl access. NOTE that this returns
 854       a long instead of an Address because we do not want to serialize
 855       Addresses. */
 856   synchronized long lookupInProcess(String objectName, String symbol) {
 857     // NOTE: this assumes that process is suspended (which is probably
 858     // necessary assumption given that DLLs can be loaded/unloaded as
 859     // process runs). Should update documentation.
 860     if (nameToDllMap == null) {
 861       getLoadObjectList();
 862     }
 863     DLL dll = (DLL) nameToDllMap.get(objectName);
 864     // The DLL can be null because we use this to search through known
 865     // DLLs in HotSpotTypeDataBase (for example)
 866     if (dll != null) {
 867       Win32Address addr = (Win32Address) dll.lookupSymbol(symbol);
 868       if (addr != null) {
 869         return addr.getValue();
 870       }
 871     }
 872     return 0;
 873   }
 874 
 875   /** This reads bytes from the remote process. */
 876   public synchronized ReadResult readBytesFromProcess(long address, long numBytes)
 877     throws UnmappedAddressException, DebuggerException {
 878     try {
 879       String cmd = "peek " + utils.addressValueToString(address) + " " + numBytes;
 880       printlnToOutput(cmd);
 881       while (in.readByte() != 'B') {
 882       }
 883       byte res = in.readByte();
 884       if (res == 0) {
 885         System.err.println("Failing command: " + cmd);
 886         throw new DebuggerException("Read of remote process address space failed");
 887       }
 888       // NOTE: must read ALL of the data regardless of whether we need
 889       // to throw an UnmappedAddressException. Otherwise will corrupt
 890       // the input stream each time we have a failure. Not good. Do
 891       // not want to risk "flushing" the input stream in case a huge
 892       // read has a hangup in the middle and we leave data on the
 893       // stream.
 894       byte[] buf = new byte[(int) numBytes];
 895       boolean bailOut = false;
 896       long failureAddress = 0;
 897       while (numBytes > 0) {
 898         long len = in.readUnsignedInt();
 899         boolean isMapped = ((in.readByte() == 0) ? false : true);
 900         if (!isMapped) {
 901           if (!bailOut) {
 902             bailOut = true;
 903             failureAddress = address;
 904           }
 905         } else {
 906           // This won't work if we have unmapped regions, but if we do
 907           // then we're going to throw an exception anyway
 908 
 909           // NOTE: there is a factor of 20 speed difference between
 910           // these two ways of doing this read.
 911           in.readBytes(buf, 0, (int) len);
 912         }
 913 
 914         // Do NOT do this:
 915         //        for (int i = 0; i < (int) len; i++) {
 916         //          buf[i] = in.readByte();
 917         //        }
 918 
 919         numBytes -= len;
 920         address += len;
 921       }
 922       if (Assert.ASSERTS_ENABLED) {
 923         Assert.that(numBytes == 0, "Bug in debug server's implementation of peek");
 924       }
 925       if (bailOut) {
 926         return new ReadResult(failureAddress);
 927       }
 928       return new ReadResult(buf);
 929     }
 930     catch (IOException e) {
 931       throw new DebuggerException(e);
 932     }
 933   }
 934 
 935   /** Convenience routines */
 936   private void printlnToOutput(String s) throws IOException {
 937     out.println(s);
 938     if (out.checkError()) {
 939       throw new IOException("Error occurred while writing to debug server");
 940     }
 941   }
 942 
 943   private void printToOutput(String s) throws IOException {
 944     out.print(s);
 945     if (out.checkError()) {
 946       throw new IOException("Error occurred while writing to debug server");
 947     }
 948   }
 949 
 950   private void writeIntToOutput(int val) throws IOException {
 951     rawOut.writeInt(val);
 952     rawOut.flush();
 953   }
 954 
 955   private void writeToOutput(byte[] buf, int off, int len) throws IOException {
 956     rawOut.write(buf, off, len);
 957     rawOut.flush();
 958   }
 959 
 960   /** Connects to the debug server, setting up out and in streams. */
 961   private void connectToDebugServer() throws IOException {
 962     // Try for a short period of time to connect to debug server; time out
 963     // with failure if didn't succeed
 964     debuggerSocket = null;
 965     long endTime = System.currentTimeMillis() + SHORT_TIMEOUT;
 966 
 967     while ((debuggerSocket == null) && (System.currentTimeMillis() < endTime)) {
 968       try {
 969         // FIXME: this does not work if we are on a DHCP machine which
 970         // did not get an IP address this session. It appears to use
 971         // an old cached address and the connection does not actually
 972         // succeed. Must file a bug.
 973         // debuggerSocket = new Socket(InetAddress.getLocalHost(), PORT);
 974         debuggerSocket = new Socket(InetAddress.getByName("127.0.0.1"), PORT);
 975         debuggerSocket.setTcpNoDelay(true);
 976       }
 977       catch (IOException e) {
 978         // Swallow IO exceptions while attempting connection
 979         debuggerSocket = null;
 980         try {
 981           // Don't swamp the CPU
 982           Thread.sleep(750);
 983         }
 984         catch (InterruptedException ex) {
 985         }
 986       }
 987     }
 988 
 989     if (debuggerSocket == null) {
 990       // Failed to connect because of timeout
 991       throw new DebuggerException("Timed out while attempting to connect to debug server (please start SwDbgSrv.exe)");
 992     }
 993 
 994     out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(debuggerSocket.getOutputStream(), "US-ASCII")), true);
 995     rawOut = new DataOutputStream(new BufferedOutputStream(debuggerSocket.getOutputStream()));
 996     in = new InputLexer(new BufferedInputStream(debuggerSocket.getInputStream()));
 997   }
 998 
 999   private DLL findDLLByName(String fullPathName) {
1000     for (Iterator iter = loadObjects.iterator(); iter.hasNext(); ) {
1001       DLL dll = (DLL) iter.next();
1002       if (dll.getName().equals(fullPathName)) {
1003         return dll;
1004       }
1005     }
1006     return null;
1007   }
1008 
1009   private void reresolveLoadObjects() throws DebuggerException {
1010     try {
1011       // It is too expensive to throw away the loadobject list every
1012       // time the process is suspended, largely because of debug
1013       // information re-parsing. When we suspend the target process we
1014       // instead fetch the list of loaded libraries in the target and
1015       // see whether any loadobject needs to be thrown away (because it
1016       // was unloaded) or invalidated (because it was unloaded and
1017       // reloaded at a different target address). Note that we don't
1018       // properly handle the case of a loaded DLL being unloaded,
1019       // recompiled, and reloaded. We could handle this by keeping a
1020       // time stamp.
1021 
1022       if (loadObjects == null) {
1023         return;
1024       }
1025 
1026       // Need to create new list since have to figure out which ones
1027       // were unloaded
1028       List newLoadObjects = new ArrayList();
1029 
1030     // Get list of library names and base addresses
1031       printlnToOutput("libinfo");
1032       int numInfo = in.parseInt();
1033 
1034       for (int i = 0; i < numInfo; i++) {
1035         // NOTE: because Win32 is case insensitive, we standardize on
1036         // lowercase file names.
1037         String  fullPathName = parseString().toLowerCase();
1038         Address base         = newAddress(in.parseAddress());
1039 
1040         // Look for full path name in DLL list
1041         DLL dll = findDLLByName(fullPathName);
1042         boolean mustLoad = true;
1043         if (dll != null) {
1044           loadObjects.remove(dll);
1045 
1046           // See whether base addresses match; otherwise, need to reload
1047           if (AddressOps.equal(base, dll.getBase())) {
1048             mustLoad = false;
1049           }
1050         }
1051 
1052         if (mustLoad) {
1053           // Create new DLL
1054           File   file = new File(fullPathName);
1055           long   size = file.length();
1056           String name = file.getName();
1057           dll  = new DLL(this, fullPathName, size, base);
1058           nameToDllMap.put(name, dll);
1059         }
1060         newLoadObjects.add(dll);
1061       }
1062 
1063       // All remaining entries in loadObjects have to be removed from
1064       // the nameToDllMap
1065       for (Iterator dllIter = loadObjects.iterator(); dllIter.hasNext(); ) {
1066         DLL dll = (DLL) dllIter.next();
1067         for (Iterator iter = nameToDllMap.keySet().iterator(); iter.hasNext(); ) {
1068           String name = (String) iter.next();
1069           if (nameToDllMap.get(name) == dll) {
1070             nameToDllMap.remove(name);
1071             break;
1072           }
1073         }
1074       }
1075 
1076       loadObjects = newLoadObjects;
1077     } catch (IOException e) {
1078       loadObjects = null;
1079       nameToDllMap = null;
1080       throw new DebuggerException(e);
1081     }
1082   }
1083 }