1 /*
   2  * Copyright 2002-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.remote;
  26 
  27 import java.rmi.*;
  28 import java.util.*;
  29 
  30 import sun.jvm.hotspot.debugger.*;
  31 import sun.jvm.hotspot.debugger.cdbg.*;
  32 import sun.jvm.hotspot.debugger.remote.sparc.*;
  33 import sun.jvm.hotspot.debugger.remote.x86.*;
  34 import sun.jvm.hotspot.debugger.remote.amd64.*;
  35 
  36 /** An implementation of Debugger which wraps a
  37     RemoteDebugger, providing remote debugging via RMI.
  38     This implementation provides caching of the remote process's
  39     address space on the local machine where the user interface is
  40     running. */
  41 
  42 public class RemoteDebuggerClient extends DebuggerBase implements JVMDebugger {
  43   private RemoteDebugger remoteDebugger;
  44   private RemoteThreadFactory threadFactory;
  45   private boolean unalignedAccessesOkay = false;
  46   private static final int cacheSize = 16 * 1024 * 1024; // 16 MB
  47   
  48   public RemoteDebuggerClient(RemoteDebugger remoteDebugger) throws DebuggerException {
  49     super();
  50     try {
  51       this.remoteDebugger = remoteDebugger;
  52       machDesc = remoteDebugger.getMachineDescription();
  53       utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian());
  54       int cacheNumPages;
  55       int cachePageSize;
  56       String cpu = remoteDebugger.getCPU();
  57       // page size. (FIXME: should pick this up from the remoteDebugger.)
  58       if (cpu.equals("sparc")) {
  59         threadFactory = new RemoteSPARCThreadFactory(this);
  60         cachePageSize = 8192;
  61         cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
  62       } else if (cpu.equals("x86")) {
  63         threadFactory = new RemoteX86ThreadFactory(this);
  64         cachePageSize = 4096;
  65         cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
  66         unalignedAccessesOkay = true;
  67       } else if (cpu.equals("amd64")) {
  68         threadFactory = new RemoteAMD64ThreadFactory(this);
  69         cachePageSize = 4096;
  70         cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
  71         unalignedAccessesOkay = true;
  72       } else {
  73         throw new DebuggerException("Thread access for CPU architecture " + cpu + " not yet supported");
  74       }
  75 
  76       // Cache portion of the remote process's address space.
  77       initCache(cachePageSize, cacheNumPages);
  78 
  79       jbooleanSize = remoteDebugger.getJBooleanSize();
  80       jbyteSize    = remoteDebugger.getJByteSize();
  81       jcharSize    = remoteDebugger.getJCharSize();
  82       jdoubleSize  = remoteDebugger.getJDoubleSize();
  83       jfloatSize   = remoteDebugger.getJFloatSize();
  84       jintSize     = remoteDebugger.getJIntSize();
  85       jlongSize    = remoteDebugger.getJLongSize();
  86       jshortSize   = remoteDebugger.getJShortSize();
  87       javaPrimitiveTypesConfigured = true;
  88     }
  89     catch (RemoteException e) {
  90       throw new DebuggerException(e);
  91     }
  92   }
  93 
  94   public long[] getThreadIntegerRegisterSet(Address addr) {
  95     try {
  96       return remoteDebugger.getThreadIntegerRegisterSet(getAddressValue(addr), true);
  97     }
  98     catch (RemoteException e) {
  99       throw new DebuggerException(e);
 100     }
 101   }
 102 
 103   public long[] getThreadIntegerRegisterSet(long id) {
 104     try {
 105       return remoteDebugger.getThreadIntegerRegisterSet(id, false);
 106     }
 107     catch (RemoteException e) {
 108       throw new DebuggerException(e);
 109     }
 110   }
 111 
 112   /** Unimplemented in this class (remote remoteDebugger should already be attached) */
 113   public boolean hasProcessList() throws DebuggerException {
 114     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
 115   }
 116 
 117   /** Unimplemented in this class (remote remoteDebugger should already be attached) */
 118   public List getProcessList() throws DebuggerException {
 119     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
 120   }
 121 
 122   /** Unimplemented in this class (remote remoteDebugger should already be attached) */
 123   public void attach(int processID) throws DebuggerException {
 124     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
 125   }
 126 
 127   /** Unimplemented in this class (remote remoteDebugger should already be attached) */
 128   public void attach(String executableName, String coreFileName) throws DebuggerException {
 129     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
 130   }
 131 
 132   /** Unimplemented in this class (remote remoteDebugger can not be detached) */
 133   public boolean detach() {
 134     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
 135   }
 136 
 137   public Address parseAddress(String addressString) throws NumberFormatException {
 138     long addr = utils.scanAddress(addressString);
 139     if (addr == 0) {
 140       return null;
 141     }
 142     return new RemoteAddress(this, addr);
 143   }
 144 
 145   public String getOS() throws DebuggerException {
 146     try {
 147       return remoteDebugger.getOS();
 148     }
 149     catch (RemoteException e) {
 150       throw new DebuggerException(e);
 151     }
 152   }
 153 
 154   public String getCPU() {
 155     try {
 156       return remoteDebugger.getCPU();
 157     }
 158     catch (RemoteException e) {
 159       throw new DebuggerException(e);
 160     }
 161   }
 162 
 163   public boolean hasConsole() throws DebuggerException {
 164     try {
 165        return remoteDebugger.hasConsole();
 166     } catch (RemoteException e) {
 167        throw new DebuggerException(e);
 168     }
 169   }
 170 
 171   public String consoleExecuteCommand(String cmd) throws DebuggerException {
 172     try {
 173       return remoteDebugger.consoleExecuteCommand(cmd);
 174     }
 175     catch (RemoteException e) {
 176       throw new DebuggerException(e);
 177     }
 178   }
 179 
 180   public String getConsolePrompt() throws DebuggerException {
 181     try {
 182       return remoteDebugger.getConsolePrompt();
 183     } catch (RemoteException e) {
 184       throw new DebuggerException(e);
 185     }
 186   }
 187 
 188   public CDebugger getCDebugger() throws DebuggerException {
 189     return null;
 190   }
 191 
 192   //--------------------------------------------------------------------------------
 193   // Implementation of SymbolLookup interface
 194 
 195   public Address lookup(String objectName, String symbol) {
 196     try {
 197       long addr = remoteDebugger.lookupInProcess(objectName, symbol);
 198       if (addr == 0) {
 199         return null;
 200       }
 201       return new RemoteAddress(this, addr);
 202     }
 203     catch (RemoteException e) {
 204       throw new DebuggerException(e);
 205     }
 206   }
 207 
 208   public OopHandle lookupOop(String objectName, String symbol) {
 209     try {
 210       long addr = remoteDebugger.lookupInProcess(objectName, symbol);
 211       if (addr == 0) {
 212         return null;
 213       }
 214       return new RemoteOopHandle(this, addr);
 215     }
 216     catch (RemoteException e) {
 217       throw new DebuggerException(e);
 218     }
 219   }
 220 
 221   /** Need to override this to relax alignment checks on x86. */
 222   public long readCInteger(long address, long numBytes, boolean isUnsigned)
 223     throws UnmappedAddressException, UnalignedAddressException {
 224     if (!unalignedAccessesOkay) {
 225       utils.checkAlignment(address, numBytes);
 226     } else {
 227       // Only slightly relaxed semantics -- this is a hack, but is
 228       // necessary on x86 where it seems the compiler is
 229       // putting some global 64-bit data on 32-bit boundaries
 230       if (numBytes == 8) {
 231         utils.checkAlignment(address, 4);
 232       } else {
 233         utils.checkAlignment(address, numBytes);
 234       }
 235     }
 236     byte[] data = readBytes(address, numBytes);
 237     return utils.dataToCInteger(data, isUnsigned);
 238   }
 239 
 240   // Overridden from DebuggerBase because we need to relax alignment
 241   // constraints on x86
 242   public long readJLong(long address)
 243     throws UnmappedAddressException, UnalignedAddressException {
 244     // FIXME: allow this to be configurable. Undesirable to add a
 245     // dependency on the runtime package here, though, since this
 246     // package should be strictly underneath it.
 247     if (unalignedAccessesOkay) {
 248       utils.checkAlignment(address, jintSize);
 249     } else {
 250       utils.checkAlignment(address, jlongSize);
 251     }
 252     byte[] data = readBytes(address, jlongSize);
 253     return utils.dataToJLong(data, jlongSize);
 254   }
 255 
 256 
 257   //--------------------------------------------------------------------------------
 258   // Implementation of JVMDebugger interface
 259   //
 260 
 261   /** Unimplemented in this class (remote remoteDebugger should already be configured) */
 262   public void configureJavaPrimitiveTypeSizes(long jbooleanSize,
 263                                               long jbyteSize,
 264                                               long jcharSize,
 265                                               long jdoubleSize,
 266                                               long jfloatSize,
 267                                               long jintSize,
 268                                               long jlongSize,
 269                                               long jshortSize) {
 270     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
 271   }
 272 
 273   public void setMachineDescription(MachineDescription machDesc) {
 274     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
 275   }
 276   
 277   public int getRemoteProcessAddressSize() {
 278     throw new DebuggerException("Should not be called on RemoteDebuggerClient");
 279   }
 280 
 281   public String addressValueToString(long addr) {
 282     return utils.addressValueToString(addr);
 283   }
 284 
 285   public long getAddressValue(Address addr) throws DebuggerException {
 286     if (addr == null) return 0;
 287     return ((RemoteAddress) addr).getValue();
 288   }
 289 
 290   public Address newAddress(long value) {
 291     if (value == 0) return null;
 292     return new RemoteAddress(this, value);
 293   }
 294 
 295   RemoteAddress readAddress(long address)
 296     throws UnmappedAddressException, UnalignedAddressException {
 297     long value = readAddressValue(address);
 298     return (value == 0 ? null : new RemoteAddress(this, value));
 299   }
 300 
 301   RemoteOopHandle readOopHandle(long address)
 302     throws UnmappedAddressException, UnalignedAddressException, NotInHeapException {
 303     long value = readAddressValue(address);
 304     return (value == 0 ? null : new RemoteOopHandle(this, value));
 305   }
 306 
 307   boolean areThreadsEqual(Address addr1, Address addr2) {
 308     try {
 309        return remoteDebugger.areThreadsEqual(getAddressValue(addr1), true,
 310                                              getAddressValue(addr2), true);
 311     } catch (RemoteException e) {
 312     }
 313     return false;
 314   }
 315 
 316   boolean areThreadsEqual(long id1, long id2) {
 317     try {
 318        return remoteDebugger.areThreadsEqual(id1, false, id2, false);
 319     } catch (RemoteException e) {
 320     }
 321     return false;
 322   }
 323 
 324   boolean areThreadsEqual(Address addr1, long id2) {
 325     try {
 326        return remoteDebugger.areThreadsEqual(getAddressValue(addr1), true, id2, false);
 327     } catch (RemoteException e) {
 328     }
 329     return false;
 330   }
 331 
 332   boolean areThreadsEqual(long id1, Address addr2) {
 333     try {
 334        return remoteDebugger.areThreadsEqual(id1, false, getAddressValue(addr2), true);
 335     } catch (RemoteException e) {
 336     }
 337     return false;
 338   }
 339 
 340   int getThreadHashCode(Address a) {
 341     try {
 342        return remoteDebugger.getThreadHashCode(getAddressValue(a), true);
 343     } catch (RemoteException e) {
 344     }
 345     return a.hashCode();
 346   }
 347 
 348   int getThreadHashCode(long id) {
 349     try {
 350        return remoteDebugger.getThreadHashCode(id, false);
 351     } catch (RemoteException e) {
 352     }
 353     return (int) id;
 354   }
 355 
 356   public ThreadProxy getThreadForIdentifierAddress(Address addr) {
 357      return threadFactory.createThreadWrapper(addr);
 358   }
 359 
 360   public ThreadProxy getThreadForThreadId(long id) {
 361      return threadFactory.createThreadWrapper(id);
 362   }
 363 
 364   public MachineDescription getMachineDescription() throws DebuggerException {
 365      return machDesc;
 366   }
 367 
 368   /** This reads bytes from the remote process. */
 369   public ReadResult readBytesFromProcess(long address, long numBytes) {
 370     try {
 371       return remoteDebugger.readBytesFromProcess(address, numBytes);
 372     }
 373     catch (RemoteException e) {
 374       throw new DebuggerException(e);
 375     }
 376   }
 377 
 378   public void writeBytesToProcess(long a, long b, byte[] c) {
 379      throw new DebuggerException("Unimplemented!");
 380   }
 381 }