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