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 }