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 }