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 }