1 /* 2 * Copyright 2001-2002 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; 26 27 /** <P> DebuggerBase is a recommended base class for debugger 28 implementations. It can use a PageCache to cache data from the 29 target process. Note that this class would not be suitable if the 30 system were used to reflect upon itself; it would never be safe to 31 store the value in an OopHandle in anything but an OopHandle. 32 However, it provides a fair amount of code sharing to the current 33 dbx and win32 implementations. </P> 34 35 <P> NOTE that much of the code sharing is achieved by having this 36 class implement many of the methods in the Win32Debugger and 37 DbxDebugger interfaces. </P> */ 38 39 public abstract class DebuggerBase implements Debugger { 40 // May be set lazily, but must be set before calling any of the read 41 // routines below 42 protected MachineDescription machDesc; 43 protected DebuggerUtilities utils; 44 // Java primitive type sizes, set during bootstrapping. Do not call 45 // any of the Java read routines until these are set up. 46 protected long jbooleanSize; 47 protected long jbyteSize; 48 protected long jcharSize; 49 protected long jdoubleSize; 50 protected long jfloatSize; 51 protected long jintSize; 52 protected long jlongSize; 53 protected long jshortSize; 54 protected boolean javaPrimitiveTypesConfigured; 55 // Should be initialized if desired by calling initCache() 56 private PageCache cache; 57 58 // State for faster accessors that don't allocate memory on each read 59 private boolean useFastAccessors; 60 private boolean bigEndian; 61 62 // Page-fetching functionality for LRU cache 63 class Fetcher implements PageFetcher { 64 public Page fetchPage(long pageBaseAddress, long numBytes) { 65 // This assumes that if any byte is unmapped, that the entire 66 // page is. The common case, however, is that the page is 67 // mapped, so we always fetch the entire thing all at once to 68 // avoid two round-trip communications per page fetch, even 69 // though fetching of unmapped pages will be slow. 70 ReadResult res = readBytesFromProcess(pageBaseAddress, numBytes); 71 if (res.getData() == null) { 72 return new Page(pageBaseAddress, numBytes); 73 } 74 return new Page(pageBaseAddress, res.getData()); 75 } 76 } 77 78 protected DebuggerBase() { 79 } 80 81 /** From the JVMDebugger interface. This is the only public method 82 of this class. */ 83 public void configureJavaPrimitiveTypeSizes(long jbooleanSize, 84 long jbyteSize, 85 long jcharSize, 86 long jdoubleSize, 87 long jfloatSize, 88 long jintSize, 89 long jlongSize, 90 long jshortSize) { 91 this.jbooleanSize = jbooleanSize; 92 this.jbyteSize = jbyteSize; 93 this.jcharSize = jcharSize; 94 this.jdoubleSize = jdoubleSize; 95 this.jfloatSize = jfloatSize; 96 this.jintSize = jintSize; 97 this.jlongSize = jlongSize; 98 this.jshortSize = jshortSize; 99 100 if (jbooleanSize < 1) { 101 throw new RuntimeException("jboolean size is too small"); 102 } 103 104 if (jbyteSize < 1) { 105 throw new RuntimeException("jbyte size is too small"); 106 } 107 108 if (jcharSize < 2) { 109 throw new RuntimeException("jchar size is too small"); 110 } 111 112 if (jdoubleSize < 8) { 113 throw new RuntimeException("jdouble size is too small"); 114 } 115 116 if (jfloatSize < 4) { 117 throw new RuntimeException("jfloat size is too small"); 118 } 119 120 if (jintSize < 4) { 121 throw new RuntimeException("jint size is too small"); 122 } 123 124 if (jlongSize < 8) { 125 throw new RuntimeException("jlong size is too small"); 126 } 127 128 if (jshortSize < 2) { 129 throw new RuntimeException("jshort size is too small"); 130 } 131 132 if (jintSize != jfloatSize) { 133 // If dataToJFloat were rewritten, this wouldn't be necessary 134 throw new RuntimeException("jint size and jfloat size must be equal"); 135 } 136 137 if (jlongSize != jdoubleSize) { 138 // If dataToJDouble were rewritten, this wouldn't be necessary 139 throw new RuntimeException("jlong size and jdouble size must be equal"); 140 } 141 142 useFastAccessors = 143 ((cache != null) && 144 (jbooleanSize == 1) && 145 (jbyteSize == 1) && 146 (jcharSize == 2) && 147 (jdoubleSize == 8) && 148 (jfloatSize == 4) && 149 (jintSize == 4) && 150 (jlongSize == 8) && 151 (jshortSize == 2)); 152 153 javaPrimitiveTypesConfigured = true; 154 } 155 156 /** May be called by subclasses if desired to initialize the page 157 cache but may not be overridden */ 158 protected final void initCache(long pageSize, long maxNumPages) { 159 cache = new PageCache(pageSize, maxNumPages, new Fetcher()); 160 if (machDesc != null) { 161 bigEndian = machDesc.isBigEndian(); 162 } 163 } 164 165 /** May be called by subclasses if needed (if the machine 166 description is not available at the time of cache 167 initialization, as on Solaris) but may not be overridden */ 168 protected final void setBigEndian(boolean bigEndian) { 169 this.bigEndian = bigEndian; 170 } 171 172 /** May be called by subclasses to clear out the cache but may not 173 be overridden. For convenience, this can be called even if the 174 cache has not been initialized. */ 175 protected final void clearCache() { 176 if (cache != null) { 177 cache.clear(); 178 } 179 } 180 181 /** May be called by subclasses to disable the cache (for example, 182 when the target process has been resumed) but may not be 183 overridden. For convenience, this can be called even if the 184 cache has not been initialized. */ 185 protected final void disableCache() { 186 if (cache != null) { 187 cache.disable(); 188 } 189 } 190 191 /** May be called by subclasses to re-enable the cache (for example, 192 when the target process has been suspended) but may not be 193 overridden. For convenience, this can be called even if the 194 cache has not been initialized. */ 195 protected final void enableCache() { 196 if (cache != null) { 197 cache.enable(); 198 } 199 } 200 201 /** May be called by subclasses directly but may not be overridden */ 202 protected final byte[] readBytes(long address, long numBytes) 203 throws UnmappedAddressException, DebuggerException { 204 if (cache != null) { 205 return cache.getData(address, numBytes); 206 } else { 207 ReadResult res = readBytesFromProcess(address, numBytes); 208 if (res.getData() != null) { 209 return res.getData(); 210 } 211 throw new UnmappedAddressException(res.getFailureAddress()); 212 } 213 } 214 215 /** May be called by subclasses directly but may not be overridden */ 216 protected final void writeBytes(long address, long numBytes, byte[] data) 217 throws UnmappedAddressException, DebuggerException { 218 if (cache != null) { 219 cache.clear(address, numBytes); 220 } 221 writeBytesToProcess(address, numBytes, data); 222 } 223 224 public boolean readJBoolean(long address) 225 throws UnmappedAddressException, UnalignedAddressException { 226 checkJavaConfigured(); 227 utils.checkAlignment(address, jbooleanSize); 228 if (useFastAccessors) { 229 return (cache.getByte(address) != 0); 230 } else { 231 byte[] data = readBytes(address, jbooleanSize); 232 return utils.dataToJBoolean(data, jbooleanSize); 233 } 234 } 235 236 public byte readJByte(long address) 237 throws UnmappedAddressException, UnalignedAddressException { 238 checkJavaConfigured(); 239 utils.checkAlignment(address, jbyteSize); 240 if (useFastAccessors) { 241 return cache.getByte(address); 242 } else { 243 byte[] data = readBytes(address, jbyteSize); 244 return utils.dataToJByte(data, jbyteSize); 245 } 246 } 247 248 // NOTE: assumes value does not span pages (may be bad assumption on 249 // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy) 250 public char readJChar(long address) 251 throws UnmappedAddressException, UnalignedAddressException { 252 checkJavaConfigured(); 253 utils.checkAlignment(address, jcharSize); 254 if (useFastAccessors) { 255 return cache.getChar(address, bigEndian); 256 } else { 257 byte[] data = readBytes(address, jcharSize); 258 return (char) utils.dataToJChar(data, jcharSize); 259 } 260 } 261 262 // NOTE: assumes value does not span pages (may be bad assumption on 263 // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy) 264 public double readJDouble(long address) 265 throws UnmappedAddressException, UnalignedAddressException { 266 checkJavaConfigured(); 267 utils.checkAlignment(address, jdoubleSize); 268 if (useFastAccessors) { 269 return cache.getDouble(address, bigEndian); 270 } else { 271 byte[] data = readBytes(address, jdoubleSize); 272 return utils.dataToJDouble(data, jdoubleSize); 273 } 274 } 275 276 // NOTE: assumes value does not span pages (may be bad assumption on 277 // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy) 278 public float readJFloat(long address) 279 throws UnmappedAddressException, UnalignedAddressException { 280 checkJavaConfigured(); 281 utils.checkAlignment(address, jfloatSize); 282 if (useFastAccessors) { 283 return cache.getFloat(address, bigEndian); 284 } else { 285 byte[] data = readBytes(address, jfloatSize); 286 return utils.dataToJFloat(data, jfloatSize); 287 } 288 } 289 290 // NOTE: assumes value does not span pages (may be bad assumption on 291 // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy) 292 public int readJInt(long address) 293 throws UnmappedAddressException, UnalignedAddressException { 294 checkJavaConfigured(); 295 utils.checkAlignment(address, jintSize); 296 if (useFastAccessors) { 297 return cache.getInt(address, bigEndian); 298 } else { 299 byte[] data = readBytes(address, jintSize); 300 return utils.dataToJInt(data, jintSize); 301 } 302 } 303 304 // NOTE: assumes value does not span pages (may be bad assumption on 305 // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy) 306 public long readJLong(long address) 307 throws UnmappedAddressException, UnalignedAddressException { 308 checkJavaConfigured(); 309 utils.checkAlignment(address, jlongSize); 310 if (useFastAccessors) { 311 return cache.getLong(address, bigEndian); 312 } else { 313 byte[] data = readBytes(address, jlongSize); 314 return utils.dataToJLong(data, jlongSize); 315 } 316 } 317 318 // NOTE: assumes value does not span pages (may be bad assumption on 319 // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy) 320 public short readJShort(long address) 321 throws UnmappedAddressException, UnalignedAddressException { 322 checkJavaConfigured(); 323 utils.checkAlignment(address, jshortSize); 324 if (useFastAccessors) { 325 return cache.getShort(address, bigEndian); 326 } else { 327 byte[] data = readBytes(address, jshortSize); 328 return utils.dataToJShort(data, jshortSize); 329 } 330 } 331 332 // NOTE: assumes value does not span pages (may be bad assumption on 333 // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy) 334 public long readCInteger(long address, long numBytes, boolean isUnsigned) 335 throws UnmappedAddressException, UnalignedAddressException { 336 checkConfigured(); 337 utils.checkAlignment(address, numBytes); 338 if (useFastAccessors) { 339 if (isUnsigned) { 340 switch((int) numBytes) { 341 case 1: return cache.getByte(address) & 0xFF; 342 case 2: return cache.getShort(address, bigEndian) & 0xFFFF; 343 case 4: return cache.getInt(address, bigEndian) & 0xFFFFFFFFL; 344 case 8: return cache.getLong(address, bigEndian); 345 default: { 346 byte[] data = readBytes(address, numBytes); 347 return utils.dataToCInteger(data, isUnsigned); 348 } 349 } 350 } else { 351 switch((int) numBytes) { 352 case 1: return cache.getByte(address); 353 case 2: return cache.getShort(address, bigEndian); 354 case 4: return cache.getInt(address, bigEndian); 355 case 8: return cache.getLong(address, bigEndian); 356 default: { 357 byte[] data = readBytes(address, numBytes); 358 return utils.dataToCInteger(data, isUnsigned); 359 } 360 } 361 } 362 } else { 363 byte[] data = readBytes(address, numBytes); 364 return utils.dataToCInteger(data, isUnsigned); 365 } 366 } 367 368 public void writeJBoolean(long address, boolean value) 369 throws UnmappedAddressException, UnalignedAddressException { 370 checkJavaConfigured(); 371 utils.checkAlignment(address, jbooleanSize); 372 byte[] data = utils.jbooleanToData(value); 373 writeBytes(address, jbooleanSize, data); 374 } 375 376 public void writeJByte(long address, byte value) 377 throws UnmappedAddressException, UnalignedAddressException { 378 checkJavaConfigured(); 379 utils.checkAlignment(address, jbyteSize); 380 byte[] data = utils.jbyteToData(value); 381 writeBytes(address, jbyteSize, data); 382 } 383 384 public void writeJChar(long address, char value) 385 throws UnmappedAddressException, UnalignedAddressException { 386 checkJavaConfigured(); 387 utils.checkAlignment(address, jcharSize); 388 byte[] data = utils.jcharToData(value); 389 writeBytes(address, jcharSize, data); 390 } 391 392 public void writeJDouble(long address, double value) 393 throws UnmappedAddressException, UnalignedAddressException { 394 checkJavaConfigured(); 395 utils.checkAlignment(address, jdoubleSize); 396 byte[] data = utils.jdoubleToData(value); 397 writeBytes(address, jdoubleSize, data); 398 } 399 400 public void writeJFloat(long address, float value) 401 throws UnmappedAddressException, UnalignedAddressException { 402 checkJavaConfigured(); 403 utils.checkAlignment(address, jfloatSize); 404 byte[] data = utils.jfloatToData(value); 405 writeBytes(address, jfloatSize, data); 406 } 407 408 public void writeJInt(long address, int value) 409 throws UnmappedAddressException, UnalignedAddressException { 410 checkJavaConfigured(); 411 utils.checkAlignment(address, jintSize); 412 byte[] data = utils.jintToData(value); 413 writeBytes(address, jintSize, data); 414 } 415 416 public void writeJLong(long address, long value) 417 throws UnmappedAddressException, UnalignedAddressException { 418 checkJavaConfigured(); 419 utils.checkAlignment(address, jlongSize); 420 byte[] data = utils.jlongToData(value); 421 writeBytes(address, jlongSize, data); 422 } 423 424 public void writeJShort(long address, short value) 425 throws UnmappedAddressException, UnalignedAddressException { 426 checkJavaConfigured(); 427 utils.checkAlignment(address, jshortSize); 428 byte[] data = utils.jshortToData(value); 429 writeBytes(address, jshortSize, data); 430 } 431 432 public void writeCInteger(long address, long numBytes, long value) 433 throws UnmappedAddressException, UnalignedAddressException { 434 checkConfigured(); 435 utils.checkAlignment(address, numBytes); 436 byte[] data = utils.cIntegerToData(numBytes, value); 437 writeBytes(address, numBytes, data); 438 } 439 440 protected long readAddressValue(long address) 441 throws UnmappedAddressException, UnalignedAddressException { 442 return readCInteger(address, machDesc.getAddressSize(), true); 443 } 444 445 protected void writeAddressValue(long address, long value) 446 throws UnmappedAddressException, UnalignedAddressException { 447 writeCInteger(address, machDesc.getAddressSize(), value); 448 } 449 450 /** Can be called by subclasses but can not be overridden */ 451 protected final void checkConfigured() { 452 if (machDesc == null) { 453 throw new RuntimeException("MachineDescription must have been set by this point"); 454 } 455 if (utils == null) { 456 throw new RuntimeException("DebuggerUtilities must have been set by this point"); 457 } 458 } 459 460 /** Can be called by subclasses but can not be overridden */ 461 protected final void checkJavaConfigured() { 462 checkConfigured(); 463 464 if (!javaPrimitiveTypesConfigured) { 465 throw new RuntimeException("Java primitive type sizes have not yet been configured"); 466 } 467 } 468 469 /** Possibly override page cache size with user-specified property */ 470 protected int parseCacheNumPagesProperty(int defaultNum) { 471 String cacheNumPagesString = System.getProperty("cacheNumPages"); 472 if (cacheNumPagesString != null) { 473 try { 474 return Integer.parseInt(cacheNumPagesString); 475 } catch (Exception e) { 476 System.err.println("Error parsing cacheNumPages property:"); 477 e.printStackTrace(); 478 } 479 } 480 return defaultNum; 481 } 482 483 /** Interim solution for allowing subclasses to write bytes to 484 process until we make that functionality available in the basic 485 Address interface */ 486 protected void invalidatePageCache(long startAddress, long numBytes) { 487 cache.clear(startAddress, numBytes); 488 } 489 490 public long getJBooleanSize() { 491 return jbooleanSize; 492 } 493 494 public long getJByteSize() { 495 return jbyteSize; 496 } 497 498 public long getJCharSize() { 499 return jcharSize; 500 } 501 502 public long getJDoubleSize() { 503 return jdoubleSize; 504 } 505 506 public long getJFloatSize() { 507 return jfloatSize; 508 } 509 510 public long getJIntSize() { 511 return jintSize; 512 } 513 514 public long getJLongSize() { 515 return jlongSize; 516 } 517 518 public long getJShortSize() { 519 return jshortSize; 520 } 521 }