diff agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children ba764ed4b6f2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/DebuggerBase.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,521 @@
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger;
+
+/** <P> DebuggerBase is a recommended base class for debugger
+    implementations. It can use a PageCache to cache data from the
+    target process. Note that this class would not be suitable if the
+    system were used to reflect upon itself; it would never be safe to
+    store the value in an OopHandle in anything but an OopHandle.
+    However, it provides a fair amount of code sharing to the current
+    dbx and win32 implementations. </P>
+
+    <P> NOTE that much of the code sharing is achieved by having this
+    class implement many of the methods in the Win32Debugger and
+    DbxDebugger interfaces. </P> */
+
+public abstract class DebuggerBase implements Debugger {
+  // May be set lazily, but must be set before calling any of the read
+  // routines below
+  protected MachineDescription machDesc;
+  protected DebuggerUtilities utils;
+  // Java primitive type sizes, set during bootstrapping. Do not call
+  // any of the Java read routines until these are set up.
+  protected long jbooleanSize;
+  protected long jbyteSize;
+  protected long jcharSize;
+  protected long jdoubleSize;
+  protected long jfloatSize;
+  protected long jintSize;
+  protected long jlongSize;
+  protected long jshortSize;
+  protected boolean javaPrimitiveTypesConfigured;
+  // Should be initialized if desired by calling initCache()
+  private PageCache cache;
+
+  // State for faster accessors that don't allocate memory on each read
+  private boolean useFastAccessors;
+  private boolean bigEndian;
+
+  // Page-fetching functionality for LRU cache
+  class Fetcher implements PageFetcher {
+    public Page fetchPage(long pageBaseAddress, long numBytes) {
+      // This assumes that if any byte is unmapped, that the entire
+      // page is. The common case, however, is that the page is
+      // mapped, so we always fetch the entire thing all at once to
+      // avoid two round-trip communications per page fetch, even
+      // though fetching of unmapped pages will be slow.
+      ReadResult res = readBytesFromProcess(pageBaseAddress, numBytes);
+      if (res.getData() == null) {
+        return new Page(pageBaseAddress, numBytes);
+      }
+      return new Page(pageBaseAddress, res.getData());
+    }
+  }
+
+  protected DebuggerBase() {
+  }
+
+  /** From the JVMDebugger interface. This is the only public method
+      of this class. */
+  public void configureJavaPrimitiveTypeSizes(long jbooleanSize,
+                                              long jbyteSize,
+                                              long jcharSize,
+                                              long jdoubleSize,
+                                              long jfloatSize,
+                                              long jintSize,
+                                              long jlongSize,
+                                              long jshortSize) {
+    this.jbooleanSize = jbooleanSize;
+    this.jbyteSize = jbyteSize;
+    this.jcharSize = jcharSize;
+    this.jdoubleSize = jdoubleSize;
+    this.jfloatSize = jfloatSize;
+    this.jintSize = jintSize;
+    this.jlongSize = jlongSize;
+    this.jshortSize = jshortSize;
+
+    if (jbooleanSize < 1) {
+      throw new RuntimeException("jboolean size is too small");
+    }
+
+    if (jbyteSize < 1) {
+      throw new RuntimeException("jbyte size is too small");
+    }
+
+    if (jcharSize < 2) {
+      throw new RuntimeException("jchar size is too small");
+    }
+
+    if (jdoubleSize < 8) {
+      throw new RuntimeException("jdouble size is too small");
+    }
+
+    if (jfloatSize < 4) {
+      throw new RuntimeException("jfloat size is too small");
+    }
+
+    if (jintSize < 4) {
+      throw new RuntimeException("jint size is too small");
+    }
+
+    if (jlongSize < 8) {
+      throw new RuntimeException("jlong size is too small");
+    }
+
+    if (jshortSize < 2) {
+      throw new RuntimeException("jshort size is too small");
+    }
+
+    if (jintSize != jfloatSize) {
+      // If dataToJFloat were rewritten, this wouldn't be necessary
+      throw new RuntimeException("jint size and jfloat size must be equal");
+    }
+
+    if (jlongSize != jdoubleSize) {
+      // If dataToJDouble were rewritten, this wouldn't be necessary
+      throw new RuntimeException("jlong size and jdouble size must be equal");
+    }
+
+    useFastAccessors =
+      ((cache != null) &&
+       (jbooleanSize == 1) &&
+       (jbyteSize    == 1) &&
+       (jcharSize    == 2) &&
+       (jdoubleSize  == 8) &&
+       (jfloatSize   == 4) &&
+       (jintSize     == 4) &&
+       (jlongSize    == 8) &&
+       (jshortSize   == 2));
+
+    javaPrimitiveTypesConfigured = true;
+  }
+
+  /** May be called by subclasses if desired to initialize the page
+      cache but may not be overridden */
+  protected final void initCache(long pageSize, long maxNumPages) {
+    cache = new PageCache(pageSize, maxNumPages, new Fetcher());
+    if (machDesc != null) {
+      bigEndian = machDesc.isBigEndian();
+    }
+  }
+
+  /** May be called by subclasses if needed (if the machine
+      description is not available at the time of cache
+      initialization, as on Solaris) but may not be overridden */
+  protected final void setBigEndian(boolean bigEndian) {
+    this.bigEndian = bigEndian;
+  }
+
+  /** May be called by subclasses to clear out the cache but may not
+      be overridden. For convenience, this can be called even if the
+      cache has not been initialized. */
+  protected final void clearCache() {
+    if (cache != null) {
+      cache.clear();
+    }
+  }
+
+  /** May be called by subclasses to disable the cache (for example,
+      when the target process has been resumed) but may not be
+      overridden. For convenience, this can be called even if the
+      cache has not been initialized. */
+  protected final void disableCache() {
+    if (cache != null) {
+      cache.disable();
+    }
+  }
+
+  /** May be called by subclasses to re-enable the cache (for example,
+      when the target process has been suspended) but may not be
+      overridden. For convenience, this can be called even if the
+      cache has not been initialized. */
+  protected final void enableCache() {
+    if (cache != null) {
+      cache.enable();
+    }
+  }
+
+  /** May be called by subclasses directly but may not be overridden */
+  protected final byte[] readBytes(long address, long numBytes)
+    throws UnmappedAddressException, DebuggerException {
+    if (cache != null) {
+      return cache.getData(address, numBytes);
+    } else {
+      ReadResult res = readBytesFromProcess(address, numBytes);
+      if (res.getData() != null) {
+        return res.getData();
+      }
+      throw new UnmappedAddressException(res.getFailureAddress());
+    }
+  }
+
+  /** May be called by subclasses directly but may not be overridden */
+  protected final void writeBytes(long address, long numBytes, byte[] data)
+    throws UnmappedAddressException, DebuggerException {
+    if (cache != null) {
+      cache.clear(address, numBytes);
+    }
+    writeBytesToProcess(address, numBytes, data);
+  }
+
+  public boolean readJBoolean(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jbooleanSize);
+    if (useFastAccessors) {
+      return (cache.getByte(address) != 0);
+    } else {
+      byte[] data = readBytes(address, jbooleanSize);
+      return utils.dataToJBoolean(data, jbooleanSize);
+    }
+  }
+
+  public byte readJByte(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jbyteSize);
+    if (useFastAccessors) {
+      return cache.getByte(address);
+    } else {
+      byte[] data = readBytes(address, jbyteSize);
+      return utils.dataToJByte(data, jbyteSize);
+    }
+  }
+
+  // NOTE: assumes value does not span pages (may be bad assumption on
+  // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
+  public char readJChar(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jcharSize);
+    if (useFastAccessors) {
+      return cache.getChar(address, bigEndian);
+    } else {
+      byte[] data = readBytes(address, jcharSize);
+      return (char) utils.dataToJChar(data, jcharSize);
+    }
+  }
+
+  // NOTE: assumes value does not span pages (may be bad assumption on
+  // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
+  public double readJDouble(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jdoubleSize);
+    if (useFastAccessors) {
+      return cache.getDouble(address, bigEndian);
+    } else {
+      byte[] data = readBytes(address, jdoubleSize);
+      return utils.dataToJDouble(data, jdoubleSize);
+    }
+  }
+
+  // NOTE: assumes value does not span pages (may be bad assumption on
+  // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
+  public float readJFloat(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jfloatSize);
+    if (useFastAccessors) {
+      return cache.getFloat(address, bigEndian);
+    } else {
+      byte[] data = readBytes(address, jfloatSize);
+      return utils.dataToJFloat(data, jfloatSize);
+    }
+  }
+
+  // NOTE: assumes value does not span pages (may be bad assumption on
+  // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
+  public int readJInt(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jintSize);
+    if (useFastAccessors) {
+      return cache.getInt(address, bigEndian);
+    } else {
+      byte[] data = readBytes(address, jintSize);
+      return utils.dataToJInt(data, jintSize);
+    }
+  }
+
+  // NOTE: assumes value does not span pages (may be bad assumption on
+  // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
+  public long readJLong(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jlongSize);
+    if (useFastAccessors) {
+      return cache.getLong(address, bigEndian);
+    } else {
+      byte[] data = readBytes(address, jlongSize);
+      return utils.dataToJLong(data, jlongSize);
+    }
+  }
+
+  // NOTE: assumes value does not span pages (may be bad assumption on
+  // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
+  public short readJShort(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jshortSize);
+    if (useFastAccessors) {
+      return cache.getShort(address, bigEndian);
+    } else {
+      byte[] data = readBytes(address, jshortSize);
+      return utils.dataToJShort(data, jshortSize);
+    }
+  }
+
+  // NOTE: assumes value does not span pages (may be bad assumption on
+  // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
+  public long readCInteger(long address, long numBytes, boolean isUnsigned)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkConfigured();
+    utils.checkAlignment(address, numBytes);
+    if (useFastAccessors) {
+      if (isUnsigned) {
+        switch((int) numBytes) {
+        case 1: return cache.getByte(address) & 0xFF;
+        case 2: return cache.getShort(address, bigEndian) & 0xFFFF;
+        case 4: return cache.getInt(address, bigEndian) & 0xFFFFFFFFL;
+        case 8: return cache.getLong(address, bigEndian);
+        default: {
+          byte[] data = readBytes(address, numBytes);
+          return utils.dataToCInteger(data, isUnsigned);
+        }
+        }
+      } else {
+        switch((int) numBytes) {
+        case 1: return cache.getByte(address);
+        case 2: return cache.getShort(address, bigEndian);
+        case 4: return cache.getInt(address, bigEndian);
+        case 8: return cache.getLong(address, bigEndian);
+        default: {
+          byte[] data = readBytes(address, numBytes);
+          return utils.dataToCInteger(data, isUnsigned);
+        }
+        }
+      }
+    } else {
+      byte[] data = readBytes(address, numBytes);
+      return utils.dataToCInteger(data, isUnsigned);
+    }
+  }
+
+  public void writeJBoolean(long address, boolean value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jbooleanSize);
+    byte[] data = utils.jbooleanToData(value);
+    writeBytes(address, jbooleanSize, data);
+  }
+
+  public void writeJByte(long address, byte value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jbyteSize);
+    byte[] data = utils.jbyteToData(value);
+    writeBytes(address, jbyteSize, data);
+  }
+
+  public void writeJChar(long address, char value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jcharSize);
+    byte[] data = utils.jcharToData(value);
+    writeBytes(address, jcharSize, data);
+  }
+
+  public void writeJDouble(long address, double value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jdoubleSize);
+    byte[] data = utils.jdoubleToData(value);
+    writeBytes(address, jdoubleSize, data);
+  }
+
+  public void writeJFloat(long address, float value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jfloatSize);
+    byte[] data = utils.jfloatToData(value);
+    writeBytes(address, jfloatSize, data);
+  }
+
+  public void writeJInt(long address, int value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jintSize);
+    byte[] data = utils.jintToData(value);
+    writeBytes(address, jintSize, data);
+  }
+
+  public void writeJLong(long address, long value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jlongSize);
+    byte[] data = utils.jlongToData(value);
+    writeBytes(address, jlongSize, data);
+  }
+
+  public void writeJShort(long address, short value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkJavaConfigured();
+    utils.checkAlignment(address, jshortSize);
+    byte[] data = utils.jshortToData(value);
+    writeBytes(address, jshortSize, data);
+  }
+
+  public void writeCInteger(long address, long numBytes, long value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    checkConfigured();
+    utils.checkAlignment(address, numBytes);
+    byte[] data = utils.cIntegerToData(numBytes, value);
+    writeBytes(address, numBytes, data);
+  }
+
+  protected long readAddressValue(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+    return readCInteger(address, machDesc.getAddressSize(), true);
+  }
+
+  protected void writeAddressValue(long address, long value)
+    throws UnmappedAddressException, UnalignedAddressException {
+    writeCInteger(address, machDesc.getAddressSize(), value);
+  }
+
+  /** Can be called by subclasses but can not be overridden */
+  protected final void checkConfigured() {
+    if (machDesc == null) {
+      throw new RuntimeException("MachineDescription must have been set by this point");
+    }
+    if (utils == null) {
+      throw new RuntimeException("DebuggerUtilities must have been set by this point");
+    }
+  }
+
+  /** Can be called by subclasses but can not be overridden */
+  protected final void checkJavaConfigured() {
+    checkConfigured();
+
+    if (!javaPrimitiveTypesConfigured) {
+      throw new RuntimeException("Java primitive type sizes have not yet been configured");
+    }
+  }
+
+  /** Possibly override page cache size with user-specified property */
+  protected int parseCacheNumPagesProperty(int defaultNum) {
+    String cacheNumPagesString = System.getProperty("cacheNumPages");
+    if (cacheNumPagesString != null) {
+      try {
+        return Integer.parseInt(cacheNumPagesString);
+      } catch (Exception e) {
+        System.err.println("Error parsing cacheNumPages property:");
+        e.printStackTrace();
+      }
+    }
+    return defaultNum;
+  }
+
+  /** Interim solution for allowing subclasses to write bytes to
+      process until we make that functionality available in the basic
+      Address interface */
+  protected void invalidatePageCache(long startAddress, long numBytes) {
+    cache.clear(startAddress, numBytes);
+  }
+
+  public long getJBooleanSize() {
+    return jbooleanSize;
+  }
+
+  public long getJByteSize() {
+    return jbyteSize;
+  }
+
+  public long getJCharSize() {
+    return jcharSize;
+  }
+
+  public long getJDoubleSize() {
+    return jdoubleSize;
+  }
+
+  public long getJFloatSize() {
+    return jfloatSize;
+  }
+
+  public long getJIntSize() {
+    return jintSize;
+  }
+
+  public long getJLongSize() {
+    return jlongSize;
+  }
+
+  public long getJShortSize() {
+    return jshortSize;
+  }
+}