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)");
+			}
+		}
+	}
+
+}