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/04/08 14:51:47 UTC

svn commit: r763261 - in /incubator/kato/trunk/trunk/org.apache.kato.example: ./ .settings/ src/ src/org/ src/org/apache/ src/org/apache/kato/ src/org/apache/kato/example/

Author: monteith
Date: Wed Apr  8 14:51:47 2009
New Revision: 763261

URL: http://svn.apache.org/viewvc?rev=763261&view=rev
Log:
Check in an example that shows how to use the Apache Kato API to print out the contents of all the objects and arrays
on a heap.

Added:
    incubator/kato/trunk/trunk/org.apache.kato.example/.classpath   (with props)
    incubator/kato/trunk/trunk/org.apache.kato.example/.project   (with props)
    incubator/kato/trunk/trunk/org.apache.kato.example/.settings/
    incubator/kato/trunk/trunk/org.apache.kato.example/.settings/org.eclipse.jdt.core.prefs   (with props)
    incubator/kato/trunk/trunk/org.apache.kato.example/src/
    incubator/kato/trunk/trunk/org.apache.kato.example/src/org/
    incubator/kato/trunk/trunk/org.apache.kato.example/src/org/apache/
    incubator/kato/trunk/trunk/org.apache.kato.example/src/org/apache/kato/
    incubator/kato/trunk/trunk/org.apache.kato.example/src/org/apache/kato/example/
    incubator/kato/trunk/trunk/org.apache.kato.example/src/org/apache/kato/example/ObjectFields.java   (with props)

Added: incubator/kato/trunk/trunk/org.apache.kato.example/.classpath
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/trunk/org.apache.kato.example/.classpath?rev=763261&view=auto
==============================================================================
--- incubator/kato/trunk/trunk/org.apache.kato.example/.classpath (added)
+++ incubator/kato/trunk/trunk/org.apache.kato.example/.classpath Wed Apr  8 14:51:47 2009
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/sun160"/>
+	<classpathentry kind="lib" path="/ApacheKatoDependencies/libs/kato.api-head.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

Propchange: incubator/kato/trunk/trunk/org.apache.kato.example/.classpath
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/kato/trunk/trunk/org.apache.kato.example/.project
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/trunk/org.apache.kato.example/.project?rev=763261&view=auto
==============================================================================
--- incubator/kato/trunk/trunk/org.apache.kato.example/.project (added)
+++ incubator/kato/trunk/trunk/org.apache.kato.example/.project Wed Apr  8 14:51:47 2009
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.apache.kato.example</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Propchange: incubator/kato/trunk/trunk/org.apache.kato.example/.project
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/kato/trunk/trunk/org.apache.kato.example/.settings/org.eclipse.jdt.core.prefs
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/trunk/org.apache.kato.example/.settings/org.eclipse.jdt.core.prefs?rev=763261&view=auto
==============================================================================
--- incubator/kato/trunk/trunk/org.apache.kato.example/.settings/org.eclipse.jdt.core.prefs (added)
+++ incubator/kato/trunk/trunk/org.apache.kato.example/.settings/org.eclipse.jdt.core.prefs Wed Apr  8 14:51:47 2009
@@ -0,0 +1,12 @@
+#Tue Apr 07 18:45:08 BST 2009
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error

Propchange: incubator/kato/trunk/trunk/org.apache.kato.example/.settings/org.eclipse.jdt.core.prefs
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/kato/trunk/trunk/org.apache.kato.example/src/org/apache/kato/example/ObjectFields.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/trunk/org.apache.kato.example/src/org/apache/kato/example/ObjectFields.java?rev=763261&view=auto
==============================================================================
--- incubator/kato/trunk/trunk/org.apache.kato.example/src/org/apache/kato/example/ObjectFields.java (added)
+++ incubator/kato/trunk/trunk/org.apache.kato.example/src/org/apache/kato/example/ObjectFields.java Wed Apr  8 14:51:47 2009
@@ -0,0 +1,499 @@
+/*******************************************************************************
+ * 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.example;
+
+import java.lang.reflect.Array;
+import java.util.Iterator;
+
+import org.apache.kato.image.CorruptData;
+import org.apache.kato.image.CorruptDataException;
+import org.apache.kato.image.DTFJException;
+import org.apache.kato.image.ImagePointer;
+import org.apache.kato.image.MemoryAccessException;
+import org.apache.kato.java.JavaClass;
+import org.apache.kato.java.JavaField;
+import org.apache.kato.java.JavaHeap;
+import org.apache.kato.java.JavaObject;
+import org.apache.kato.java.JavaRuntime;
+
+/**
+ * This examples walks over all objects on the heap and prints the values
+ * of all of the fields, and the contents of all elements of all the arrays.
+ * 
+ * The example starts with walkObjectFields(JavaRuntime), so it's not a complete
+ * example.
+ * 
+ * 
+ * The following API interfaces are used:
+ * 	JavaRuntime
+ * 		JavaHeap
+ * 			JavaObject
+ * 				JavaClass
+ * 					JavaField
+ * 
+ * It is useful to consider the classes as being analogues of the Java reflection classes.
+ * The equivalence is:
+ * 
+ * JavaObject	java.lang.Object
+ * JavaClass	java.lang.Class
+ * JavaField	java.lang.reflect.Field
+ * 
+ * Here is some example output:
+
+JavaObject @ 0x100f7270
+	java/lang/UnsatisfiedLinkError:
+	  java/lang/LinkageError:
+	    java/lang/Error:
+	      java/lang/Throwable:
+	        Ljava/lang/Object; backtrace = [Ljava/lang/Object;: @ 0x100f70d8
+	        Ljava/lang/String; detailMessage = java/lang/String: @ 0x100f7108java/lang/String: @ 0x100f7108 = "/home/monteith/IBMJava2-142/jre/bin/libCrash.so: /home/monteith/IBMJava2-142/jre/bin/libCrash.so: cannot open shared object file: No such file or directory"
+	        Ljava/lang/Throwable; cause = <null reference>
+	        [Ljava/lang/StackTraceElement; stackTrace = <null reference>
+	        java/lang/Object:
+JavaObject @ 0x100f7290
+	java/lang/String:
+	  [C value = [C: @ 0x100f72b0
+	  I offset = 0
+	  I count = 30
+	  I hash = 0
+	  java/lang/Object:
+JavaObject @ 0x100f72b0
+	[C[30] = {
+		j,
+		a,
+		v,
+		a,
+		.,
+		l,
+		a,
+		n,
+		g,
+		.,
+		U,
+		n,
+		s,
+		a,
+		t,
+		i,
+		s,
+		f,
+		i,
+		e,
+		d,
+		L,
+		i,
+		n,
+		k,
+		E,
+		r,
+		r,
+		o,
+		r,
+	};
+
+ */
+public class ObjectFields {
+	
+	/**
+	 * Given a JavaRuntime, print out all of the objects on the heap.
+	 * 
+	 * @param jr JavaRuntime to get objects from
+	 */
+	public void walkObjectFields(JavaRuntime jr) {
+		
+		/* First get the iterator for all of the heaps.
+		 * A JVM's heap may split across different heaps, e.g.
+		 * nurseries, system heap, large object heap.
+		 */
+		Iterator heaps = jr.getHeaps();
+		
+		
+		/* What follows is a typical pattern, 
+		 * iterate, check type, handle data or handle corrupt data,
+		 * continue.
+		 */
+		while (heaps.hasNext()) {
+			Object next = heaps.next();
+			
+			// This is the normal case.
+			if (next instanceof JavaHeap) {
+				walkHeap ((JavaHeap) next);
+			} 
+			// As per the JavaDoc, expect CorruptData.
+			else if (next instanceof CorruptData) {
+				// We have a string to print out and an address.
+				System.err.println("Corrupt Heap instance \"" + next + "\"" +
+						pointerToHexString(((CorruptData)next).getAddress()));
+				continue;
+			}
+			
+		} // while (heaps.hasNext())		
+	}
+	
+	/**
+	 * Walks over all objects on the heap.
+	 * 
+	 * @param heap JavaHeap to iterate over.
+	 */
+	public void walkHeap(JavaHeap heap) {
+		Iterator objects = heap.getObjects();
+		
+		// Follow same pattern as walkObjectFields
+		while (objects.hasNext()) {
+			Object next = objects.next();
+			
+			/* The heap has only JavaObjects on it. Not JavaClasses,
+			 * but JavaObjects of type java/lang/Class will be encountered.
+			 */
+			if (next instanceof JavaObject) {
+				JavaObject jObject = (JavaObject) next;
+				
+				/* Some objects are arrays, while they are JavaObjects.
+				 * They are handled differently.
+				 */
+				try {
+					if (jObject.isArray()) {
+						walkArray (jObject);
+					} else {
+						walkObject (jObject);
+					}
+					
+					// Even determining whether or not the JavaObject is an array has difficulties.
+				} catch (CorruptDataException e) {
+					System.err.println("Corrupt data exception calling jObject.isArray() at "+
+							pointerToHexString(jObject.getID()));
+					e.printStackTrace();
+				}
+ 			} 
+			
+			/* Iterators return a mix of objects - either what you expected
+			 * or a CorruptData object.
+			 */
+			else if (next instanceof CorruptData) {
+				// We have a string to print out and an address.
+				System.err.println("Corrupt Heap instance \"" + next + "\"" +
+						pointerToHexString(((CorruptData)next).getAddress()));
+				continue;
+			}
+				
+				
+		} // while (objects.next()
+	}
+	
+	/**
+	 * Prints out all of the values of the fields in an object, along with
+	 * identifying information of the type itself.
+	 * 
+	 * <br/>To print out the values of an objects fields, we do the following:
+	 * 
+	 * <ol>
+	 * <li>Get the object's type - a JavaClass.</li>
+	 * <li>Retrieve the fields (JavaField) from that JavaClass.</li>
+	 * <li>Call the JavaField's get methods, passing the JavaObject, printing out the values.</li>
+	 * <li>Get the type's superclass (another JavaClass), if it's not null, repeat from 2.</li>
+	 * </ol>
+	 * 
+	 * @param jObject A JavaObject
+	 */
+	public void walkObject(JavaObject jObject) {
+	
+		
+		// Just identify the object by its ID - this would the address on the heap.
+		System.out.println("JavaObject @ " + pointerToHexString(jObject.getID()));
+		// Handle indentation.
+		String prefix = "\t";
+		
+		/* Get the type of this object.
+		 * A common mistake is to call "Class Object.getClass()".
+		 * 
+		 * If we can't get the type, print error and return - there is nothing
+		 * to be done here. It's important that the iterator either finishes or
+		 * continues past the bad object.
+		 */		
+		JavaClass clazz;
+		try {
+			clazz = jObject.getJavaClass();
+		} catch (CorruptDataException e) {
+			System.err.println(prefix+"Error getting JavaClass");
+			e.printStackTrace();
+			return;
+		}
+		
+		/* The fields in a class are only the fields for that class.
+		 * The superclasses fields must retreived from the superclasses. 
+		 * 
+		 * Some classes don't have a superclass - null is used to indicate this.
+		 */
+		while (clazz != null) {
+			// print out the name of the class and the the fields.
+			try {
+				System.out.println( prefix + clazz.getName() +":");
+				prefix += "  ";
+			
+				Iterator fields = clazz.getDeclaredFields();
+			
+				/* Print out all fields for this class.
+				 */
+				while (fields.hasNext()) {
+					Object nextField = fields.next();
+					
+					if (nextField instanceof JavaField) {
+						printField(prefix, (JavaField) nextField, jObject);						
+					} else if (nextField instanceof CorruptData) {
+						System.err.println("Error getting field. " + nextField);
+					}
+				} // while (fields.hasNext())
+			} catch (DTFJException e) {
+				System.err.println("Error printing out fields.");
+				e.printStackTrace();
+			}
+			
+			// Get the next superclass.
+			try {
+				clazz = clazz.getSuperclass();
+			} catch (CorruptDataException e) {
+				
+				e.printStackTrace();
+				break;
+			}
+			
+		} // while (class != null)
+	}
+	
+	/**
+	 * Print out the content of one field.
+	 * Only prints out instance fields. Will return if a
+	 * static field is passed.
+	 * 
+	 * @param prefix Pad out message
+	 * @param field The field to print
+	 * @param object The object to print out
+	 * @throws CorruptDataException if something goes wrong
+	 * @throws MemoryAccessException 
+	 */
+	private void printField(String prefix, JavaField field, JavaObject object) throws CorruptDataException, MemoryAccessException {
+
+		/* Modifier is fully qualified to indicate that some constants are not held by the API,
+		 * but reused from the existing reflection API.
+		 * This is testing the field to see if it is static. The getModifiers method is
+		 * held within the JavaMember interface. Here the resemblance to Java reflection is more
+		 * pronounced.
+		 */
+		if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
+			return;
+		}
+		
+		/* Get the value of a field. This call will suit for all
+		 * field types, primitives and references.
+		 * A java.lang.Integer instance would be returned as a JavaObject, not as an Integer,
+		 * but a primitive int field will be returned as an Integer.
+		 * There are methods that can be used to return the primitives directly, the
+		 * JavaMember.getSignature() methods would have to be used in order to determine the
+		 * field's type.
+		 * 
+		 */
+		Object fieldValue = field.get(object);
+		
+		String valueString = "";
+		
+		// Format the field's value. 
+		if(fieldValue == null) {
+			valueString = "<null reference>";
+			
+			// Most of the primitive fields can be handled as Number instances.
+		} else if (fieldValue instanceof Number) {
+			valueString = fieldValue.toString();
+		} else if (fieldValue instanceof Character) {
+			valueString = "`" + (Character)fieldValue + "'";
+		} else if (fieldValue instanceof Boolean) {
+			valueString = ((Boolean) fieldValue).booleanValue() ? "true" : "false";
+		} else if (fieldValue instanceof JavaObject) {
+			// Note how we have to get an instance of the object to know anything about it.
+			JavaObject reference = (JavaObject) fieldValue;
+			
+			// classname: @ 0xadddress
+			valueString = reference.getJavaClass().getName() + ": @ " + pointerToHexString(reference.getID());
+			
+			/* We can get the actual String as it would appear if printed on the running JVM using
+			 * the JavaField.getString() method. 
+			 * To do this, we have to identify the object referenced as a java.lang.String.
+			 * We use a string comparision against the referenced object's class name rather than using
+			 * JavaField.getSignature(), as that could simply be a java.lang.Object reference.
+			 * 
+			 * This is the only means of translating a JavaObject into a String instance without
+			 * examining the referenced JavaObject fields using the API.
+			 */
+			if ("java/lang/String".equals(reference.getJavaClass().getName())) {
+				valueString += valueString +" = \"" + field.getString(object) + "\"";
+			}
+			
+		}
+		// The JavaField.get() method doesn't return CorruptData - it throws CorruptDataException and
+		// MemoryAccessException
+		
+		/* Print out the value of the field, prefixed by its signature and name.
+		 * The signature will come out in the internal, compact format. This could
+		 * be expanded with more code into Java language style.
+		 * 
+		 * For example, a string would be "Ljava/lang/String;", a string array
+		 * would be "[Ljava/lang/String;", a byte would be "B", a boolean array
+		 * would be "[Z".
+		 * 
+		 */ 
+		System.out.println(prefix + field.getSignature() + " " + 
+				field.getName() + " = " + valueString);		
+	}
+
+	/**
+	 * Print out the contents of an array.
+	 * 
+	 * @param jObject JavaObject of an array.
+	 */
+	public void walkArray(JavaObject object) {
+		// Just identify the object by its ID - this would the address on the heap.
+		System.out.println("JavaObject @ " + pointerToHexString(object.getID()));
+		// Handle indentation.
+		String prefix = "\t";
+		String className;
+		
+		JavaClass clazz;
+		try {
+			clazz = object.getJavaClass();
+		} catch (CorruptDataException e) {
+			System.err.println("Unable to determine array's JavaClass. aborting");
+			e.printStackTrace();
+			return;
+		}
+		
+		// The class name is needed to determine the element types
+		try {
+			className = clazz.getName();
+		} catch (CorruptDataException e) {
+			System.err.println("Error getting Array class name.");
+			e.printStackTrace();
+			return;
+		}
+
+		
+		int arraySize = 0;
+
+		/* This gets the number of elements in the array.
+		 * It should not be confused with JavaObject.getSize() which
+		 * is the size of the array on the heap.
+		 */ 
+		try {
+			arraySize = object.getArraySize();
+		} catch (CorruptDataException e) {
+			System.err.println("Unable to get object size.");
+			e.printStackTrace();
+			return;
+		}		
+		
+		String componentName;
+		try {
+			componentName = clazz.getComponentType().getName();
+		} catch (CorruptDataException e) {
+			System.err.println("Unable to determine component type name. Quitting.");
+			e.printStackTrace();
+			return;
+		}
+		
+		Object arrayCopy;
+		
+		/* Create an instance of the array that JavaObject.arraycopy()
+		 * will copy into. Must be of correct type.
+		 * 
+		 * There exist classes that directly represent the primitive types.
+		 * See Javadoc for java.lang.Class.
+		 * 
+		 * i.e. an actual class called "int", not "java/lang/Integer".
+		 */
+		if ("boolean".equals(componentName)) {
+			arrayCopy = new boolean[arraySize];
+		} else if ("byte".equals(componentName)) {
+			arrayCopy = new byte[arraySize];
+		} else if ("char".equals(componentName)) {
+			arrayCopy = new char[arraySize];
+		} else if ("short".equals(componentName)) {
+			arrayCopy = new short[arraySize];
+		} else if ("int".equals(componentName)) {
+			arrayCopy = new int[arraySize];
+		} else if ("long".equals(componentName)) {
+			arrayCopy = new long[arraySize];
+		} else if ("float".equals(componentName)) {
+			arrayCopy = new float[arraySize];
+		} else if ("double".equals(componentName)) {
+			arrayCopy = new double[arraySize];
+		} else {
+			// Anything element that is not a primitive must be a reference type.
+			arrayCopy = new JavaObject[arraySize];
+		}
+							
+		/* Copy the contents of the JavaObject array into the array we prepared earlier.
+		 * This is the only way to get the values of an array in a dump.
+		 */
+		try {
+			object.arraycopy(0, arrayCopy, 0, arraySize);
+		} catch (CorruptDataException e) {
+			e.printStackTrace();
+			return;
+		} catch (MemoryAccessException e) {
+			e.printStackTrace();
+			return;
+		} catch (IllegalArgumentException e){
+			e.printStackTrace();
+			return;
+		} catch (IndexOutOfBoundsException e) {
+			e.printStackTrace();
+			return;
+		}
+		
+		/* Go through every element in the copy of the array and print out its contents.
+		 * This example uses java.lang.Array.get() to make this easy to handle generically.
+		 * 
+		 * Object references - JavaObjects - are only printed out at the type name @ an address.
+		 * We don't print out subarrays - they will be encountered later in the heap anyhow.
+		 */
+		System.out.println("\t" + className + "[" + arraySize +"] = {");
+		for (int cnt=0; cnt < arraySize; cnt++) {
+			Object obj = Array.get(arrayCopy, cnt);
+			
+			if (obj == null) {
+				System.out.println("\t\tnull,");
+			} else if (obj instanceof JavaObject) {
+				JavaObject refObj = (JavaObject) obj;
+				try {
+					System.out.println("\t\t" + refObj.getJavaClass().getName()+ " @ "+
+							pointerToHexString(refObj.getID())+",");
+				} catch (CorruptDataException e) {
+					System.err.println("\t\t CorruptDataException while printing out array element");
+					e.printStackTrace();
+				}
+			} else {
+				System.out.println("\t\t"+obj+",");
+			}
+		}
+		System.out.println("\t};");
+	}
+	
+	/**
+	 * Takes ImagePointer and returns it as a hex string. Perhaps this should be defined
+	 * behaviour for ImagePointer.toString().
+	 * @param pointer ImagePointer
+	 * @return Address of pointer as a hex string prefixed with "0x"
+	 */
+	public static String pointerToHexString(ImagePointer pointer) {
+		return "0x"+Long.toHexString(pointer.getAddress());
+	}
+}

Propchange: incubator/kato/trunk/trunk/org.apache.kato.example/src/org/apache/kato/example/ObjectFields.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain