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