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