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 heapOopSize = remoteDebugger.getHeapOopSize(); 103 } 104 catch (RemoteException e) { 105 throw new DebuggerException(e); 106 } 107 } 108 109 public long[] getThreadIntegerRegisterSet(Address addr) { 110 try { 111 return remoteDebugger.getThreadIntegerRegisterSet(getAddressValue(addr), true); 112 } 113 catch (RemoteException e) { 114 throw new DebuggerException(e); 115 } 116 } 117 118 public long[] getThreadIntegerRegisterSet(long id) { 119 try { 120 return remoteDebugger.getThreadIntegerRegisterSet(id, false); 121 } 122 catch (RemoteException e) { 123 throw new DebuggerException(e); 124 } 125 } 126 127 /** Unimplemented in this class (remote remoteDebugger should already be attached) */ 128 public boolean hasProcessList() throws DebuggerException { 129 throw new DebuggerException("Should not be called on RemoteDebuggerClient"); 130 } 131 132 /** Unimplemented in this class (remote remoteDebugger should already be attached) */ 133 public List getProcessList() throws DebuggerException { 134 throw new DebuggerException("Should not be called on RemoteDebuggerClient"); 135 } 136 137 /** Unimplemented in this class (remote remoteDebugger should already be attached) */ 138 public void attach(int processID) throws DebuggerException { 139 throw new DebuggerException("Should not be called on RemoteDebuggerClient"); 140 } 141 142 /** Unimplemented in this class (remote remoteDebugger should already be attached) */ 143 public void attach(String executableName, String coreFileName) throws DebuggerException { 144 throw new DebuggerException("Should not be called on RemoteDebuggerClient"); 145 } 146 147 /** Unimplemented in this class (remote remoteDebugger can not be detached) */ 148 public boolean detach() { 149 throw new DebuggerException("Should not be called on RemoteDebuggerClient"); 150 } 151 152 public Address parseAddress(String addressString) throws NumberFormatException { 153 long addr = utils.scanAddress(addressString); 154 if (addr == 0) { 155 return null; 156 } 157 return new RemoteAddress(this, addr); 158 } 159 160 public String getOS() throws DebuggerException { 161 try { 162 return remoteDebugger.getOS(); 163 } 164 catch (RemoteException e) { 165 throw new DebuggerException(e); 166 } 167 } 168 169 public String getCPU() { 170 try { 171 return remoteDebugger.getCPU(); 172 } 173 catch (RemoteException e) { 174 throw new DebuggerException(e); 175 } 176 } 177 178 public boolean hasConsole() throws DebuggerException { 179 try { 180 return remoteDebugger.hasConsole(); 181 } catch (RemoteException e) { 182 throw new DebuggerException(e); 183 } 184 } 185 186 public String consoleExecuteCommand(String cmd) throws DebuggerException { 187 try { 188 return remoteDebugger.consoleExecuteCommand(cmd); 189 } 190 catch (RemoteException e) { 191 throw new DebuggerException(e); 192 } 193 } 194 195 public String getConsolePrompt() throws DebuggerException { 196 try { 197 return remoteDebugger.getConsolePrompt(); 198 } catch (RemoteException e) { 199 throw new DebuggerException(e); 200 } 201 } 202 203 public CDebugger getCDebugger() throws DebuggerException { 204 return null; 205 } 206 207 //-------------------------------------------------------------------------------- 208 // Implementation of SymbolLookup interface 209 210 public Address lookup(String objectName, String symbol) { 211 try { 212 long addr = remoteDebugger.lookupInProcess(objectName, symbol); 213 if (addr == 0) { 214 return null; 215 } 216 return new RemoteAddress(this, addr); 217 } 218 catch (RemoteException e) { 219 throw new DebuggerException(e); 220 } 221 } 222 223 public OopHandle lookupOop(String objectName, String symbol) { 224 try { 225 long addr = remoteDebugger.lookupInProcess(objectName, symbol); 226 if (addr == 0) { 227 return null; 228 } 229 return new RemoteOopHandle(this, addr); 230 } 231 catch (RemoteException e) { 232 throw new DebuggerException(e); 233 } 234 } 235 236 /** Need to override this to relax alignment checks on x86. */ 237 public long readCInteger(long address, long numBytes, boolean isUnsigned) 238 throws UnmappedAddressException, UnalignedAddressException { 239 if (!unalignedAccessesOkay) { 240 utils.checkAlignment(address, numBytes); 241 } else { 242 // Only slightly relaxed semantics -- this is a hack, but is 243 // necessary on x86 where it seems the compiler is 244 // putting some global 64-bit data on 32-bit boundaries 245 if (numBytes == 8) { 246 utils.checkAlignment(address, 4); 247 } else { 248 utils.checkAlignment(address, numBytes); 249 } 250 } 251 byte[] data = readBytes(address, numBytes); 252 return utils.dataToCInteger(data, isUnsigned); 253 } 254 255 // Overridden from DebuggerBase because we need to relax alignment 256 // constraints on x86 257 public long readJLong(long address) 258 throws UnmappedAddressException, UnalignedAddressException { 259 // FIXME: allow this to be configurable. Undesirable to add a 260 // dependency on the runtime package here, though, since this 261 // package should be strictly underneath it. 262 if (unalignedAccessesOkay) { 263 utils.checkAlignment(address, jintSize); 264 } else { 265 utils.checkAlignment(address, jlongSize); 266 } 267 byte[] data = readBytes(address, jlongSize); 268 return utils.dataToJLong(data, jlongSize); 269 } 270 271 272 //-------------------------------------------------------------------------------- 273 // Implementation of JVMDebugger interface 274 // 275 276 /** Unimplemented in this class (remote remoteDebugger should already be configured) */ 277 public void configureJavaPrimitiveTypeSizes(long jbooleanSize, 278 long jbyteSize, 279 long jcharSize, 280 long jdoubleSize, 281 long jfloatSize, 282 long jintSize, 283 long jlongSize, 284 long jshortSize) { 285 throw new DebuggerException("Should not be called on RemoteDebuggerClient"); 286 } 287 288 public void setMachineDescription(MachineDescription machDesc) { 289 throw new DebuggerException("Should not be called on RemoteDebuggerClient"); 290 } 291 292 public int getRemoteProcessAddressSize() { 293 throw new DebuggerException("Should not be called on RemoteDebuggerClient"); 294 } 295 296 public String addressValueToString(long addr) { 297 return utils.addressValueToString(addr); 298 } 299 300 public long getAddressValue(Address addr) throws DebuggerException { 301 if (addr == null) return 0; 302 return ((RemoteAddress) addr).getValue(); 303 } 304 305 public Address newAddress(long value) { 306 if (value == 0) return null; 307 return new RemoteAddress(this, value); 308 } 309 310 RemoteAddress readAddress(long address) 311 throws UnmappedAddressException, UnalignedAddressException { 312 long value = readAddressValue(address); 313 return (value == 0 ? null : new RemoteAddress(this, value)); 314 } 315 316 RemoteAddress readCompOopAddress(long address) 317 throws UnmappedAddressException, UnalignedAddressException { 318 long value = readCompOopAddressValue(address); 319 return (value == 0 ? null : new RemoteAddress(this, value)); 320 } 321 322 RemoteOopHandle readOopHandle(long address) 323 throws UnmappedAddressException, UnalignedAddressException, NotInHeapException { 324 long value = readAddressValue(address); 325 return (value == 0 ? null : new RemoteOopHandle(this, value)); 326 } 327 328 RemoteOopHandle readCompOopHandle(long address) 329 throws UnmappedAddressException, UnalignedAddressException, NotInHeapException { 330 long value = readCompOopAddressValue(address); 331 return (value == 0 ? null : new RemoteOopHandle(this, value)); 332 } 333 334 boolean areThreadsEqual(Address addr1, Address addr2) { 335 try { 336 return remoteDebugger.areThreadsEqual(getAddressValue(addr1), true, 337 getAddressValue(addr2), true); 338 } catch (RemoteException e) { 339 } 340 return false; 341 } 342 343 boolean areThreadsEqual(long id1, long id2) { 344 try { 345 return remoteDebugger.areThreadsEqual(id1, false, id2, false); 346 } catch (RemoteException e) { 347 } 348 return false; 349 } 350 351 boolean areThreadsEqual(Address addr1, long id2) { 352 try { 353 return remoteDebugger.areThreadsEqual(getAddressValue(addr1), true, id2, false); 354 } catch (RemoteException e) { 355 } 356 return false; 357 } 358 359 boolean areThreadsEqual(long id1, Address addr2) { 360 try { 361 return remoteDebugger.areThreadsEqual(id1, false, getAddressValue(addr2), true); 362 } catch (RemoteException e) { 363 } 364 return false; 365 } 366 367 int getThreadHashCode(Address a) { 368 try { 369 return remoteDebugger.getThreadHashCode(getAddressValue(a), true); 370 } catch (RemoteException e) { 371 } 372 return a.hashCode(); 373 } 374 375 int getThreadHashCode(long id) { 376 try { 377 return remoteDebugger.getThreadHashCode(id, false); 378 } catch (RemoteException e) { 379 } 380 return (int) id; 381 } 382 383 public ThreadProxy getThreadForIdentifierAddress(Address addr) { 384 return threadFactory.createThreadWrapper(addr); 385 } 386 387 public ThreadProxy getThreadForThreadId(long id) { 388 return threadFactory.createThreadWrapper(id); 389 } 390 391 public MachineDescription getMachineDescription() throws DebuggerException { 392 return machDesc; 393 } 394 395 /** This reads bytes from the remote process. */ 396 public ReadResult readBytesFromProcess(long address, long numBytes) { 397 try { 398 return remoteDebugger.readBytesFromProcess(address, numBytes); 399 } 400 catch (RemoteException e) { 401 throw new DebuggerException(e); 402 } 403 } 404 405 public void writeBytesToProcess(long a, long b, byte[] c) { 406 throw new DebuggerException("Unimplemented!"); 407 } 408 }