/*******************************************************************************
* 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.helpers;
import java.util.HashMap;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Vector;
import java.util.Stack;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.lang.reflect.Modifier;
import javax.tools.diagnostics.image.CorruptData;
import javax.tools.diagnostics.image.CorruptDataException;
import javax.tools.diagnostics.image.Image;
import javax.tools.diagnostics.image.ImageAddressSpace;
import javax.tools.diagnostics.image.ImageProcess;
import javax.tools.diagnostics.image.MemoryAccessException;
import javax.tools.diagnostics.runtime.ManagedRuntime;
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.JavaObject;
import javax.tools.diagnostics.runtime.java.JavaRuntime;
import org.apache.kato.katoview.Output;
public class Utils {
public static final String byteToAscii =
"................" +
"................" +
" !\"#$%&'()*+'-./" +
"0123456789:;<=>?" +
"@ABCDEFGHIJKLMNO" +
"PQRSTUVWXYZ[\\]^_"+
"`abcdefghijklmno" +
"pqrstuvwxyz{|}~." +
"................" +
"................" +
"................" +
"................" +
"................" +
"................" +
"................" +
"................"
;
//List of keys used by HashMap object associated with each session
public static final String CURRENT_MEM_ADDRESS = "currentMemPtrAddress";
public static final String CURRENT_NUM_BYTES_TO_PRINT = "currentNumBytes";
public static final String RootCommand_OBJECT = "RootCommandObject";
public static final String FIND_ATTRIBUTES = "FindAttributes";
public static Iterator getRuntimes(Image loadedImage)
{
Vector runtimes = new Vector();
Iterator itAddressSpace;
Iterator itProcess;
Iterator itRuntime;
ManagedRuntime mr;
ImageAddressSpace ias;
ImageProcess ip;
itAddressSpace = loadedImage.getAddressSpaces().iterator();
while (itAddressSpace.hasNext()) {
ias = (ImageAddressSpace)itAddressSpace.next();
itProcess = ias.getProcesses().iterator();
while (itProcess.hasNext())
{
ip = (ImageProcess)itProcess.next();
itRuntime = ip.getRuntimes().iterator();
while (itRuntime.hasNext()) {
// this iterator can contain ManagedRuntime or CorruptData objects
Object next = itRuntime.next();
if (next instanceof CorruptData) {
continue; // skip any CorruptData objects
} else {
mr = (ManagedRuntime)next;
if (!runtimes.contains(mr))
runtimes.add(mr);
}
}
}
}
return runtimes.iterator();
}
public static String toHex(long l)
{
return "0x" + Long.toHexString(l);
}
public static String toHex(int i)
{
return "0x" + Integer.toHexString(i);
}
public static String toHex(short s)
{
// bit-wise AND is done to cancel the sign-extension that int casting does;
// if a short's value is -1, its hex representation is 0xffff, which will be
// sign-extended to 0xffffffff when cast to an int, but we want to know the hex
// representation before the short is cast to an int, which the bit-wise AND does
return "0x" + Integer.toHexString(s & 0x0000ffff);
}
public static String toHex(byte b)
{
// bit-wise AND is done to cancel the sign-extension that int casting does;
// if a byte's value is -1, its hex representation is 0xff, which will be
// sign-extended to 0xffffffff when cast to an int, but we want to know the hex
// representation before the byte is cast to an int, which the bit-wise AND does
return "0x" + Integer.toHexString(b & 0x000000ff);
}
public static String toFixedWidthHex(long l)
{
return Utils.padWithZeroes(Long.toHexString(l), 16);
}
public static String toFixedWidthHex(int i)
{
return Utils.padWithZeroes(Integer.toHexString(i), 8);
}
public static String toFixedWidthHex(short s)
{
// bit-wise AND is done to cancel the sign-extension that int casting does;
// if a short's value is -1, its hex representation is 0xffff, which will be
// sign-extended to 0xffffffff when cast to an int, but we want to know the hex
// representation before the short is cast to an int, which the bit-wise AND does
return Utils.padWithZeroes(Integer.toHexString(s & 0x0000ffff), 4);
}
public static String toFixedWidthHex(byte b)
{
// bit-wise AND is done to cancel the sign-extension that int casting does;
// if a byte's value is -1, its hex representation is 0xff, which will be
// sign-extended to 0xffffffff when cast to an int, but we want to know the hex
// representation before the byte is cast to an int, which the bit-wise AND does
return Utils.padWithZeroes(Integer.toHexString(b & 0x000000ff), 2);
}
public static Stack constructStackFromString(String args)
{
String[] argsArray = args.split("\\s+");
return constructStackFromStringArray(argsArray);
}
public static Stack constructStackFromStringArray(String[] argsArray){
Stack s = new Stack();
for (int i = argsArray.length - 1; i >= 0; i--){
s.push(argsArray[i]);
}
return s;
}
public static String concatArgsFromStack(Stack args){
String s = "";
while(!args.empty()){
s = s.concat((String)args.pop());
}
return s;
}
public static ImageAddressSpace _extractAddressSpace(Image loadedImage)
{
ImageAddressSpace space = null;
Iterator spaces = loadedImage.getAddressSpaces().iterator();
while ((null == space) && (spaces.hasNext())) {
space = (ImageAddressSpace) spaces.next();
}
return space;
}
public static Long longFromString(String value)
{
Long translated = null;
if (null != value) {
if (value.startsWith("0x")) {
value = value.substring(2);
}
try {
translated = new Long(Long.parseLong(value, 16));
} catch (NumberFormatException e) {
translated = null;
}
}
return translated;
}
public static Long longFromStringWithPrefix(String value)
{
Long translated = null;
if (value.startsWith("0x"))
{
translated = longFromString(value);
}
return translated;
}
public static String getSignatureName(String signature)
{
Hashtable table = new Hashtable();
String retval = null;
table.put("Z", "boolean");
table.put("B", "byte");
table.put("C", "char");
table.put("S", "short");
table.put("I", "int");
table.put("J", "long");
table.put("F", "float");
table.put("D", "double");
table.put("V", "void");
if (signature.startsWith("L"))
{
StringTokenizer st = new StringTokenizer(signature.substring(1), ";");
String className;
if (st.hasMoreTokens()) {
className = st.nextToken();
if (className.startsWith("java/lang/"))
{
className = className.substring(10);
}
retval = className.replaceAll("/", ".");
} else {
// nothing or only ";"s after opening "L"
return null;
}
}
else if (signature.startsWith("["))
{
String currSig = new String(signature);
String arraySuffix = "";
while (currSig.startsWith("["))
{
arraySuffix += "[]";
currSig = currSig.substring(1);
}
retval = Utils.getSignatureName(currSig) + arraySuffix;
}
else
{
retval = (String)table.get(signature.substring(0,1));
}
return retval;
}
public static String getMethodSignatureName(String signature)
{
Hashtable table = new Hashtable();
String retval = "";
table.put("Z", "boolean");
table.put("B", "byte");
table.put("C", "char");
table.put("S", "short");
table.put("I", "int");
table.put("J", "long");
table.put("F", "float");
table.put("D", "double");
if (signature.startsWith("("))
{
StringTokenizer st = new StringTokenizer(signature.substring(1), ")");
if (st.hasMoreTokens()) {
String parameters = st.nextToken();
if (st.hasMoreTokens()) {
retval = "(" + Utils.getMethodSignatureName(parameters) + ")";
} else {
// there is nothing between "(" and ")"
retval = "()";
}
} else {
// there is no ")" after opening "("
retval = null;
}
}
else if (signature.startsWith("L"))
{
StringTokenizer st = new StringTokenizer(signature.substring(1), ";");
String className;
if (st.hasMoreTokens()) {
className = st.nextToken();
if (className.startsWith("java/lang/"))
{
className = className.substring(10);
}
retval = className.replaceAll("/", ".");
if (st.hasMoreTokens()) {
retval += ", " + Utils.getMethodSignatureName(
signature.substring(signature.indexOf(';') + 1)
);
}
} else {
// nothing or only ";"s after opening "L"
retval = null;
}
}
else if (signature.startsWith("["))
{
String currSig = new String(signature);
String arraySuffix = "";
while (currSig.startsWith("["))
{
arraySuffix += "[]";
currSig = currSig.substring(1);
}
if (currSig.startsWith("L")) {
if (currSig.indexOf(';') + 1 == currSig.length()) {
retval = Utils.getSignatureName(currSig) + arraySuffix;
} else {
retval = Utils.getMethodSignatureName(
currSig.substring(0, currSig.indexOf(';') + 1)
);
retval += arraySuffix + ", ";
retval += Utils.getMethodSignatureName(
currSig.substring(currSig.indexOf(';') + 1)
);
}
} else {
if (1 == currSig.length()) {
retval = (String)table.get(currSig) + arraySuffix;
} else {
retval = (String)table.get(currSig.substring(0,1)) + arraySuffix;
retval += ", ";
retval += Utils.getMethodSignatureName(currSig.substring(1));
}
}
}
else
{
retval = (String)table.get(signature.substring(0,1));
if (signature.length() > 1) {
retval += ", " + Utils.getMethodSignatureName(signature.substring(1));
}
}
return retval;
}
public static String getReturnValueName(String signature)
{
if (signature.startsWith("("))
{
StringTokenizer st = new StringTokenizer(signature, ")");
if (st.hasMoreTokens()) {
st.nextToken(); // we don't care what's inside the brackets
if (st.hasMoreTokens()) {
String retval = st.nextToken();
if (st.hasMoreTokens()) {
// there is more than one ")"; that's one too many
return null;
} else {
return Utils.getSignatureName(retval);
}
} else {
// there is no ")" after opening "(" or the ")" is followed by nothing
return null;
}
}
else {
// nothing after opening "("
return null;
}
}
else
{
return null;
}
}
public static String toString(String s)
{
if (null == s)
return "null";
else
return s;
}
public static File absPath(HashMap properties, String path)
{
File oldPwd = (File)properties.get("pwd");
File newPwd = new File(path);
if (!newPwd.isAbsolute())
newPwd = new File(oldPwd, path);
try {
newPwd = newPwd.getCanonicalFile();
} catch (IOException e) {
}
return newPwd;
}
public static String getVal(Object o)
{
return Utils.getVal(o, null);
}
/* public static String getVal(JavaObject jo, JavaRuntime jr)
{
//try {
// return "\t object name: " + jo.getJavaClass().getName() + "\n";
//} catch (CorruptDataException e) {
// return "\t bad name \n";
//}
//JavaField
return Utils.getVal(jo, Utils.getField(jo, jr));
}
*/
// note: this method lets you pass in a null JavaObject, but it _will_ throw a
// NullPointerException if the JavaField is not a static field when you pass it
// a null JavaObject; this is the behavior of jf.get() and jf.getString()
public static String getVal(JavaObject jo, JavaField jf)
{
Object o;
String s;
if (null == jf)
{
o = jo;
s = null;
}
else {
try {
o = jf.get(jo);
} catch (CorruptDataException e) {
o = null; // FIXME
} catch (MemoryAccessException d) {
o = null; // FIXME
} catch (NumberFormatException nfe) {
//out.print("<nfe>");
// FIXME
o = null;
}
try {
s = jf.getString(jo);
} catch (CorruptDataException e) {
s = null;
} catch (MemoryAccessException e) {
s = null;
} catch (IllegalArgumentException e) {
s = null;
}
}
return getVal(o, s);
}
public static String getVal(Object o, String str)
{
String val = "";
Long value = null;
boolean object = false;
if (null == o)
{
val += "null";
}
else
{
if (o instanceof Boolean) {
val += ((Boolean)o).toString();
} else if (o instanceof Byte) {
byte b = ((Byte)o).byteValue();
val += String.valueOf(b);
value = new Long((new Byte(b)).longValue());
} else if (o instanceof Character) {
char c = ((Character)o).charValue();
val += Utils.getPrintableWithQuotes(c);
value = new Long((new Integer((int)c).longValue()));
} else if (o instanceof Double) {
double d = ((Double)o).doubleValue();
val += String.valueOf(d);
value = new Long(Double.doubleToRawLongBits(d));
} else if (o instanceof Float) {
float f = ((Float)o).floatValue();
val += String.valueOf(f);
value = new Long(Float.floatToRawIntBits(f));
} else if (o instanceof Integer) {
int i = ((Integer)o).intValue();
val += String.valueOf(i);
value = new Long((new Integer(i)).longValue());
} else if (o instanceof Long) {
long l = ((Long)o).longValue();
val += String.valueOf(l);
value = new Long(l);
} else if (o instanceof Short) {
short s = ((Short)o).shortValue();
val += String.valueOf(s);
value = new Long((new Short(s)).longValue());
} else if (o instanceof String) {
val += (String)o;
} else if (o instanceof JavaObject) {
if (Utils.isNull((JavaObject)o)) {
val += "null";
} else {
object = true;
}
} else {
// FIXME
}
// why are we processing objects here?
// because we want control over the exceptions that are thrown
if (object)
{
JavaObject joField = (JavaObject)o;
JavaClass jcField;
String jcName;
try {
jcField = joField.getJavaClass();
} catch (CorruptDataException e) {
jcField = null;
}
try {
if (null != jcField) {
jcName = jcField.getName();
} else {
jcName = null;
}
} catch (CorruptDataException e) {
jcName = null;
}
if (null != jcName && jcName.equals("java/lang/String"))
{
if (null == str) {
val += getStringVal(joField);
} else {
val += "\"" + Utils.getPrintable(str) + "\"";
}
}
else
{
val += "<object>";
}
val += " @ ";
val += Utils.toHex(joField.getID().getAddress());
}
}
if (null != value)
{
val += " (";
val += Utils.toHex(value.longValue());
val += ")";
}
return val;
}
private static String getStringVal(JavaObject jo)
{
JavaClass jc;
try {
jc = jo.getJavaClass();
} catch (CorruptDataException e) {
return "<cannot get String class from String object (" +
Exceptions.getCorruptDataExceptionString() + ")>";
}
Iterator itJavaField = jc.getDeclaredFields().iterator();
JavaField jf = null;
while (itJavaField.hasNext())
{
jf = (JavaField)itJavaField.next();
try {
if (jf.getSignature().equals("[C") && !Modifier.isStatic(jf.getModifiers()))
break;
} catch (CorruptDataException e) {
// if we have an exception, do nothing and go onto the next field
}
}
JavaObject charArray = null;
try {
charArray = (JavaObject)jf.get(jo);
} catch (CorruptDataException e) {
return "<cannot get char array out of String (" +
Exceptions.getCorruptDataExceptionString() + ")>";
} catch (MemoryAccessException e) {
return "<cannot get char array out of String (" +
Exceptions.getMemoryAccessExceptionString() + ")>";
}
int arraySize;
try {
arraySize = charArray.getArraySize();
} catch (CorruptDataException e) {
return "<cannot determine the size of the array (" +
Exceptions.getCorruptDataExceptionString() + ")>";
}
char[] dst = new char[arraySize];
try {
charArray.arraycopy(0, dst, 0, arraySize);
} catch (CorruptDataException e) {
return "<cannot copy data from the array (" +
Exceptions.getCorruptDataExceptionString() + ")>";
} catch (MemoryAccessException e) {
return "<cannot copy data from the array (" +
Exceptions.getMemoryAccessExceptionString() + ")>";
}
return "\"" + Utils.getPrintable(new String(dst)) + "\"";
}
public static String getPrintable(char c)
{
// for a good set of test cases for this code, try using it to print the
// static char arrays of the String class; the memory addresses of these arrays
// can be found by using the command "x/j java/lang/String" and looking at the
// static fields printed at the top of the output
switch (c)
{
// the following 8 cases were taken from Section 3.10.6 of the
// Java Language Specification (2nd Edition), which can be found at
// http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#101089
case '\b':
return "\\b";
case '\t':
return "\\t";
case '\n':
return "\\n";
case '\f':
return "\\f";
case '\r':
return "\\r";
case '\"':
return "\\\"";
case '\'':
return "\\'";
case '\\':
return "\\\\";
default:
int i = (int)c;
if (i <= 255) {
if (i >= 32 && i <= 126) {
// if the character is easily printable (has an integer value between
// 32 and 126), then just print it
// note: this was determined by looking at http://www.lookuptables.com/
return String.valueOf(c);
} else {
// if the character is not easily printable, print an octal escape;
// this is done according to the Section 3.10.6 of the Java
// Language Specification (see above for reference)
return "\\" + Utils.padWithZeroes(Integer.toOctalString(i), 3);
}
} else {
// if we have a character that is not between Unicode values
// \u0000 and \u00ff, then print an escaped form of its Unicode value;
// the format was determined from Section 3.3 of the
// Java Language Specification (2nd Edition), which can be found at
// http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#100850
return "\\u" + Utils.padWithZeroes(Integer.toHexString(i), 4);
}
}
}
public static String getPrintableWithQuotes(char c)
{
return "\'" + Utils.getPrintable(c) + "\'";
}
public static String getPrintable(String s)
{
String retval = "";
for (int i = 0; i < s.length(); i++)
{
retval += Utils.getPrintable(s.charAt(i));
}
return retval;
}
public static String padWithZeroes(String unpadded, int desiredLength)
{
String output = new String(unpadded);
for (int i = unpadded.length(); i < desiredLength; i++)
{
output = "0" + output;
}
return output;
}
public static Iterator getAddressSapceSectionInfo(Image loadedImage){
Iterator itAddressSpace = loadedImage.getAddressSpaces().iterator();
Vector vSections = new Vector();
while(itAddressSpace.hasNext()){
ImageAddressSpace imageAddressSpace = (ImageAddressSpace)itAddressSpace.next();
Iterator iSections = imageAddressSpace.getImageSections().iterator();
while(iSections.hasNext()){
vSections.add(iSections.next());
}
}
return vSections.iterator();
}
public static String getModifierString(int modifiers){
String retval = "";
if(Modifier.isPublic(modifiers)) retval += "public ";
if(Modifier.isPrivate(modifiers)) retval += "private ";
if(Modifier.isProtected(modifiers)) retval += "protected ";
if(Modifier.isStatic(modifiers)) retval += "static ";
if(Modifier.isAbstract(modifiers)) retval += "abstract ";
if(Modifier.isFinal(modifiers)) retval += "final ";
if(Modifier.isSynchronized(modifiers)) retval += "synchronized ";
if(Modifier.isVolatile(modifiers)) retval += "volatile ";
if(Modifier.isTransient(modifiers)) retval += "transient ";
if(Modifier.isNative(modifiers)) retval += "native ";
if(Modifier.isInterface(modifiers)) retval += "interface ";
if(Modifier.isStrict(modifiers)) retval += "strict ";
return retval;
}
public static boolean isNull(JavaObject jo)
{
return jo.getID().getAddress() == 0;
}
public static String padWithSpaces(String unpadded, int desiredLength)
{
String output = new String(unpadded);
for (int i = unpadded.length(); i < desiredLength; i++)
{
output += " ";
}
return output;
}
public static String prePadWithSpaces(String unpadded, int desiredLength)
{
String output = "";
for (int i = unpadded.length(); i < desiredLength; i++)
{
output += " ";
}
output += unpadded;
return output;
}
public static JavaClass getClassGivenName(String className, JavaRuntime jr, Output out)
{
Iterator itJavaClassLoader = jr.getJavaClassLoaders().iterator();
boolean found = false;
JavaClass jc = null;
while (itJavaClassLoader.hasNext() && !found)
{
JavaClassLoader jcl = (JavaClassLoader)itJavaClassLoader.next();
Iterator itJavaClass = jcl.getDefinedClasses().iterator();
while (itJavaClass.hasNext() && !found)
{
jc = (JavaClass)itJavaClass.next();
String currClassName;
try {
currClassName = jc.getName();
} catch (CorruptDataException e) {
out.print("\t <error getting class name while traversing classes: ");
out.print(Exceptions.getCorruptDataExceptionString());
out.print(">\n");
currClassName = null;
continue;
}
if (currClassName.equals(className))
{
found = true;
}
}
}
if (found) {
return jc;
} else {
return null;
}
}
}