You are viewing a plain text version of this content. The canonical link for it is here.
Posted to kato-commits@incubator.apache.org by cc...@apache.org on 2009/03/16 16:43:31 UTC
svn commit: r754949 [2/5] - in
/incubator/kato/trunk/import/org.apache.kato.tools.katoview: ./ .settings/
src/ src/com/ src/com/ibm/ src/com/ibm/dtfj/ src/com/ibm/dtfj/dtfjview/
src/com/ibm/dtfj/dtfjview/commands/ src/com/ibm/dtfj/dtfjview/commands/hel...
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/HeapdumpCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/HeapdumpCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/HeapdumpCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/HeapdumpCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,878 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.Stack;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.dtfjview.heapdump.HeapDumpFormatter;
+import com.ibm.dtfj.dtfjview.heapdump.HeapDumpSettings;
+import com.ibm.dtfj.dtfjview.heapdump.LongListReferenceIterator;
+import com.ibm.dtfj.dtfjview.heapdump.ReferenceIterator;
+import com.ibm.dtfj.dtfjview.heapdump.classic.ClassicHeapDumpFormatter;
+import com.ibm.dtfj.image.CorruptData;
+import com.ibm.dtfj.image.CorruptDataException;
+import com.ibm.dtfj.image.DTFJException;
+import com.ibm.dtfj.image.DataUnavailable;
+import com.ibm.dtfj.image.Image;
+import com.ibm.dtfj.image.ImageAddressSpace;
+import com.ibm.dtfj.image.ImageProcess;
+import com.ibm.dtfj.image.MemoryAccessException;
+import com.ibm.dtfj.java.JavaClass;
+import com.ibm.dtfj.java.JavaClassLoader;
+import com.ibm.dtfj.java.JavaField;
+import com.ibm.dtfj.java.JavaHeap;
+import com.ibm.dtfj.java.JavaObject;
+import com.ibm.dtfj.java.JavaRuntime;
+
+/**
+ * Command for dumping heapdumps from DTFJ.
+ *
+ * Contains the heap-walking logic for building the reference tree. The code for writing the heapdumps
+ * is in the com.ibm.jvm.heapdump package.
+ *
+ */
+public class HeapdumpCommand extends Command
+{
+ public static final String COMMAND_NAME = "heapdump";
+ public static final String DESCRIPTION = "generates a heapdump";
+ public static final String LONG_DESCRIPTION = "Parameters: [heapname+]\n\n"
+ + "\t[heapname+] - space-separated name of heap or heaps to dump. Use \"info heap\" to get the list of heap names. Default: all heaps are dumped.\n\n"
+ + "Writes a heapdump from the memory image.\n"
+ + "The file name and format are controlled using the \"set heapdump\" command; the current settings "
+ + "can be displayed using \"show heapdump\".\n";
+
+ private static final String PROTECTION_DOMAIN_FIELD_NAME = "protectionDomain";
+ /**
+ * Regexp pattern used to extract a subset of the versions string
+ */
+ private static final Pattern J9_VERSION_PATTERN = Pattern.compile("(IBM J9 VM.*?\\))");
+ //Do not change the order this array - the indexes are used to extract type codes in the getPrimitiveTypeCode method
+ private static final String[] PRIMITIVE_TYPES = { "boolean", "char",
+ "float", "double", "byte", "short", "int", "long", "void" };
+ private int _numberOfObjects = 0;
+ private int _numberOfClasses = 0;
+ private int _numberOfErrors = 0;
+ private boolean _verbose = false;
+
+ public HeapdumpCommand(Output o)
+ {
+ super(o, COMMAND_NAME, DESCRIPTION, LONG_DESCRIPTION);
+ child_commands = null;
+ }
+
+ public void doCommand(Stack args, Image loadedImage, HashMap properties)
+ {
+ Set heapsToDump = new HashSet();
+
+ while(! args.isEmpty()) {
+ heapsToDump.add(args.pop());
+ }
+
+ _numberOfObjects = 0;
+ _numberOfErrors = 0;
+ _numberOfClasses = 0;
+
+ Object verboseModeStr = properties.get("verbose.mode");
+ _verbose = verboseModeStr != null ? verboseModeStr.equals("on") : false;
+
+ ImageAddressSpace addressSpace = (ImageAddressSpace) properties.get("current_address_space");
+
+ if(addressSpace == null) {
+ out.error("Couldn't get handle on address space");
+ return;
+ }
+
+ JavaRuntime runtime = getRuntime(addressSpace);
+
+ if(runtime == null) {
+ return;
+ }
+
+ if(! heapArgumentsAreValid(runtime,heapsToDump)) {
+ return;
+ }
+
+ String version = getVersionString(runtime);
+
+ boolean is64Bit = addressSpace.getCurrentProcess().getPointerSize() == 64;
+ String filename = HeapDumpSettings.getFileName(properties);
+ boolean phdFormat = HeapDumpSettings.areHeapDumpsPHD(properties);
+
+ try {
+ if(HeapDumpSettings.multipleHeapsInMultipleFiles(properties)) {
+ dumpMultipleHeapsInSeparateFiles(runtime,version,is64Bit,phdFormat,filename,heapsToDump);
+ } else {
+ dumpMultipleHeapsInOneFile(runtime,version,is64Bit,phdFormat,filename,heapsToDump);
+ }
+
+ if(_numberOfErrors == 0) {
+ out.print("\nSuccessfully wrote " + _numberOfObjects + " objects and " + _numberOfClasses + " classes\n");
+ } else {
+ out.print("\nWrote "
+ + _numberOfObjects
+ + " objects and "
+ + _numberOfClasses
+ + " classes and encountered "
+ + _numberOfErrors
+ + " errors."
+ + (! _verbose ? " Start DTFJView with -verbose for more detail." : "")
+ + "\n");
+ }
+ }
+ catch (IOException ex) {
+ out.error("I/O error writing dump:\n");
+ StringWriter writer = new StringWriter();
+ ex.printStackTrace(new PrintWriter(writer));
+ out.error(writer.toString());
+ }
+ }
+
+ /**
+ * Checks the list of heaps to dump as specified by the user.
+ * @param runtime Current java runtime
+ * @param heapsToDump Set of strings the user passed as heaps to dump
+ * @return True if all the names are valid heaps, false otherwise
+ */
+ private boolean heapArgumentsAreValid(JavaRuntime runtime, Set heapsToDump)
+ {
+ if(heapsToDump.size() == 0) {
+ return true;
+ }
+
+ Set workingSet = new HashSet();
+ workingSet.addAll(heapsToDump);
+
+ Iterator heapIt = runtime.getHeaps();
+
+ while(heapIt.hasNext()) {
+ Object potential = heapIt.next();
+
+ if(potential instanceof JavaHeap) {
+ JavaHeap thisHeap = (JavaHeap)potential;
+
+ workingSet.remove(thisHeap.getName());
+ } else if (potential instanceof CorruptData) {
+ reportError("Corrupt heap found. Address = " + ((CorruptData)potential).getAddress(),null);
+ _numberOfErrors++;
+ } else {
+ _numberOfErrors++;
+ reportError("Unexpected type " + potential.getClass().getName() + " found in heap iterator",null);
+ }
+ }
+
+ if(workingSet.isEmpty()) {
+ return true;
+ } else {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("These specified heaps do not exist:\n");
+
+ Iterator nameIterator = workingSet.iterator();
+
+ while(nameIterator.hasNext()) {
+ buffer.append("\t\t" + nameIterator.next() + "\n");
+ }
+
+ buffer.append("\tUse \"info heap\" to see list of heap names");
+
+ out.error(buffer.toString());
+
+ return false;
+ }
+ }
+
+ /**
+ * Extracts a minimal version string from the full -version output
+ */
+ private String getVersionString(JavaRuntime runtime)
+ {
+ try {
+ String rawVersion = runtime.getVersion();
+
+ Matcher matcher = J9_VERSION_PATTERN.matcher(rawVersion);
+
+ if(matcher.find()) {
+ String minimalVersion = matcher.group(1);
+ return minimalVersion;
+ } else {
+ _numberOfErrors++;
+ reportError("Could not parse version string: " + rawVersion,null);
+ return rawVersion;
+ }
+ }
+ catch (CorruptDataException e) {
+ _numberOfErrors++;
+ out.error("Could not read version string from dump: data corrupted at "
+ + e.getCorruptData().getAddress());
+ return "*Corrupt*";
+ }
+ }
+
+ private JavaRuntime getRuntime(ImageAddressSpace addressSpace)
+ {
+ ImageProcess process = addressSpace.getCurrentProcess();
+
+ if(process == null) {
+ out.error("Couldn't get handle on current process");
+ return null;
+ }
+
+ Iterator runtimeIterator = process.getRuntimes();
+
+ if(! runtimeIterator.hasNext()) {
+ out.error("Cannot find a runtime");
+ return null;
+ }
+
+ Object potential = runtimeIterator.next();
+
+ if(potential instanceof CorruptData) {
+ out.error("Runtime data is corrupt");
+ return null;
+ }
+
+ return (JavaRuntime) potential;
+ }
+
+ private void dumpMultipleHeapsInOneFile(JavaRuntime runtime,
+ String version, boolean is64Bit, boolean phdFormat, String filename, Set heapsToDump) throws IOException
+ {
+ Iterator heapIterator = runtime.getHeaps();
+
+ HeapDumpFormatter formatter = getFormatter(filename, version, is64Bit, phdFormat);
+
+ out.print("Writing " + ( phdFormat ? "PHD" : "Classic") + " format heapdump into " + filename);
+
+ dumpClasses(formatter,runtime);
+
+ while (heapIterator.hasNext()) {
+ Object thisHeapObj = heapIterator.next();
+
+ if (thisHeapObj instanceof CorruptData) {
+ out.error("Corrupt heap data found at: "
+ + ((CorruptData) thisHeapObj).getAddress());
+ _numberOfErrors++;
+ continue;
+ }
+
+ JavaHeap thisHeap = (JavaHeap) thisHeapObj;
+
+ if(heapsToDump.size() > 0 && ! heapsToDump.contains(thisHeap.getName())) {
+ continue;
+ }
+
+ dumpHeap(formatter, thisHeap);
+ }
+
+ formatter.close();
+ }
+
+ private void dumpMultipleHeapsInSeparateFiles(JavaRuntime runtime,String version, boolean is64Bit, boolean phdFormat,String baseFileName, Set heapsToDump) throws IOException
+ {
+ Iterator heapIterator = runtime.getHeaps();
+
+ HeapDumpFormatter formatter = null;
+
+ while (heapIterator.hasNext()) {
+ Object thisHeapObj = heapIterator.next();
+
+ if (thisHeapObj instanceof CorruptData) {
+ out.error("Heap corrupted at: "
+ + ((CorruptData) thisHeapObj).getAddress());
+ _numberOfErrors++;
+ continue;
+ }
+
+ JavaHeap thisHeap = (JavaHeap) thisHeapObj;
+
+ // Create a new heapdump formatter for every heap we find
+ if (formatter != null) {
+ formatter.close();
+ }
+
+ if(heapsToDump.size() > 0 && ! heapsToDump.contains(thisHeap.getName())) {
+ continue;
+ }
+
+ String fileName = getFileNameForHeap(thisHeap,baseFileName);
+
+ out.print("Writing "
+ + ( phdFormat ? "PHD" : "Classic")
+ + " format heapdump for heap "
+ + thisHeap.getName()
+ + " into "
+ + fileName + "\n");
+
+ formatter = getFormatter(fileName, version, is64Bit, phdFormat);
+
+ //We have to dump classes in every heapdump
+ dumpClasses(formatter,runtime);
+
+ dumpHeap(formatter, thisHeap);
+ }
+
+ if(formatter != null) {
+ formatter.close();
+ }
+ }
+
+ /**
+ * Walks the runtime classes and passes them through the formatter interface
+ */
+ private void dumpClasses(HeapDumpFormatter formatter, JavaRuntime runtime) throws IOException
+ {
+ Iterator classLoaderIt = runtime.getJavaClassLoaders();
+
+ int numberOfClasses = 0;
+
+ITERATING_LOADERS:while(classLoaderIt.hasNext()) {
+ Object potential = classLoaderIt.next();
+
+ if(potential instanceof CorruptData) {
+ _numberOfErrors++;
+ reportError("CorruptData found in classloader list at address: " + ((CorruptData)potential).getAddress(), null);
+ continue ITERATING_LOADERS;
+ }
+
+ JavaClassLoader thisClassLoader = (JavaClassLoader)potential;
+
+ Iterator classesIt = thisClassLoader.getDefinedClasses();
+
+ITERATING_CLASSES:while(classesIt.hasNext()) {
+ potential = classesIt.next();
+
+ numberOfClasses++;
+
+ try {
+
+ if(potential instanceof CorruptData) {
+ _numberOfErrors++;
+ reportError("CorruptData found in class list for classloader "
+ + Long.toHexString(thisClassLoader.getObject().getID().getAddress())
+ + " at address: " + ((CorruptData)potential).getAddress(), null);
+ continue ITERATING_CLASSES;
+ }
+
+ JavaClass thisJavaClass = (JavaClass)potential;
+
+ JavaClass superClass = thisJavaClass.getSuperclass();
+
+ JavaObject classObject = thisJavaClass.getObject();
+
+ int instanceSize = 0;
+
+ if(thisJavaClass.isArray()) {
+ instanceSize = 0;
+ } else {
+ // we need to figure out a way of determining the instance size for a class
+ }
+
+ formatter.addClass(thisJavaClass.getID().getAddress(),
+ thisJavaClass.getName(),
+ superClass != null ? superClass.getID().getAddress() : 0,
+ classObject != null ? (int)classObject.getSize() : 0,
+ instanceSize,
+ classObject != null ? (int)classObject.getPersistentHashcode() : 0,
+ getClassReferences(thisJavaClass) );
+ } catch(DTFJException ex) {
+ //Handle CorruptDataException and DataUnavailableException the same way
+ _numberOfErrors++;
+ reportError(null,ex);
+ continue ITERATING_CLASSES;
+ }
+ }
+ }
+
+ _numberOfClasses = numberOfClasses;
+ }
+
+ /**
+ * Walks the supplied heap and passes the artifacts through the formatter
+ */
+ private void dumpHeap(HeapDumpFormatter formatter, JavaHeap thisHeap)
+ throws IOException
+ {
+ Iterator objectIterator = thisHeap.getObjects();
+
+ while (objectIterator.hasNext()) {
+ Object next = objectIterator.next();
+ _numberOfObjects++;
+
+ if (next instanceof CorruptData) {
+ _numberOfErrors++;
+ reportError("Corrupt object data found at " + ((CorruptData)next).getAddress() + " while walking heap " + thisHeap.getName(),null);
+ continue;
+ }
+
+ try {
+ JavaObject thisObject = (JavaObject) next;
+ JavaClass thisClass = thisObject.getJavaClass();
+
+ int hashcode = 0;
+
+ try {
+ hashcode = (int) thisObject.getHashcode();
+ }
+ catch (DataUnavailable ex) {
+ _numberOfErrors++;
+ reportError("Failed to get hashcode for object: " + thisObject.getID(),ex);
+ }
+
+ if (thisObject.isArray()) {
+ if (isPrimitive(thisClass.getComponentType())) {
+ formatter.addPrimitiveArray(thisObject.getID().getAddress(),
+ thisClass.getID().getAddress(),
+ getPrimitiveTypeCode(thisClass.getComponentType()),
+ (int) thisObject.getSize(),
+ hashcode,
+ thisObject.getArraySize());
+ }
+ else {
+
+ formatter.addObjectArray(thisObject.getID().getAddress(),
+ thisClass.getID().getAddress(),
+ thisClass.getName(),
+ thisClass.getComponentType().getID().getAddress(),
+ thisClass.getComponentType().getName(),
+ (int) thisObject.getSize(),
+ thisObject.getArraySize(),
+ hashcode,
+ getObjectReferences(thisObject));
+ }
+ }
+ else {
+ formatter.addObject(thisObject.getID().getAddress(),
+ thisClass.getID().getAddress(),
+ thisClass.getName(),
+ (int)thisObject.getSize(),
+ hashcode,
+ getObjectReferences(thisObject));
+ }
+ }
+ catch (CorruptDataException ex) {
+ _numberOfErrors++;
+ reportError(null,ex);
+ continue;
+ }
+ }
+ }
+
+ /* Reference code reimplemented (rather than using the DTFJ getReferences() API)
+ * because we are trying to match the behaviour of the runtime heapdump rather than
+ * the GC spec. The set of references we're trying to create is different.
+ */
+
+ /**
+ * Gets the references for the supplied class
+ *
+ * @param thisJavaClass Class being examined
+ */
+ private ReferenceIterator getClassReferences(JavaClass thisJavaClass)
+ {
+ List references = new LinkedList();
+
+ try {
+ //Statics
+ addStaticReferences(thisJavaClass, references);
+
+ addProtectionDomainReference(thisJavaClass,references);
+
+ //Classloader
+ JavaClassLoader loader = thisJavaClass.getClassLoader();
+
+ if(loader != null) {
+ JavaObject loaderObject = loader.getObject();
+ if(loaderObject != null) {
+ references.add(new Long(loaderObject.getID().getAddress()));
+ } else {
+ reportError("Null loader object returned for class: " + thisJavaClass.getName() + "(" + thisJavaClass.getID() + ")",null);
+ _numberOfErrors++;
+ }
+ } else {
+ reportError("Null classloader returned for class: " + thisJavaClass.getName() + "(" + thisJavaClass.getID() + ")",null);
+ _numberOfErrors++;
+ }
+
+ //Heap object
+ JavaObject classObject = thisJavaClass.getObject();
+ if(classObject != null) {
+ references.add(new Long(classObject.getID().getAddress()));
+ } else {
+ _numberOfErrors++;
+ reportError("Couldn't get Java class loader for: " + thisJavaClass.getName() + "(" + thisJavaClass.getID() + ")",null);
+ }
+
+ } catch(DTFJException ex) {
+ reportError(null,ex);
+ _numberOfErrors++;
+ }
+
+ return new LongListReferenceIterator(references);
+ }
+
+ private JavaField _protectionDomainField;
+
+ private void addProtectionDomainReference(JavaClass thisJavaClass,
+ List references) throws CorruptDataException, MemoryAccessException
+
+ {
+ JavaObject classObject = thisJavaClass.getObject();
+
+ //Protection domain hangs off the protectionDomain field on the class object
+ if(_protectionDomainField == null) {
+ JavaClass javaLangClassObject = classObject.getJavaClass();
+ if(javaLangClassObject == null) {
+ _numberOfErrors++;
+ reportError("Couldn't find java.lang.Class class",null);
+ return;
+ }
+ Iterator fieldsIt = javaLangClassObject.getDeclaredFields();
+
+ while(fieldsIt.hasNext()) {
+ Object potential = fieldsIt.next();
+
+ if(potential instanceof JavaField) {
+ JavaField field = (JavaField) potential;
+
+ if(field.getName().equals(PROTECTION_DOMAIN_FIELD_NAME)) {
+ _protectionDomainField = field;
+ }
+ } else if(potential instanceof CorruptData) {
+ _numberOfErrors++;
+ reportError("CorruptData found walking fields for java.lang.Class. Bad address = "
+ + ((CorruptData)potential).getAddress()
+ ,null);
+ } else {
+ _numberOfErrors++;
+ reportError("Unexpected type "
+ + potential.getClass()
+ + " returned from fields iterator."
+ ,null);
+ }
+ }
+
+ if(_protectionDomainField == null) {
+ _numberOfErrors++;
+ reportError("Couldn't find protection domain field.",null);
+ return;
+ }
+ }
+
+ Object potential = _protectionDomainField.get(classObject);
+
+ if(potential instanceof JavaObject) {
+ JavaObject protectionDomain = (JavaObject)potential;
+
+ references.add(new Long(protectionDomain.getID().getAddress()));
+ } else if (potential instanceof CorruptData) {
+ _numberOfErrors++;
+ reportError("Corrupt data found in protectionDomainField of "
+ + thisJavaClass.getName()
+ + " at address "
+ + ((CorruptData)potential).getAddress()
+ ,null);
+ } else if (potential == null) {
+ //Do nothing
+ } else {
+ reportError("Unexpected type: "
+ + potential.getClass().getName()
+ + " found in protectionDomain field of "
+ + thisJavaClass.getName()
+ ,null);
+ _numberOfErrors++;
+ }
+ }
+
+ /**
+ * Extracts static references from class
+ * @param thisClass Class being examined
+ * @param references List to add references to
+ */
+ private void addStaticReferences(JavaClass thisClass, List references)
+ throws CorruptDataException, MemoryAccessException
+ {
+ Iterator fieldsIt = thisClass.getDeclaredFields();
+
+ while(fieldsIt.hasNext()) {
+ Object potential = fieldsIt.next();
+
+ if(potential instanceof CorruptData) {
+ reportError("Corrupt field found in class "
+ + thisClass.getName()
+ + "(" + thisClass.getID() + ") at "
+ + ((CorruptData)potential).getAddress()
+ ,null);
+ _numberOfErrors++;
+ continue;
+ }
+
+ JavaField field = (JavaField) potential;
+
+ if(! Modifier.isStatic(field.getModifiers())) {
+ continue;
+ }
+
+ Object referent = field.get(thisClass.getObject());
+
+ if(referent instanceof CorruptData) {
+ _numberOfErrors++;
+ reportError("Corrupt referent found in class "
+ + thisClass.getName()
+ + "(" + thisClass.getID() + ") from field "
+ + field.getName()
+ + " at address "
+ + ((CorruptData)potential).getAddress()
+ ,null);
+ } else if (referent instanceof JavaObject) {
+ JavaObject referredObject = (JavaObject) referent;
+
+ references.add(new Long(referredObject.getID().getAddress()));
+ } else if (referent == null) {
+ references.add(new Long(0));
+ } else if (referent instanceof Number || referent instanceof Boolean || referent instanceof Character) {
+ //Ignore
+ } else {
+ reportError("Unexpected type: "
+ + referent.getClass().getName()
+ + " returned from field "
+ + field.getName()
+ + " from class "
+ + thisClass.getName()
+ + "(" + thisClass.getID()+ ")"
+ ,null);
+ _numberOfErrors++;
+ }
+ }
+ }
+
+ /**
+ * Gets instance references for objects
+ * @param thisObject Object being examined
+ * @return Iterator of references
+ */
+ private ReferenceIterator getObjectReferences(JavaObject thisObject)
+ {
+ List references = new LinkedList();
+
+ try {
+ JavaClass thisClass = thisObject.getJavaClass();
+
+ if(thisClass.isArray()) {
+ addArrayReferences(thisObject, references);
+ } else {
+ addRegularObjectReferences(thisObject, references,thisClass);
+ }
+ } catch(DTFJException ex) {
+ _numberOfErrors++;
+ reportError(null,ex);
+ }
+
+ return new LongListReferenceIterator(references);
+ }
+
+ /**
+ * Extracts the instance references from object arrays
+ * @param arrayObject Array
+ * @param references List to add references to
+ */
+ private void addArrayReferences(JavaObject arrayObject, List references)
+ throws CorruptDataException, MemoryAccessException
+ {
+ JavaObject[] localArray = new JavaObject[arrayObject.getArraySize()];
+ arrayObject.arraycopy(0, localArray, 0, arrayObject.getArraySize());
+
+ for(int i=0;i!=localArray.length;i++) {
+ if(localArray[i] != null) {
+ references.add(new Long(localArray[i].getID().getAddress()));
+ } else {
+ references.add(new Long(0));
+ }
+ }
+ }
+
+ /**
+ * Extracts the instance references from a regular (non-array) object
+ * @param object Object being walked
+ * @param references List to add references to
+ * @param thisClass Class of object
+ */
+ private void addRegularObjectReferences(JavaObject object,
+ List references, JavaClass thisClass) throws CorruptDataException,
+ MemoryAccessException
+ {
+ while(thisClass != null) {
+
+ Iterator fieldsIt = thisClass.getDeclaredFields();
+
+WALKING_FIELDS: while(fieldsIt.hasNext()) {
+ Object potential = fieldsIt.next();
+
+ if(potential instanceof CorruptData) {
+ _numberOfErrors++;
+ reportError("Corrupt data found at address "
+ + ((CorruptData)potential).getAddress()
+ + " walking fields of class: "
+ + thisClass.getName()
+ + "(" + thisClass.getID() + ")"
+ ,null);
+ continue WALKING_FIELDS;
+ }
+
+ JavaField field = (JavaField) potential;
+
+ if(Modifier.isStatic(field.getModifiers())) {
+ continue WALKING_FIELDS;
+ }
+
+ Object referent = field.get(object);
+
+ if(referent instanceof CorruptData) {
+ _numberOfErrors++;
+ reportError("Corrupt data found in referent at address "
+ + ((CorruptData)referent).getAddress()
+ + " walking field "
+ + field.getName()
+ + " of class: "
+ + thisClass.getName()
+ + "(" + thisClass.getID() + ")"
+ ,null);
+ continue WALKING_FIELDS;
+ } else if (referent instanceof JavaObject) {
+ JavaObject referredObject = (JavaObject) referent;
+
+ references.add(new Long(referredObject.getID().getAddress()));
+ } else if (referent == null) {
+ references.add(new Long(0));
+ } else if (referent instanceof Number || referent instanceof Boolean || referent instanceof Character) {
+ //Ignore
+ } else {
+ reportError("Unexpected type: " + referent.getClass().getName() + " found in referent",null);
+ _numberOfErrors++;
+ }
+ }
+
+ thisClass = thisClass.getSuperclass();
+ }
+ }
+
+ /**
+ * Checks if class is primitive
+ *
+ * @param clazz
+ * Class under test
+ * @return True if clazz represents a primitive type, false otherwise
+ */
+ private static boolean isPrimitive(JavaClass clazz)
+ throws CorruptDataException
+ {
+ String name = clazz.getName();
+
+ /* Fastpath, anything containing a / cannot be primitive */
+ if (name.indexOf("/") != -1) {
+ return false;
+ }
+
+ for (int i = 0; i != PRIMITIVE_TYPES.length; i++) {
+ if (PRIMITIVE_TYPES[i].equals(name)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Converts a class into a primitive type code (as used by the HeapdumpFormatter interface).
+ * @param clazz
+ * @return
+ */
+ private int getPrimitiveTypeCode(JavaClass clazz)
+ throws CorruptDataException
+ {
+ String name = clazz.getName();
+
+ for (int i = 0; i != PRIMITIVE_TYPES.length; i++) {
+ if (PRIMITIVE_TYPES[i].equals(name)) {
+ return i;
+ }
+ }
+
+ throw new IllegalArgumentException("Class: " + name
+ + " is not primitive");
+ }
+
+ /**
+ * Factory method for HeapDumpFormatters
+ * @param fileName File name for output file
+ * @param version Version string
+ * @param is64Bit True if 64 bit
+ * @param phdFormat True if using PhD format
+ */
+ private HeapDumpFormatter getFormatter(String fileName, String version,
+ boolean is64Bit, boolean phdFormat) throws IOException
+ {
+ return new ClassicHeapDumpFormatter(new FileWriter(fileName),version,is64Bit);
+ }
+
+ /**
+ * Modifies the base file name to include the heap name, whilst maintaining
+ * the suffix
+ */
+ private String getFileNameForHeap(JavaHeap thisHeap, String baseFileName)
+ {
+ int pointIndex = baseFileName.lastIndexOf(".");
+
+ if(pointIndex != -1) {
+ return baseFileName.substring(0,pointIndex) + "." + thisHeap.getName() + baseFileName.substring(pointIndex);
+ } else {
+ return baseFileName + "." + thisHeap.getName();
+ }
+ }
+
+ /**
+ * Internal error handling routine that only reports the supplied message if verbose was supplied on the command line.
+ */
+ private void reportError(String msg,Throwable t)
+ {
+ //Property set in Session.imageFromCommandLine when -verbose specified on command line
+ if(!_verbose) {
+ return;
+ }
+
+ if(msg != null) {
+ out.error(msg);
+ }
+
+ if(t != null) {
+ StringWriter writer = new StringWriter();
+
+ t.printStackTrace(new PrintWriter(writer));
+
+ out.error(writer.toString());
+ }
+ }
+}
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/HelpCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/HelpCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/HelpCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/HelpCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.util.HashMap;
+import java.util.Stack;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.image.Image;
+
+public class HelpCommand extends Command {
+
+ private RootCommand rootCommand;
+
+ public HelpCommand(Output o, RootCommand r){
+ super(o, "help", "displays list of commands or help for a specific command",
+ "parameters: none, <command_name>\n\n" +
+ "With no parameters, \"help\" displays the complete list of commands " +
+ "currently supported. When a <command_name> is specified, \"help\" " +
+ "will list that command's sub-commands if it has sub-commands; " +
+ "otherwise, the command's complete description will be displayed.\n\n" +
+ "To view help on a command's sub-command, specify both the command " +
+ "name and the sub-command name. For example, \"help info thread\" " +
+ "will display \"info thread\"'s description."
+ );
+ child_commands = null;
+
+ rootCommand = r;
+ }
+
+ public void doCommand(Stack args, Image loadedImage, HashMap properties)
+ {
+ rootCommand.printHelp("\t", 11, args, new Stack());
+ }
+}
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/HexdumpCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/HexdumpCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/HexdumpCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/HexdumpCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.util.HashMap;
+import java.util.Stack;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.dtfjview.commands.helpers.Utils;
+import com.ibm.dtfj.image.CorruptDataException;
+import com.ibm.dtfj.image.Image;
+import com.ibm.dtfj.image.ImageAddressSpace;
+import com.ibm.dtfj.image.ImagePointer;
+import com.ibm.dtfj.image.MemoryAccessException;
+
+public class HexdumpCommand extends Command {
+
+ public HexdumpCommand(Output o){
+ super(o, "hexdump", "outputs a section of memory in a hexdump-like format",
+ "parameters: <hex_address> <bytes_to_print>\n\n" +
+ "outputs <bytes_to_print> bytes of memory contents " +
+ "starting from <hex_address>"
+ );
+ child_commands = null;
+ }
+
+ public void doCommand(Stack args, Image loadedImage, HashMap properties){
+ StringBuffer stringBuffer = new StringBuffer();
+ ImageAddressSpace imageAddressSpace = Utils._extractAddressSpace(loadedImage);
+ long addressInDecimal = 0;
+ int numBytesToPrint = 16*16; //dump 256 bytes by default
+ int asciiIndex = 0;
+
+ if (!args.isEmpty()){
+ Long address = Utils.longFromString((String)args.pop());
+ if(null == address){
+ out.error("Specified address is invalid");
+ return;
+ }
+ addressInDecimal = address.longValue();
+ }
+ else
+ {
+ out.error("\"hexdump\" requires at least an address parameter");
+ return;
+ }
+
+ if (!args.isEmpty()){
+ try{
+ numBytesToPrint = Integer.parseInt((String)args.pop());
+ }catch(NumberFormatException nfe){
+ out.error("Specified length is invalid");
+ return;
+ }
+ }
+
+ ImagePointer imagePointerBase = imageAddressSpace.getPointer(addressInDecimal);
+
+ String asciiChars = "";
+
+ long i;
+ for (i = 0; i < numBytesToPrint; i++){
+ ImagePointer imagePointer = imagePointerBase.add(i);
+ //stringBuffer.append(Long.toHexString(addressInDecimal+i)+":\t");
+ //stringBuffer.append(Long.toHexString(imagePointer.getAddress())+":\t");
+ try {
+ Byte byteValue = new Byte(imagePointer.getByteAt(0));
+ asciiIndex = (int) byteValue.byteValue();
+ if (asciiIndex < 0) {
+ asciiIndex += 256;
+ }
+
+ String rawHexString = Integer.toHexString(byteValue.intValue());
+ String fixedHexString = fixHexStringLength(rawHexString);
+
+ String hexText = fixedHexString;
+ if (0 == i%4){
+ hexText = " "+hexText;
+ }
+
+ if (0 == i%16){
+ hexText = "\n"+Long.toHexString(imagePointer.getAddress())+":"+hexText;
+ asciiChars = " |";
+ }
+
+ stringBuffer.append(hexText);
+
+ asciiChars += Utils.byteToAscii.substring(asciiIndex,asciiIndex+1);
+ if (15 == i%16 && i != 0){
+ asciiChars += "|";
+ //System.out.println("****"+asciiChars);
+ stringBuffer.append(asciiChars);
+ }
+ }catch (MemoryAccessException e) {
+ out.error("Address not in memory - 0x"
+ + Long.toHexString(imagePointer.getAddress()));
+ return;
+ }catch (CorruptDataException e) {
+ out.error("Dump data is corrupted");
+ return;
+ }
+ }
+
+ long undisplayedBytes = 16 - i%16;
+ if (16 != undisplayedBytes){
+ stringBuffer.append(padSpace(undisplayedBytes, asciiChars));
+ }
+ stringBuffer.append("\n");
+ out.println(new String(stringBuffer));
+
+ /*properties.put(Utils.CURRENT_MEM_ADDRESS,
+ Long.toHexString(addressInDecimal+numBytesToPrint));*/
+ properties.put(Utils.CURRENT_MEM_ADDRESS, new Long(addressInDecimal));
+ properties.put(Utils.CURRENT_NUM_BYTES_TO_PRINT, new Integer(numBytesToPrint));
+ }
+
+ private String padSpace(long undisplayedBytes, String asciiChars){
+ for (int i = 0; i < 2*undisplayedBytes + undisplayedBytes/4; i++){
+ asciiChars = " " + asciiChars;
+ }
+ return asciiChars;
+ }
+
+ private String fixHexStringLength(String rawHexString){
+ int length = rawHexString.length();
+ if (1 == length){
+ return ("0" + rawHexString);
+ }
+ else if (2 == length){
+ return rawHexString;
+ }
+ else if (8 == length){
+ return rawHexString.substring(6, 8);
+ }
+ else{
+ return "ERROR fixHexStringLength";
+ }
+ }
+
+}
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/InfoCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/InfoCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/InfoCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/InfoCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.util.Vector;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.dtfjview.commands.infocommands.InfoClassCommand;
+import com.ibm.dtfj.dtfjview.commands.infocommands.InfoHeapCommand;
+import com.ibm.dtfj.dtfjview.commands.infocommands.InfoJitmCommand;
+import com.ibm.dtfj.dtfjview.commands.infocommands.InfoLockCommand;
+import com.ibm.dtfj.dtfjview.commands.infocommands.InfoMmapCommand;
+import com.ibm.dtfj.dtfjview.commands.infocommands.InfoProcCommand;
+import com.ibm.dtfj.dtfjview.commands.infocommands.InfoSymCommand;
+import com.ibm.dtfj.dtfjview.commands.infocommands.InfoSystemCommand;
+import com.ibm.dtfj.dtfjview.commands.infocommands.InfoThreadCommand;
+
+public class InfoCommand extends Command{
+
+ public InfoCommand(Output o){
+ super(o, "info", "", "");
+
+ child_commands = new Vector();
+ child_commands.add(new InfoThreadCommand(o));
+ child_commands.add(new InfoSystemCommand(o));
+ child_commands.add(new InfoClassCommand(o));
+ child_commands.add(new InfoProcCommand(o));
+ child_commands.add(new InfoJitmCommand(o));
+ child_commands.add(new InfoLockCommand(o));
+ child_commands.add(new InfoSymCommand(o));
+ child_commands.add(new InfoMmapCommand(o));
+ child_commands.add(new InfoHeapCommand(o));
+ }
+}
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/MinusCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/MinusCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/MinusCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/MinusCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.util.HashMap;
+import java.util.Stack;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.image.Image;
+
+public class MinusCommand extends Command{
+
+ public MinusCommand(Output o){
+ super(o, "-", "displays the previous section of memory in hexdump-like format",
+ "parameters: none\n\n" +
+ "The - command is used in conjunction with the hexdump command " +
+ "to allow easy scrolling backwards through memory. It repeats " +
+ "the previous hexdump command starting from a position " +
+ "before the previous one."
+ );
+ child_commands = null;
+ }
+
+ public void doCommand(Stack args, Image loadedImage, HashMap properties){
+ doScrollCommand(loadedImage, properties, false);
+ }
+}
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/PlusCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/PlusCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/PlusCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/PlusCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.util.HashMap;
+import java.util.Stack;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.image.Image;
+
+public class PlusCommand extends Command{
+
+ public PlusCommand(Output o){
+ super(o, "+", "displays the next section of memory in hexdump-like format",
+ "parameters: none\n\n" +
+ "The + command is used in conjunction with the hexdump command " +
+ "to allow easy scrolling forwards through memory. It repeats the " +
+ "previous hexdump command starting from the end of the previous one."
+ );
+ child_commands = null;
+ }
+
+ public void doCommand(Stack args, Image loadedImage, HashMap properties){
+ doScrollCommand(loadedImage, properties, true);
+ }
+
+}
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/PwdCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/PwdCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/PwdCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/PwdCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.util.HashMap;
+import java.util.Stack;
+import java.io.File;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.image.Image;
+
+public class PwdCommand extends Command {
+
+ public PwdCommand(Output o){
+ super(o, "pwd", "displays the current working directory",
+ "parameters: none\n\n" +
+ "displays the current working directory, which is the directory " +
+ "where log files are stored; see the help for \"cd\" for more " +
+ "information\n"
+ );
+ child_commands = null;
+ }
+
+ public void doCommand(Stack args, Image loadedImage, HashMap properties){
+ if (!args.isEmpty())
+ {
+ out.error("\"pwd\" does not take any parameters");
+ return;
+ }
+
+ File pwd = (File)properties.get("pwd");
+
+ out.print("\n");
+ out.print("\t" + pwd.getPath());
+ out.print("\n\n");
+ }
+}
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/QuitCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/QuitCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/QuitCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/QuitCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.util.HashMap;
+import java.util.Stack;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.image.Image;
+
+public class QuitCommand extends Command {
+
+ public QuitCommand(Output o){
+ super(o, "quit", "exits the core file viewing tool",
+ "parameters: none\n\n" +
+ "exits the core file viewing tool; any log files that are " +
+ "currently open will be closed prior to exit\n"
+ );
+ child_commands = null;
+ }
+
+ public void doCommand(Stack args, Image loadedImage, HashMap properties){
+ if (!args.isEmpty())
+ {
+ out.error("\"quit\" does not take any parameters");
+ return;
+ }
+ properties.put("quit", "on");
+ }
+}
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/RootCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/RootCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/RootCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/RootCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Stack;
+import java.util.Vector;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.image.Image;
+
+public class RootCommand extends Command{
+
+ public RootCommand(Output o){
+ super(o, "", "", "");
+
+ child_commands = new Vector();
+ child_commands.add(new InfoCommand(o));
+ child_commands.add(new HexdumpCommand(o));
+ child_commands.add(new HeapdumpCommand(o));
+ child_commands.add(new PlusCommand(o));
+ child_commands.add(new MinusCommand(o));
+ child_commands.add(new FindCommand(o));
+ child_commands.add(new DeadlockCommand(o));
+ child_commands.add(new SetCommand(o));
+ child_commands.add(new ShowCommand(o));
+ child_commands.add(new QuitCommand(o));
+ child_commands.add(new WhatisCommand(o));
+ child_commands.add(new CdCommand(o));
+ child_commands.add(new PwdCommand(o));
+ child_commands.add(new FindNextCommand(o));
+ child_commands.add(new FindPtrCommand(o));
+ child_commands.add(new HelpCommand(o, this));
+ child_commands.add(new XCommand(o));
+ child_commands.add(new ExitCommand(o));
+ }
+
+ public void printHelp(String indent, int descOffset, Stack currArgs, Stack prevArgs)
+ {
+ if (currArgs.isEmpty())
+ {
+ // out of arguments; we should get our children to print their
+ // short descriptions
+ out.print("\n");
+ Iterator itCommand = child_commands.iterator();
+ while (itCommand.hasNext())
+ {
+ Command command = (Command)itCommand.next();
+
+ command.printHelp(indent, descOffset, null, prevArgs);
+ }
+ out.print("\n");
+ return;
+ }
+
+ // ASSERT: !currArgs.isEmpty()
+ // we've still got arguments left so we should keep on processing
+ String arg = (String)currArgs.pop();
+
+ // first, we need to process the "x/" command
+ if (arg.equals("x"))
+ {
+ if (!currArgs.isEmpty())
+ {
+ out.error("\"x\" command does not have any sub-commands; try \"x/\"");
+ return;
+ }
+ currArgs.push("x/");
+ }
+ else if (arg.startsWith("x/"))
+ {
+ String xSuffix = arg.substring(2);
+ if (!xSuffix.equals(""))
+ {
+ currArgs.push(xSuffix);
+ }
+ currArgs.push("x/");
+ }
+ else
+ {
+ currArgs.push(arg);
+ }
+
+ arg = (String)currArgs.pop();
+
+ // ASSERT: !currArgs.isEmpty() && null != child_commands
+ // we've still got arguments left and we're an internal node in the command tree;
+ // thus, we'll pass on the job to the next command down
+ Iterator itCommand = child_commands.iterator();
+ boolean found = false;
+ Command currCommand = null;
+ while (itCommand.hasNext() && !found)
+ {
+ currCommand = (Command)itCommand.next();
+ if (currCommand.getName().equals(arg))
+ found = true;
+ }
+
+ if (found)
+ {
+ prevArgs.push(arg);
+ currCommand.printHelp(indent, descOffset, currArgs, prevArgs);
+ }
+ else
+ {
+ out.error("\"" + arg + "\" is not a command");
+ return;
+ }
+ }
+
+ public void doCommand(Stack args, Image loadedImage, HashMap properties)
+ {
+ String nextCommand = null;
+
+ if (!args.isEmpty())
+ {
+ nextCommand = (String)args.pop();
+ }
+ else
+ {
+ out.error("specified command requires additional subcommand");
+ return;
+ }
+ nextCommand = nextCommand.toLowerCase();
+
+ if (nextCommand.equals("x"))
+ {
+ args.push(null); // signifies empty set of parameters for "x" command
+ args.push("x/");
+ }
+ else if (nextCommand.startsWith("x/"))
+ {
+ args.push(nextCommand.substring(2)); // push parameters for "x" command
+ args.push("x/");
+ }
+ else
+ {
+ args.push(nextCommand);
+ }
+ super.doCommand(args, loadedImage, properties);
+ }
+}
+
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/SetCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/SetCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/SetCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/SetCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.util.Vector;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.dtfjview.commands.setcommands.SetHeapdumpCommand;
+import com.ibm.dtfj.dtfjview.commands.setcommands.SetLoggingCommand;
+
+public class SetCommand extends Command {
+
+ public SetCommand(Output o){
+ super(o, "set", "", "");
+
+ child_commands = new Vector();
+ child_commands.add(new SetLoggingCommand(o));
+ child_commands.add(new SetHeapdumpCommand(o));
+ }
+
+}
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/ShowCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/ShowCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/ShowCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/ShowCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.util.Vector;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.dtfjview.commands.showcommands.ShowHeapdumpCommand;
+import com.ibm.dtfj.dtfjview.commands.showcommands.ShowLoggingCommand;
+
+public class ShowCommand extends Command {
+
+ public ShowCommand(Output o){
+ super(o, "show", "", "");
+
+ child_commands = new Vector();
+ child_commands.add(new ShowLoggingCommand(o));
+ child_commands.add(new ShowHeapdumpCommand(o));
+ }
+
+}
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/WhatisCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/WhatisCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/WhatisCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/WhatisCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,260 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Stack;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.dtfjview.commands.helpers.Utils;
+import com.ibm.dtfj.image.CorruptDataException;
+import com.ibm.dtfj.image.DataUnavailable;
+import com.ibm.dtfj.image.Image;
+import com.ibm.dtfj.image.ImageSection;
+import com.ibm.dtfj.java.JavaClass;
+import com.ibm.dtfj.java.JavaHeap;
+import com.ibm.dtfj.java.JavaMethod;
+import com.ibm.dtfj.java.JavaObject;
+import com.ibm.dtfj.java.JavaRuntime;
+import com.ibm.dtfj.runtime.ManagedRuntime;
+
+public class WhatisCommand extends Command {
+
+ public WhatisCommand(Output o){
+ super(o, "whatis", "gives information about what is stored at the given memory address",
+ "parameters: <hex_address>\n\n" +
+ "the whatis command examines the memory location at <hex_address> and tries to find out more information about this address " +
+ "- for example whether it is within an object in a heap or within the byte codes associated with a class method."
+ );
+ child_commands = null;
+ }
+
+ public void doCommand(Stack args, Image loadedImage, HashMap systemProperties){
+ if(0 == args.size()){
+ out.error("missing address argument");
+ return;
+ }
+ String address = (String)args.pop();
+ Long lAddressInDecimal = Utils.longFromString(address);
+ if (null == lAddressInDecimal){
+ out.error("cannot convert \"" + address + "\" to numeric value");
+ return;
+ }
+ long addressInDecimal = lAddressInDecimal.longValue();
+
+ findInImage(loadedImage, addressInDecimal);
+
+ out.print("\n");
+ }
+
+ private void findInImage(Image loadedImage, long address)
+ {
+ ManagedRuntime mr;
+ Iterator itRuntime = Utils.getRuntimes(loadedImage);
+ int count = 1;
+
+ out.print("\n");
+ while (itRuntime.hasNext()) {
+ mr = (ManagedRuntime)itRuntime.next();
+ if (mr instanceof JavaRuntime)
+ {
+ out.print("\truntime #" + count + "\n");
+
+ findInRuntime((JavaRuntime)mr, address);
+ }
+ count++;
+ }
+ }
+
+ private void findInRuntime(JavaRuntime jr, long address)
+ {
+ JavaHeap jh;
+ Iterator itHeap = jr.getHeaps();
+ int count = 1;
+
+ while (itHeap.hasNext()) {
+ jh = (JavaHeap)itHeap.next();
+
+ out.print("\t heap #" + count + " - name: ");
+ out.print(jh.getName() + "\n");
+
+ findInHeap(jh, address);
+ count++;
+ }
+ }
+
+ private void findInHeap(JavaHeap jh, long address)
+ {
+ //TODO: checkWithinValidMemRange(sb, ...);
+
+ if (isWithinImageSections(jh.getSections(), null, false, address)){
+ //if it's start or within the range of an object
+ if (!isStartOfObj(jh.getObjects(), address)){
+ if (!isWithinObjectRange(jh.getObjects(), address)){
+ out.print("\t\t0x" + Long.toHexString(address) + " is orphaned on the heap.\n");
+ }
+ }
+ }
+ else{
+ out.print("\t\t0x" + Long.toHexString(address) + " is not within this heap.\n");
+ //TODO : function to indicate 16 or 32 bit
+ long bound = 12; //bounds default to 16 for 32 bit system.
+ checkClassInRange(jh.getObjects(), bound, address);
+ }
+
+ checkMethodInRange(jh.getObjects(), address);
+ }
+
+
+
+ private void checkMethodInRange(Iterator objects, long address){
+ while(objects.hasNext()){
+ JavaObject jObject = (JavaObject)objects.next();
+ JavaClass jClass;
+ try{
+ jClass = jObject.getJavaClass();
+ }catch(CorruptDataException cde){
+ //go to the next iteration
+ continue;
+ }
+ Iterator methods = jClass.getDeclaredMethods();
+ while(methods.hasNext()){
+ JavaMethod jMethod = (JavaMethod)methods.next();
+ Iterator bytecodeSections = jMethod.getBytecodeSections();
+ Iterator compiledSections = jMethod.getCompiledSections();
+ isWithinImageSections(bytecodeSections, jMethod, false, address);
+ isWithinImageSections(compiledSections, jMethod, true, address);
+ }
+ }
+ }
+
+/* TODO: need to implement some output for this method and use it
+ private void checkMonitorInRange(Iterator monitors){
+ while(monitors.hasNext()){
+ JavaMonitor jMonitor = (JavaMonitor)monitors.next();
+ //TODO: need API for retrieving monitor ID (address)
+ //sb.append("\n" + "monitor object id: " + jMonitor.getObject().getID().getAddress());
+ }
+ }
+*/
+
+ private void checkClassInRange(Iterator objects, long bound, long address){
+ long startAddress, endAddress ;
+ while(objects.hasNext()){
+ JavaObject jObject = (JavaObject)objects.next();
+ JavaClass jClass;
+ String className;
+ try{
+ jClass = jObject.getJavaClass();
+ className = jClass.getName();
+ }catch(CorruptDataException cde){
+ //TODO exception handling
+ continue;
+ }
+ startAddress = jClass.getID().getAddress();
+ endAddress = startAddress + bound;
+ if(address == startAddress){
+ out.print("0x" + Long.toHexString(address) +
+ " is the address of the java/lang/Class object for " + className);
+ return;
+ }
+ if (isWithinRange(startAddress, endAddress, address)){
+ out.print("0x" + Long.toHexString(address)
+ + " is within the java/lang/Class object for " + className);
+ return;
+ }
+ }
+ }
+
+ private boolean isWithinObjectRange(Iterator objects, long address){
+ long startAddress, endAddress ;
+ String className;
+ while(objects.hasNext()){
+ JavaObject jObject = (JavaObject)objects.next();
+ try{
+ className = jObject.getJavaClass().getName();
+ startAddress = jObject.getID().getAddress();
+ endAddress = startAddress + jObject.getSize();
+ }catch(CorruptDataException cde){
+ //TODO exception handling
+ continue;
+ }
+ if (isWithinRange(startAddress, endAddress, address)){
+ out.print("\t\t0x" + Long.toHexString(address) + " is within an object on the heap:\n" +
+ "\t\t\toffset " + (address - startAddress) + " within "+ className +
+ " instance @ 0x" + Long.toHexString(startAddress) + "\n");
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isWithinRange(long startAddress, long endAddress, long address){
+ return (address <= endAddress && address > startAddress);
+ }
+
+ private boolean isStartOfObj(Iterator objects, long address){
+ String className;
+ while(objects.hasNext()){
+ JavaObject jObject = (JavaObject)objects.next();
+ if (address == jObject.getID().getAddress()){
+ try{
+ className = jObject.getJavaClass().getName();
+ }catch(CorruptDataException cde){
+ className = "N/A (CorruptDataException occurred)";
+ }
+ out.print("0x" + Long.toHexString(address) + " is start of an object of type " + className);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isWithinImageSections(Iterator heapImageSections, Object memType,
+ boolean isMethodCompiled, long address)
+ {
+ while (heapImageSections.hasNext()){
+ ImageSection imageSection = (ImageSection)heapImageSections.next();
+ long baseAddress = imageSection.getBaseAddress().getAddress();
+ long size = imageSection.getSize();
+ long endAddress = baseAddress + size;
+
+ if (address <= endAddress && address >= baseAddress) {
+ if (null == memType) {
+ out.print("\t\t0x" + Long.toHexString(address) + " is within heap segment: " +
+ Long.toHexString(baseAddress) + " -- " + Long.toHexString(endAddress) + "\n");
+ return true;
+ }
+ if (memType instanceof JavaMethod) {
+ String methodName = "N/A", methodSig = "N/A", className = "N/A";
+ try{
+ methodName = ((JavaMethod)memType).getName();
+ methodSig = ((JavaMethod)memType).getSignature();
+ className = ((JavaMethod)memType).getDeclaringClass().getName();
+ }catch(CorruptDataException cde){
+ }catch(DataUnavailable du){
+ }
+ String codeType = isMethodCompiled ? "compiled code" : "byte code";
+ out.print("0x" + Long.toHexString(address) + " is within the " + codeType + " range: " +
+ Long.toHexString(baseAddress) + " -- " + Long.toHexString(endAddress) + "\n\t" + "...of method " +
+ methodName + " with signature " + methodSig + "\n\t" +
+ "...in class " + className + "\n");
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/XCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/XCommand.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/XCommand.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/XCommand.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,234 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands;
+
+import java.util.HashMap;
+import java.util.Stack;
+import java.util.Vector;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.dtfjview.commands.xcommands.XDCommand;
+import com.ibm.dtfj.dtfjview.commands.xcommands.XJCommand;
+import com.ibm.dtfj.dtfjview.commands.xcommands.XKCommand;
+import com.ibm.dtfj.dtfjview.commands.xcommands.XXCommand;
+import com.ibm.dtfj.image.Image;
+
+public class XCommand extends Command {
+
+ public XCommand(Output o){
+ super(o, "x/", "works like \"x/\" in gdb (including use of defaults): passes " +
+ "number of items to display and unit " +
+ "size ('b' for byte, 'h' for halfword, 'w' for word, 'g' for giant " +
+ "word) to sub-command (ie. x/12bd)",
+
+ ""
+ );
+
+ child_commands = new Vector();
+ child_commands.add(new XJCommand(o));
+ child_commands.add(new XDCommand(o));
+ child_commands.add(new XXCommand(o));
+ child_commands.add(new XKCommand(o));
+
+ // note: do NOT add any of the following:
+ // - XBCommand
+ // - XHCommand
+ // - XWCommand
+ // - XGCommand
+
+ // why not? because 'b', 'h', 'w', and 'g' represent unit sizes and
+ // the parser won't know whether you mean a unit size or a display format
+ // if you use any of the above characters for a display format
+ }
+
+ public void doCommand(Stack args, Image loadedImage, HashMap properties)
+ {
+ String arg;
+
+ if (!args.isEmpty())
+ {
+ arg = (String)args.pop();
+ }
+ else
+ {
+ out.error("\"x/\" command requires additional parameters");
+ return;
+ }
+
+ int n;
+ Character unitSize;
+ Character displayFormat;
+
+ if (null == arg || arg.equals(""))
+ {
+ // user didn't specify any parameters; use the defaults
+ n = 1;
+ unitSize = getDefaultUnitSize(properties);
+ displayFormat = getDefaultDisplayFormat(properties);
+ }
+ else
+ {
+ n = 0;
+ int i;
+ for (i = 0; i < arg.length() && Character.isDigit(arg.charAt(i)); i++)
+ {
+ n *= 10;
+ n += Character.getNumericValue(arg.charAt(i));
+ }
+
+ if (0 == n)
+ n = 1;
+
+ displayFormat = null;
+ unitSize = null;
+
+ if (i < arg.length())
+ {
+ char currChar = arg.charAt(i);
+ switch (currChar)
+ {
+ case 'b':
+ case 'h':
+ case 'w':
+ case 'g':
+ unitSize = new Character(currChar);
+ break;
+ default:
+ displayFormat = new Character(currChar);
+ break;
+ }
+ i++;
+ }
+
+ if (i < arg.length())
+ {
+ char currChar = arg.charAt(i);
+ switch (currChar)
+ {
+ case 'b':
+ case 'h':
+ case 'w':
+ case 'g':
+ if (null == unitSize)
+ {
+ unitSize = new Character(currChar);
+ }
+ else
+ {
+ out.error("first letter after \"x/\" was a unit size character; " +
+ "second letter (if specified) must be a display " +
+ "format letter but it was also a unit size character");
+ return;
+ }
+ break;
+ default:
+ if (null == displayFormat)
+ {
+ displayFormat = new Character(currChar);
+ }
+ else
+ {
+ out.error("first letter after \"x/\" was a display format character; " +
+ "second letter (if specified) must be a unit size " +
+ "letter but it was also a display format character");
+ return;
+ }
+ break;
+ }
+ i++;
+ }
+
+ if (arg.length() != i)
+ {
+ out.error("too many letters after \"x/\"; the \"x/\" command accepts at " +
+ "most two letters, a display format character and a unit " +
+ "size character");
+ return;
+ }
+
+ // we now have all the necessary information to put on the stack (except
+ // for the unspecified parameters that assume use of defaults) so let's
+ // get the required default values and push some parameters back on to
+ // the argument stack
+
+ if (null == unitSize) {
+ unitSize = getDefaultUnitSize(properties);
+ } else {
+ setDefaultUnitSize(properties, unitSize);
+ }
+
+ if (null == displayFormat) {
+ displayFormat = getDefaultDisplayFormat(properties);
+ } else {
+ setDefaultDisplayFormat(properties, displayFormat);
+ }
+ }
+
+ Integer nUnitSize = null;
+ char cUnitSize = unitSize.charValue();
+
+ switch (cUnitSize)
+ {
+ case 'b':
+ nUnitSize = new Integer(1);
+ break;
+ case 'h':
+ nUnitSize = new Integer(2);
+ break;
+ case 'w':
+ nUnitSize = new Integer(4);
+ break;
+ case 'g':
+ nUnitSize = new Integer(8);
+ break;
+ }
+
+ // we can pretty much guarantee that nUnitSize is not null here because
+ // unitSize has to be one of the above 4 characters if it isn't null
+
+ args.push(nUnitSize); // add the unit size to the stack
+ args.push(new Integer(n)); // add the number of units to print to the stack
+ args.push(displayFormat.toString()); // add the display format as a String
+
+ super.doCommand(args, loadedImage, properties);
+ }
+
+ private Character getDefaultUnitSize(HashMap properties)
+ {
+ Character defaultUnitSize = (Character)properties.get("x_default_unit_size");
+ if (null == defaultUnitSize)
+ return new Character('w');
+ else
+ return defaultUnitSize;
+ }
+
+ private Character getDefaultDisplayFormat(HashMap properties)
+ {
+ Character defaultDisplayFormat = (Character)properties.get("x_default_display_format");
+ if (null == defaultDisplayFormat)
+ return new Character('x');
+ else
+ return defaultDisplayFormat;
+ }
+
+ private void setDefaultUnitSize(HashMap properties, Character defaultUnitSize)
+ {
+ properties.put("x_default_unit_size", defaultUnitSize);
+ }
+
+ private void setDefaultDisplayFormat(HashMap properties, Character defaultDisplayFormat)
+ {
+ properties.put("x_default_display_format", defaultDisplayFormat);
+ }
+}
Added: incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/helpers/ClassOutput.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/helpers/ClassOutput.java?rev=754949&view=auto
==============================================================================
--- incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/helpers/ClassOutput.java (added)
+++ incubator/kato/trunk/import/org.apache.kato.tools.katoview/src/com/ibm/dtfj/dtfjview/commands/helpers/ClassOutput.java Mon Mar 16 16:43:29 2009
@@ -0,0 +1,416 @@
+/*******************************************************************************
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package com.ibm.dtfj.dtfjview.commands.helpers;
+
+import java.lang.reflect.Modifier;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.ibm.dtfj.dtfjview.Output;
+import com.ibm.dtfj.image.CorruptDataException;
+import com.ibm.dtfj.image.ImageSection;
+import com.ibm.dtfj.image.MemoryAccessException;
+import com.ibm.dtfj.java.JavaClass;
+import com.ibm.dtfj.java.JavaField;
+import com.ibm.dtfj.java.JavaMethod;
+import com.ibm.dtfj.java.JavaObject;
+import com.ibm.dtfj.java.JavaRuntime;
+
+
+public class ClassOutput {
+
+ public static void printStaticFields(JavaClass jc, Output out)
+ {
+ // if the class name refers to an array, return because there are no fields
+ try {
+ if (jc.isArray()) {
+ return;
+ }
+ } catch (CorruptDataException cde) {
+ out.print("\t <can't determine if class is array; assuming it's not>\n\n");
+ }
+
+ String className;
+ try {
+ className = jc.getName();
+ } catch (CorruptDataException cde) {
+ className = null;
+ }
+
+ // we've found a class, so we'll print out its static fields
+ boolean found = false;
+ Iterator itField = jc.getDeclaredFields();
+ while (itField.hasNext())
+ {
+ JavaField jf = (JavaField)itField.next();
+ boolean isStatic;
+
+ try {
+ isStatic = Modifier.isStatic(jf.getModifiers());
+ } catch (CorruptDataException e) {
+ out.print("\t <error while getting modifier for field \"");
+ try {
+ out.print(jf.getName());
+ } catch (CorruptDataException d) {
+ out.print(Exceptions.getCorruptDataExceptionString());
+ }
+ out.print("\", " + Exceptions.getCorruptDataExceptionString() + ">");
+ isStatic = false;
+ }
+
+ if (isStatic)
+ {
+ if (!found)
+ {
+ out.print("\t static fields for \"" + className + "\"\n");
+ }
+ found = true;
+ printStaticFieldData(jf, out);
+ }
+ }
+ if (found)
+ out.print("\n");
+ else
+ out.print("\t \"" + className + "\" has no static fields\n\n");
+ }
+
+ public static void printNonStaticFields(JavaClass jc, Output out)
+ {
+ // if the class name refers to an array, return because there are no fields
+ try {
+ if (jc.isArray()) {
+ return;
+ }
+ } catch (CorruptDataException cde) {
+ out.print("\t <can't determine if class is array; assuming it's not>\n\n");
+ }
+
+ String className;
+ try {
+ className = jc.getName();
+ } catch (CorruptDataException cde) {
+ className = null;
+ }
+
+ // we've found a class, so we'll print out its static fields
+ boolean found = false;
+ Iterator itField = jc.getDeclaredFields();
+ while (itField.hasNext())
+ {
+ JavaField jf = (JavaField)itField.next();
+ boolean isStatic;
+
+ try {
+ isStatic = Modifier.isStatic(jf.getModifiers());
+ } catch (CorruptDataException e) {
+ out.print("\t <error while getting modifier for field \"");
+ try {
+ out.print(jf.getName());
+ } catch (CorruptDataException d) {
+ out.print(Exceptions.getCorruptDataExceptionString());
+ }
+ out.print("\", " + Exceptions.getCorruptDataExceptionString() + ">");
+ isStatic = false;
+ }
+
+ if (!isStatic)
+ {
+ if (!found)
+ {
+ out.print("\t non-static fields for \"" + className + "\"\n");
+ }
+ found = true;
+ printNonStaticFieldData(null, jf, out);
+ }
+ }
+ if (found)
+ out.print("\n");
+ else
+ out.print("\t \"" + className + "\" has no non-static fields\n\n");
+ }
+
+ public static void printFields(JavaObject jo, JavaClass jc, JavaRuntime jr, Output out)
+ {
+ boolean array;
+
+ try {
+ array = jo.isArray();
+ } catch (CorruptDataException e) {
+ out.print("\t <cannot determine if above object is array (" +
+ Exceptions.getCorruptDataExceptionString() + "); "
+ + "we will assume it is not an array>\n");
+ array = false;
+ }
+
+ if (array)
+ {
+ String componentType;
+ int arraySize;
+
+ try {
+ componentType = jc.getComponentType().getName();
+ } catch (CorruptDataException e) {
+ out.print("\t <cannot determine what type of array this is (" +
+ Exceptions.getCorruptDataExceptionString() + ")>\n");
+ return;
+ }
+
+ try {
+ arraySize = jo.getArraySize();
+ } catch (CorruptDataException e) {
+ out.print("\t <cannot determine the size of the array (" +
+ Exceptions.getCorruptDataExceptionString() + ")>\n");
+ return;
+ }
+
+ Object dst = null;
+
+ if (componentType.equals("boolean")) {
+ dst = new boolean[arraySize];
+ } else if (componentType.equals("byte")) {
+ dst = new byte[arraySize];
+ } else if (componentType.equals("char")) {
+ dst = new char[arraySize];
+ } else if (componentType.equals("short")) {
+ dst = new short[arraySize];
+ } else if (componentType.equals("int")) {
+ dst = new int[arraySize];
+ } else if (componentType.equals("long")) {
+ dst = new long[arraySize];
+ } else if (componentType.equals("float")) {
+ dst = new float[arraySize];
+ } else if (componentType.equals("double")) {
+ dst = new double[arraySize];
+ } else {
+ dst = new JavaObject[arraySize];
+ }
+
+ try {
+ jo.arraycopy(0, dst, 0, arraySize);
+ } catch (CorruptDataException e) {
+ out.print("\t <cannot copy data from the array (" +
+ Exceptions.getCorruptDataExceptionString() + ")>\n");
+ return;
+ } catch (MemoryAccessException e) {
+ out.print("\t <cannot copy data from the array (" +
+ Exceptions.getMemoryAccessExceptionString() + ")>\n");
+ return;
+ }
+
+ for (int i = 0; i < arraySize; i++)
+ {
+ out.print("\t " + i + ":\t");
+ if (componentType.equals("boolean")) {
+ out.print(Utils.getVal(new Boolean(((boolean[])dst)[i])));
+ } else if (componentType.equals("byte")) {
+ out.print(Utils.getVal(new Byte(((byte[])dst)[i])));
+ } else if (componentType.equals("char")) {
+ out.print(Utils.getVal(new Character(((char[])dst)[i])));
+ } else if (componentType.equals("short")) {
+ out.print(Utils.getVal(new Short(((short[])dst)[i])));
+ } else if (componentType.equals("int")) {
+ out.print(Utils.getVal(new Integer(((int[])dst)[i])));
+ } else if (componentType.equals("long")) {
+ out.print(Utils.getVal(new Long(((long[])dst)[i])));
+ } else if (componentType.equals("float")) {
+ out.print(Utils.getVal(new Float(((float[])dst)[i])));
+ } else if (componentType.equals("double")) {
+ out.print(Utils.getVal(new Double(((double[])dst)[i])));
+ } else {
+ out.print(Utils.getVal(((JavaObject[])dst)[i]));
+ }
+ out.print("\n");
+ }
+ }
+ else
+ {
+
+ JavaClass initialJC = jc;
+ List classList = new ArrayList();
+ while (jc != null){
+
+ classList.add(jc);
+ try {
+ jc = jc.getSuperclass();
+ } catch (CorruptDataException d) {
+ jc = null;
+ }
+ }
+ for (int i = (classList.size()-1); i >=0 ; i--){
+
+ jc = (JavaClass)classList.get(i);
+ Iterator itField = jc.getDeclaredFields();
+
+ if (itField.hasNext()){
+ if (jc.equals(initialJC)){
+ out.print("\t declared fields:\n");
+ } else {
+ out.print("\t fields inherited from \"");
+ try {
+ out.print(jc.getName() + "\":\n");
+ } catch (CorruptDataException d) {
+ out.print(Exceptions.getCorruptDataExceptionString());
+ }
+ }
+ }
+
+ while (itField.hasNext())
+ {
+ JavaField jf = (JavaField)itField.next();
+ boolean isStatic;
+
+ try {
+ isStatic = Modifier.isStatic(jf.getModifiers());
+ } catch (CorruptDataException e) {
+ out.print("\t <error while getting modifier for field \"");
+ try {
+ out.print(jf.getName());
+ } catch (CorruptDataException d) {
+ out.print(Exceptions.getCorruptDataExceptionString());
+ }
+ out.print("\", " + Exceptions.getCorruptDataExceptionString() + ">");
+ isStatic = true;
+ }
+
+ if (!isStatic)
+ {
+ printNonStaticFieldData(jo, jf, out);
+ }
+ }
+ }
+ }
+ out.print("\n");
+ }
+
+ private static void printStaticFieldData(JavaField jf, Output out)
+ {
+ printFieldData(null, jf, out, true);
+ }
+
+ private static void printNonStaticFieldData(JavaObject jo, JavaField jf, Output out)
+ {
+ printFieldData(jo, jf, out, false);
+ }
+
+ private static void printFieldData(JavaObject jo, JavaField jf, Output out, boolean isStatic)
+ {
+ String signature;
+
+ out.print("\t ");
+ try {
+ String modifierString = Utils.getModifierString(jf.getModifiers());
+ out.print(modifierString);
+ } catch (CorruptDataException e) {
+ out.print(Exceptions.getCorruptDataExceptionString());
+ }
+
+ try {
+ signature = jf.getSignature();
+ } catch (CorruptDataException e) {
+ out.print(Exceptions.getCorruptDataExceptionString());
+ signature = null;
+ }
+ if (null != signature)
+ {
+ String name = Utils.getSignatureName(signature);
+ if (null == name) {
+ out.print("<unknown>");
+ } else {
+ out.print(name);
+ }
+ }
+
+ out.print(" ");
+
+ try {
+ out.print(jf.getName());
+ } catch (CorruptDataException e) {
+ out.print(Exceptions.getCorruptDataExceptionString());
+ }
+
+ if (isStatic || null != jo) {
+ out.print(" = ");
+ out.print(Utils.getVal(jo, jf));
+ }
+ out.print("\n");
+ }
+
+ public static void printMethods(Iterator methods, Output out)
+ {
+ while(methods.hasNext()) {
+ JavaMethod jMethod = (JavaMethod)methods.next();
+ try{
+ out.print("Bytecode range(s): ");
+ Iterator imageSections = jMethod.getBytecodeSections();
+ boolean firstSectionPassed = false;
+ while (imageSections.hasNext()){
+ ImageSection is = (ImageSection)imageSections.next();
+ long baseAddress = is.getBaseAddress().getAddress();
+ long endAddress = baseAddress + is.getSize();
+ if (firstSectionPassed) {
+ out.print(", ");
+ }
+ out.print(Long.toHexString(baseAddress) + " -- " +
+ Long.toHexString(endAddress));
+ firstSectionPassed = true;
+ }
+ out.print(": ");
+
+
+ String signature;
+
+ try {
+ out.print(Utils.getModifierString(jMethod.getModifiers()));
+ } catch (CorruptDataException e) {
+ out.print(Exceptions.getCorruptDataExceptionString());
+ }
+
+ try {
+ signature = jMethod.getSignature();
+ } catch (CorruptDataException e) {
+ out.print(Exceptions.getCorruptDataExceptionString());
+ signature = null;
+ }
+ if (null != signature)
+ {
+ String name = Utils.getReturnValueName(signature);
+ if (null == name) {
+ out.print("<unknown>");
+ } else {
+ out.print(name);
+ }
+ }
+
+ out.print(" ");
+ out.print(jMethod.getName());
+
+ if (null != signature)
+ {
+ String name = Utils.getMethodSignatureName(signature);
+ if (null == name) {
+ out.print("<unknown>");
+ } else {
+ out.print(name);
+ }
+ }
+
+ out.print("\n");
+ }catch (CorruptDataException cde){
+ out.print("N/A (CorruptDataException occurred)");
+ }
+ }
+ }
+
+}