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