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