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 mo...@apache.org on 2009/11/23 15:54:15 UTC

svn commit: r883384 [40/47] - in /incubator/kato/trunk/org.apache.kato: ./ kato.anttasks/src/main/java/org/apache/kato/anttasks/ kato.anttasks/src/main/java/org/apache/kato/anttasks/sitebuilder/ kato.anttasks/src/main/java/org/apache/kato/anttasks/tck/...

Modified: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HeapdumpCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HeapdumpCommand.java?rev=883384&r1=883383&r2=883384&view=diff
==============================================================================
--- incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HeapdumpCommand.java (original)
+++ incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HeapdumpCommand.java Mon Nov 23 15:53:48 2009
@@ -1,879 +1,879 @@
-/*******************************************************************************
- * 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 org.apache.kato.katoview.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 javax.tools.diagnostics.image.CorruptData;
-import javax.tools.diagnostics.image.CorruptDataException;
-import javax.tools.diagnostics.image.DataUnavailable;
-import javax.tools.diagnostics.image.Image;
-import javax.tools.diagnostics.image.ImageAddressSpace;
-import javax.tools.diagnostics.image.ImageProcess;
-import javax.tools.diagnostics.image.DiagnosticException;
-import javax.tools.diagnostics.image.MemoryAccessException;
-import javax.tools.diagnostics.runtime.java.JavaClass;
-import javax.tools.diagnostics.runtime.java.JavaClassLoader;
-import javax.tools.diagnostics.runtime.java.JavaField;
-import javax.tools.diagnostics.runtime.java.JavaHeap;
-import javax.tools.diagnostics.runtime.java.JavaObject;
-import javax.tools.diagnostics.runtime.java.JavaRuntime;
-
-import org.apache.kato.katoview.Output;
-import org.apache.kato.katoview.heapdump.HeapDumpFormatter;
-import org.apache.kato.katoview.heapdump.HeapDumpSettings;
-import org.apache.kato.katoview.heapdump.LongListReferenceIterator;
-import org.apache.kato.katoview.heapdump.ReferenceIterator;
-import org.apache.kato.katoview.heapdump.classic.ClassicHeapDumpFormatter;
-
-
-/**
- * Command for dumping heapdumps from Kato.
- * 
- * Contains the heap-walking logic for building the reference tree. 
- *
- */
-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 KatoView 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().iterator();
-		
-		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().iterator();
-		
-		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().iterator();
-		
-		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().iterator();
-		
-		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().iterator();
-		
-		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().iterator();
-			
-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(DiagnosticException 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().iterator();
-
-		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 Kato 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(DiagnosticException 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().iterator();
-			
-			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().iterator();
-			
-		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(DiagnosticException 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().iterator();
-			
-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());
-		}
-	}
-}
+/*******************************************************************************
+ * 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 org.apache.kato.katoview.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 javax.tools.diagnostics.image.CorruptData;
+import javax.tools.diagnostics.image.CorruptDataException;
+import javax.tools.diagnostics.image.DataUnavailable;
+import javax.tools.diagnostics.image.Image;
+import javax.tools.diagnostics.image.ImageAddressSpace;
+import javax.tools.diagnostics.image.ImageProcess;
+import javax.tools.diagnostics.image.DiagnosticException;
+import javax.tools.diagnostics.image.MemoryAccessException;
+import javax.tools.diagnostics.runtime.java.JavaClass;
+import javax.tools.diagnostics.runtime.java.JavaClassLoader;
+import javax.tools.diagnostics.runtime.java.JavaField;
+import javax.tools.diagnostics.runtime.java.JavaHeap;
+import javax.tools.diagnostics.runtime.java.JavaObject;
+import javax.tools.diagnostics.runtime.java.JavaRuntime;
+
+import org.apache.kato.katoview.Output;
+import org.apache.kato.katoview.heapdump.HeapDumpFormatter;
+import org.apache.kato.katoview.heapdump.HeapDumpSettings;
+import org.apache.kato.katoview.heapdump.LongListReferenceIterator;
+import org.apache.kato.katoview.heapdump.ReferenceIterator;
+import org.apache.kato.katoview.heapdump.classic.ClassicHeapDumpFormatter;
+
+
+/**
+ * Command for dumping heapdumps from Kato.
+ * 
+ * Contains the heap-walking logic for building the reference tree. 
+ *
+ */
+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 KatoView 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().iterator();
+		
+		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().iterator();
+		
+		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().iterator();
+		
+		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().iterator();
+		
+		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().iterator();
+		
+		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().iterator();
+			
+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(DiagnosticException 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().iterator();
+
+		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 Kato 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(DiagnosticException 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().iterator();
+			
+			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().iterator();
+			
+		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(DiagnosticException 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().iterator();
+			
+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());
+		}
+	}
+}

Propchange: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HeapdumpCommand.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HelpCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HelpCommand.java?rev=883384&r1=883383&r2=883384&view=diff
==============================================================================
--- incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HelpCommand.java (original)
+++ incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HelpCommand.java Mon Nov 23 15:53:48 2009
@@ -1,48 +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 org.apache.kato.katoview.commands;
-
-import java.util.HashMap;
-import java.util.Stack;
-
-import javax.tools.diagnostics.image.Image;
-
-import org.apache.kato.katoview.Output;
-
-
-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());
-	}
-}
+/*******************************************************************************
+ * 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 org.apache.kato.katoview.commands;
+
+import java.util.HashMap;
+import java.util.Stack;
+
+import javax.tools.diagnostics.image.Image;
+
+import org.apache.kato.katoview.Output;
+
+
+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());
+	}
+}

Propchange: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HelpCommand.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HexdumpCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HexdumpCommand.java?rev=883384&r1=883383&r2=883384&view=diff
==============================================================================
--- incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HexdumpCommand.java (original)
+++ incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HexdumpCommand.java Mon Nov 23 15:53:48 2009
@@ -1,153 +1,153 @@
-/*******************************************************************************
- * 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 org.apache.kato.katoview.commands;
-
-import java.util.HashMap;
-import java.util.Stack;
-
-import javax.tools.diagnostics.image.CorruptDataException;
-import javax.tools.diagnostics.image.Image;
-import javax.tools.diagnostics.image.ImageAddressSpace;
-import javax.tools.diagnostics.image.ImagePointer;
-import javax.tools.diagnostics.image.MemoryAccessException;
-
-import org.apache.kato.katoview.Output;
-import org.apache.kato.katoview.commands.helpers.Utils;
-
-
-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";
-		}
-	}
-	
-}
+/*******************************************************************************
+ * 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 org.apache.kato.katoview.commands;
+
+import java.util.HashMap;
+import java.util.Stack;
+
+import javax.tools.diagnostics.image.CorruptDataException;
+import javax.tools.diagnostics.image.Image;
+import javax.tools.diagnostics.image.ImageAddressSpace;
+import javax.tools.diagnostics.image.ImagePointer;
+import javax.tools.diagnostics.image.MemoryAccessException;
+
+import org.apache.kato.katoview.Output;
+import org.apache.kato.katoview.commands.helpers.Utils;
+
+
+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";
+		}
+	}
+	
+}

Propchange: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/HexdumpCommand.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/InfoCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/InfoCommand.java?rev=883384&r1=883383&r2=883384&view=diff
==============================================================================
--- incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/InfoCommand.java (original)
+++ incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/InfoCommand.java Mon Nov 23 15:53:48 2009
@@ -1,48 +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 org.apache.kato.katoview.commands;
-
-import java.util.Vector;
-
-import org.apache.kato.katoview.Output;
-import org.apache.kato.katoview.commands.infocommands.InfoClassCommand;
-import org.apache.kato.katoview.commands.infocommands.InfoHeapCommand;
-import org.apache.kato.katoview.commands.infocommands.InfoJitmCommand;
-import org.apache.kato.katoview.commands.infocommands.InfoLockCommand;
-import org.apache.kato.katoview.commands.infocommands.InfoMmapCommand;
-import org.apache.kato.katoview.commands.infocommands.InfoProcCommand;
-import org.apache.kato.katoview.commands.infocommands.InfoPropertyCommand;
-import org.apache.kato.katoview.commands.infocommands.InfoSymCommand;
-import org.apache.kato.katoview.commands.infocommands.InfoSystemCommand;
-import org.apache.kato.katoview.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));
-		child_commands.add(new InfoPropertyCommand(o));
-	}
-}
+/*******************************************************************************
+ * 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 org.apache.kato.katoview.commands;
+
+import java.util.Vector;
+
+import org.apache.kato.katoview.Output;
+import org.apache.kato.katoview.commands.infocommands.InfoClassCommand;
+import org.apache.kato.katoview.commands.infocommands.InfoHeapCommand;
+import org.apache.kato.katoview.commands.infocommands.InfoJitmCommand;
+import org.apache.kato.katoview.commands.infocommands.InfoLockCommand;
+import org.apache.kato.katoview.commands.infocommands.InfoMmapCommand;
+import org.apache.kato.katoview.commands.infocommands.InfoProcCommand;
+import org.apache.kato.katoview.commands.infocommands.InfoPropertyCommand;
+import org.apache.kato.katoview.commands.infocommands.InfoSymCommand;
+import org.apache.kato.katoview.commands.infocommands.InfoSystemCommand;
+import org.apache.kato.katoview.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));
+		child_commands.add(new InfoPropertyCommand(o));
+	}
+}

Propchange: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/InfoCommand.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/MinusCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/MinusCommand.java?rev=883384&r1=883383&r2=883384&view=diff
==============================================================================
--- incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/MinusCommand.java (original)
+++ incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/MinusCommand.java Mon Nov 23 15:53:48 2009
@@ -1,40 +1,40 @@
-/*******************************************************************************
- * 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 org.apache.kato.katoview.commands;
-
-import java.util.HashMap;
-import java.util.Stack;
-
-import javax.tools.diagnostics.image.Image;
-
-import org.apache.kato.katoview.Output;
-
-
-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);
-	}
-}
+/*******************************************************************************
+ * 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 org.apache.kato.katoview.commands;
+
+import java.util.HashMap;
+import java.util.Stack;
+
+import javax.tools.diagnostics.image.Image;
+
+import org.apache.kato.katoview.Output;
+
+
+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);
+	}
+}

Propchange: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/MinusCommand.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/PlusCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/PlusCommand.java?rev=883384&r1=883383&r2=883384&view=diff
==============================================================================
--- incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/PlusCommand.java (original)
+++ incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/PlusCommand.java Mon Nov 23 15:53:48 2009
@@ -1,40 +1,40 @@
-/*******************************************************************************
- * 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 org.apache.kato.katoview.commands;
-
-import java.util.HashMap;
-import java.util.Stack;
-
-import javax.tools.diagnostics.image.Image;
-
-import org.apache.kato.katoview.Output;
-
-
-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);
-	}
-	
-}
+/*******************************************************************************
+ * 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 org.apache.kato.katoview.commands;
+
+import java.util.HashMap;
+import java.util.Stack;
+
+import javax.tools.diagnostics.image.Image;
+
+import org.apache.kato.katoview.Output;
+
+
+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);
+	}
+	
+}

Propchange: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/PlusCommand.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/PwdCommand.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/PwdCommand.java?rev=883384&r1=883383&r2=883384&view=diff
==============================================================================
--- incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/PwdCommand.java (original)
+++ incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/PwdCommand.java Mon Nov 23 15:53:48 2009
@@ -1,50 +1,50 @@
-/*******************************************************************************
- * 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 org.apache.kato.katoview.commands;
-
-import java.util.HashMap;
-import java.util.Stack;
-import java.io.File;
-
-import javax.tools.diagnostics.image.Image;
-
-import org.apache.kato.katoview.Output;
-
-
-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");
-	}
-}
+/*******************************************************************************
+ * 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 org.apache.kato.katoview.commands;
+
+import java.util.HashMap;
+import java.util.Stack;
+import java.io.File;
+
+import javax.tools.diagnostics.image.Image;
+
+import org.apache.kato.katoview.Output;
+
+
+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");
+	}
+}

Propchange: incubator/kato/trunk/org.apache.kato/kato.tools.katoview/src/main/java/org/apache/kato/katoview/commands/PwdCommand.java
------------------------------------------------------------------------------
    svn:eol-style = native