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