diff agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children ba764ed4b6f2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,1269 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot;
+
+import java.io.*;
+import java.math.*;
+import java.util.*;
+import java.util.regex.*;
+
+import sun.jvm.hotspot.types.Type;
+import sun.jvm.hotspot.types.Field;
+import sun.jvm.hotspot.HotSpotTypeDataBase;
+import sun.jvm.hotspot.types.basic.BasicType;
+import sun.jvm.hotspot.types.CIntegerType;
+import sun.jvm.hotspot.code.*;
+import sun.jvm.hotspot.compiler.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.interpreter.*;
+import sun.jvm.hotspot.memory.*;
+import sun.jvm.hotspot.oops.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.utilities.*;
+import sun.jvm.hotspot.utilities.soql.*;
+import sun.jvm.hotspot.ui.classbrowser.*;
+import sun.jvm.hotspot.ui.tree.*;
+import sun.jvm.hotspot.tools.*;
+import sun.jvm.hotspot.tools.ObjectHistogram;
+import sun.jvm.hotspot.tools.StackTrace;
+
+public class CommandProcessor {
+    public abstract static class DebuggerInterface {
+        public abstract HotSpotAgent getAgent();
+        public abstract boolean isAttached();
+        public abstract void attach(String pid);
+        public abstract void attach(String java, String core);
+        public abstract void detach();
+        public abstract void reattach();
+    }
+
+    static class Tokens {
+        final String input;
+        int i;
+        String[] tokens;
+        int length;
+
+        String[] splitWhitespace(String cmd) {
+            String[] t = cmd.split("\\s");
+            if (t.length == 1 && t[0].length() == 0) {
+                return new String[0];
+            }
+            return t;
+        }
+
+        void add(String s, ArrayList t) {
+            if (s.length() > 0) {
+                t.add(s);
+            }
+        }
+
+        Tokens(String cmd) {
+            input = cmd;
+
+            // check for quoting
+            int quote = cmd.indexOf('"');
+            ArrayList t = new ArrayList();
+            if (quote != -1) {
+                while (cmd.length() > 0) {
+                    if (quote != -1) {
+                        int endquote = cmd.indexOf('"', quote + 1);
+                        if (endquote == -1) {
+                            throw new RuntimeException("mismatched quotes: " + input);
+                        }
+
+                        String before = cmd.substring(0, quote).trim();
+                        String quoted = cmd.substring(quote + 1, endquote);
+                        cmd = cmd.substring(endquote + 1).trim();
+                        if (before.length() > 0) {
+                            String[] w = splitWhitespace(before);
+                            for (int i = 0; i < w.length; i++) {
+                                add(w[i], t);
+                            }
+                        }
+                        add(quoted, t);
+                        quote = cmd.indexOf('"');
+                    } else {
+                        String[] w = splitWhitespace(cmd);
+                        for (int i = 0; i < w.length; i++) {
+                            add(w[i], t);
+                        }
+                        cmd = "";
+
+                    }
+                }
+            } else {
+                String[] w = splitWhitespace(cmd);
+                for (int i = 0; i < w.length; i++) {
+                    add(w[i], t);
+                }
+            }
+            tokens = (String[])t.toArray(new String[0]);
+            i = 0;
+            length = tokens.length;
+
+            //for (int i = 0; i < tokens.length; i++) {
+            //    System.out.println("\"" + tokens[i] + "\"");
+            //}
+        }
+
+        String nextToken() {
+            return tokens[i++];
+        }
+        boolean hasMoreTokens() {
+            return i < length;
+        }
+        int countTokens() {
+            return length - i;
+        }
+        void trim(int n) {
+            if (length >= n) {
+                length -= n;
+            } else {
+                throw new IndexOutOfBoundsException(String.valueOf(n));
+            }
+        }
+        String join(String sep) {
+            StringBuffer result = new StringBuffer();
+            for (int w = i; w < length; w++) {
+                result.append(tokens[w]);
+                if (w + 1 < length) {
+                    result.append(sep);
+                }
+            }
+            return result.toString();
+        }
+
+        String at(int i) {
+            if (i < 0 || i >= length) {
+                throw new IndexOutOfBoundsException(String.valueOf(i));
+            }
+            return tokens[i];
+        }
+    }
+
+
+    abstract class Command {
+        Command(String n, String u, boolean ok) {
+            name = n;
+            usage = u;
+            okIfDisconnected = ok;
+        }
+
+        Command(String n, boolean ok) {
+            name = n;
+            usage = n;
+            okIfDisconnected = ok;
+        }
+
+        final String name;
+        final String usage;
+        final boolean okIfDisconnected;
+        abstract void doit(Tokens t);
+        void usage() {
+            out.println("Usage: " + usage);
+        }
+
+        void printOopValue(Oop oop) {
+            if (oop != null) {
+                Klass k = oop.getKlass();
+                Symbol s = k.getName();
+                if (s != null) {
+                    out.print("Oop for " + s.asString() + " @ ");
+                } else {
+                    out.print("Oop @ ");
+                }
+                Oop.printOopAddressOn(oop, out);
+            } else {
+                out.print("null");
+            }
+        }
+
+        void printNode(SimpleTreeNode node) {
+            int count = node.getChildCount();
+            for (int i = 0; i < count; i++) {
+                try {
+                    SimpleTreeNode field = node.getChild(i);
+                    if (field instanceof OopTreeNodeAdapter) {
+                        out.print(field);
+                        out.print(" ");
+                        printOopValue(((OopTreeNodeAdapter)field).getOop());
+                        out.println();
+                    } else {
+                        out.println(field);
+                    }
+                } catch (Exception e) {
+                    out.println();
+                    out.println("Error: " + e);
+                    if (verboseExceptions) {
+                        e.printStackTrace(out);
+                    }
+                }
+            }
+        }
+    }
+
+    void quote(String s) {
+        if (s.indexOf(" ") == -1) {
+            out.print(s);
+        } else {
+            out.print("\"");
+            out.print(s);
+            out.print("\"");
+        }
+    }
+
+    void dumpType(Type type) {
+        out.print("type ");
+        quote(type.getName());
+        out.print(" ");
+        if (type.getSuperclass() != null) {
+            quote(type.getSuperclass().getName());
+            out.print(" ");
+        } else {
+            out.print("null ");
+        }
+        out.print(type.isOopType());
+        out.print(" ");
+        if (type.isCIntegerType()) {
+            out.print("true ");
+            out.print(((CIntegerType)type).isUnsigned());
+            out.print(" ");
+        } else {
+            out.print("false false ");
+        }
+        out.print(type.getSize());
+        out.println();
+    }
+
+    void dumpFields(Type type) {
+        Iterator i = type.getFields();
+        while (i.hasNext()) {
+            Field f = (Field) i.next();
+            out.print("field ");
+            quote(type.getName());
+            out.print(" ");
+            out.print(f.getName());
+            out.print(" ");
+            quote(f.getType().getName());
+            out.print(" ");
+            out.print(f.isStatic());
+            out.print(" ");
+            if (f.isStatic()) {
+                out.print("0 ");
+                out.print(f.getStaticFieldAddress());
+            } else {
+                out.print(f.getOffset());
+                out.print(" 0x0");
+            }
+            out.println();
+        }
+    }
+
+
+    Address lookup(String symbol) {
+        if (symbol.indexOf("::") != -1) {
+            String[] parts = symbol.split("::");
+            StringBuffer mangled = new StringBuffer("__1c");
+            for (int i = 0; i < parts.length; i++) {
+                int len = parts[i].length();
+                if (len >= 26) {
+                    mangled.append((char)('a' + (len / 26)));
+                    len = len % 26;
+                }
+                mangled.append((char)('A' + len));
+                mangled.append(parts[i]);
+            }
+            mangled.append("_");
+            symbol = mangled.toString();
+        }
+        return VM.getVM().getDebugger().lookup(null, symbol);
+    }
+
+    Address parseAddress(String addr) {
+        return VM.getVM().getDebugger().parseAddress(addr);
+    }
+
+    private final Command[] commandList = {
+        new Command("reattach", true) {
+            public void doit(Tokens t) {
+                int tokens = t.countTokens();
+                if (tokens != 0) {
+                    usage();
+                    return;
+                }
+                preAttach();
+                debugger.reattach();
+                postAttach();
+            }
+        },
+        new Command("attach", "attach pid | exec core", true) {
+            public void doit(Tokens t) {
+                int tokens = t.countTokens();
+                if (tokens == 1) {
+                    preAttach();
+                    debugger.attach(t.nextToken());
+                    postAttach();
+                } else if (tokens == 2) {
+                    preAttach();
+                    debugger.attach(t.nextToken(), t.nextToken());
+                    postAttach();
+                } else {
+                    usage();
+                }
+            }
+        },
+        new Command("detach", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 0) {
+                    usage();
+                } else {
+                    debugger.detach();
+                }
+            }
+        },
+        new Command("examine", "examine [ address/count ] | [ address,address]", false) {
+            Pattern args1 = Pattern.compile("^(0x[0-9a-f]+)(/([0-9]*)([a-z]*))?$");
+            Pattern args2 = Pattern.compile("^(0x[0-9a-f]+),(0x[0-9a-f]+)(/[a-z]*)?$");
+
+            String fill(Address a, int width) {
+                String s = "0x0";
+                if (a != null) {
+                    s = a.toString();
+                }
+                if (s.length() != width) {
+                    return s.substring(0, 2) + "000000000000000000000".substring(0, width - s.length()) + s.substring(2);
+                }
+                return s;
+            }
+
+            public void doit(Tokens t) {
+                if (t.countTokens() != 1) {
+                    usage();
+                } else {
+                    String arg = t.nextToken();
+                    Matcher m1 = args1.matcher(arg);
+                    Matcher m2 = args2.matcher(arg);
+                    Address start = null;
+                    Address end   = null;
+                    String format = "";
+                    int formatSize = (int)VM.getVM().getAddressSize();
+
+                    if (m1.matches()) {
+                        start = VM.getVM().getDebugger().parseAddress(m1.group(1));
+                        int count = 1;
+                        if (m1.group(2) != null) {
+                            count = Integer.parseInt(m1.group(3));
+                        }
+                        end = start.addOffsetTo(count * formatSize);
+                    } else if (m2.matches()) {
+                        start = VM.getVM().getDebugger().parseAddress(m2.group(1));
+                        end   = VM.getVM().getDebugger().parseAddress(m2.group(2));
+                    } else {
+                        usage();
+                        return;
+                    }
+                    int line = 80;
+                    int formatWidth = formatSize * 8 / 4 + 2;
+
+                    out.print(fill(start, formatWidth));
+                    out.print(": ");
+                    int width = line - formatWidth - 2;
+
+                    boolean needsPrintln = true;
+                    while (start != null && start.lessThan(end)) {
+                        Address val = start.getAddressAt(0);
+                        out.print(fill(val, formatWidth));
+                        needsPrintln = true;
+                        width -= formatWidth;
+                        start = start.addOffsetTo(formatSize);
+                        if (width <= formatWidth) {
+                            out.println();
+                            needsPrintln = false;
+                            if (start.lessThan(end)) {
+                                out.print(fill(start, formatWidth));
+                                out.print(": ");
+                                width = line - formatWidth - 2;
+                            }
+                        } else {
+                            out.print(" ");
+                            width -= 1;
+                        }
+                    }
+                    if (needsPrintln) {
+                        out.println();
+                    }
+                }
+            }
+        },
+        new Command("findpc", "findpc address", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 1) {
+                    usage();
+                } else {
+                    Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
+                    PointerLocation loc = PointerFinder.find(a);
+                    loc.printOn(out);
+                }
+            }
+        },
+        new Command("flags", "flags [ flag ]", false) {
+            public void doit(Tokens t) {
+                int tokens = t.countTokens();
+                if (tokens != 0 && tokens != 1) {
+                    usage();
+                } else {
+                    String name = tokens > 0 ? t.nextToken() : null;
+
+                    VM.Flag[] flags = VM.getVM().getCommandLineFlags();
+                    if (flags == null) {
+                        out.println("Command Flag info not available (use 1.4.1_03 or later)!");
+                    } else {
+                        boolean printed = false;
+                        for (int f = 0; f < flags.length; f++) {
+                            VM.Flag flag = flags[f];
+                            if (name == null || flag.getName().equals(name)) {
+                                out.println(flag.getName() + " = " + flag.getValue());
+                                printed = true;
+                            }
+                        }
+                        if (name != null && !printed) {
+                            out.println("Couldn't find flag: " + name);
+                        }
+                    }
+                }
+            }
+        },
+        new Command("help", "help [ command ]", true) {
+            public void doit(Tokens t) {
+                int tokens = t.countTokens();
+                Command cmd = null;
+                if (tokens == 1) {
+                    cmd = findCommand(t.nextToken());
+                }
+
+                if (cmd != null) {
+                    cmd.usage();
+                } else if (tokens == 0) {
+                    out.println("Available commands:");
+                    Object[] keys = commands.keySet().toArray();
+                    Arrays.sort(keys, new Comparator() {
+                             public int compare(Object o1, Object o2) {
+                                 return o1.toString().compareTo(o2.toString());
+                             }
+                          });
+                    for (int i = 0; i < keys.length; i++) {
+                        out.print("  ");
+                        out.println(((Command)commands.get(keys[i])).usage);
+                    }
+                }
+            }
+        },
+        new Command("history", "history", true) {
+            public void doit(Tokens t) {
+                int tokens = t.countTokens();
+                if (tokens != 0 && (tokens != 1 || !t.nextToken().equals("-h"))) {
+                    usage();
+                    return;
+                }
+                boolean printIndex = tokens == 0;
+                for (int i = 0; i < history.size(); i++) {
+                    if (printIndex) out.print(i + " ");
+                    out.println(history.get(i));
+                }
+            }
+        },
+        new Command("inspect", "inspect expression", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 1) {
+                    usage();
+                } else {
+                    Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
+                    SimpleTreeNode node = null;
+                    if (VM.getVM().getUniverse().heap().isInReserved(a)) {
+                        OopHandle handle = a.addOffsetToAsOopHandle(0);
+                        Oop oop = VM.getVM().getObjectHeap().newOop(handle);
+                        node = new OopTreeNodeAdapter(oop, null);
+
+                        out.println("instance of " + node.getValue() + " @ " + a +
+                                    " (size = " + oop.getObjectSize() + ")");
+                    } else if (VM.getVM().getCodeCache().contains(a)) {
+                        CodeBlob blob = VM.getVM().getCodeCache().findBlobUnsafe(a);
+                        a = blob.headerBegin();
+                    }
+                    if (node == null) {
+                        Type type = VM.getVM().getTypeDataBase().guessTypeForAddress(a);
+                        if (type != null) {
+                            out.println("Type is " + type.getName() + " (size of " + type.getSize() + ")");
+                            node = new CTypeTreeNodeAdapter(a, type, null);
+                        }
+                    }
+                    if (node != null) {
+                        printNode(node);
+                    }
+                }
+            }
+        },
+        new Command("jhisto", "jhisto", false) {
+            public void doit(Tokens t) {
+                 ObjectHistogram histo = new ObjectHistogram();
+                 histo.run(out, err);
+            }
+        },
+        new Command("jstack", "jstack [-v]", false) {
+            public void doit(Tokens t) {
+                boolean verbose = false;
+                if (t.countTokens() > 0 && t.nextToken().equals("-v")) {
+                    verbose = true;
+                }
+                StackTrace jstack = new StackTrace(verbose, true);
+                jstack.run(out);
+            }
+        },
+        new Command("print", "print expression", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 1) {
+                    usage();
+                } else {
+                    Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
+                    HTMLGenerator gen = new HTMLGenerator(false);
+                    out.println(gen.genHTML(a));
+                }
+            }
+        },
+        new Command("printas", "printas type expression", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 2) {
+                    usage();
+                } else {
+                    Type type = agent.getTypeDataBase().lookupType(t.nextToken());
+                    Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
+                    CTypeTreeNodeAdapter node = new CTypeTreeNodeAdapter(a, type, null);
+
+                    out.println("pointer to " + type + " @ " + a +
+                                " (size = " + type.getSize() + ")");
+                    printNode(node);
+                }
+            }
+        },
+        new Command("symbol", "symbol name", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 1) {
+                    usage();
+                } else {
+                    String symbol = t.nextToken();
+                    Address a = lookup(symbol);
+                    out.println(symbol + " = " + a);
+                }
+            }
+        },
+        new Command("printstatics", "printstatics [ type ]", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() > 1) {
+                    usage();
+                } else {
+                    if (t.countTokens() == 0) {
+                        out.println("All known static fields");
+                        printNode(new CTypeTreeNodeAdapter(agent.getTypeDataBase().getTypes()));
+                    } else {
+                        Type type = agent.getTypeDataBase().lookupType(t.nextToken());
+                        out.println("Static fields of " + type.getName());
+                        printNode(new CTypeTreeNodeAdapter(type));
+                    }
+                }
+            }
+        },
+        new Command("pmap", "pmap", false) {
+            public void doit(Tokens t) {
+                PMap pmap = new PMap();
+                pmap.run(out, debugger.getAgent().getDebugger());
+            }
+        },
+        new Command("pstack", "pstack [-v]", false) {
+            public void doit(Tokens t) {
+                boolean verbose = false;
+                if (t.countTokens() > 0 && t.nextToken().equals("-v")) {
+                    verbose = true;
+                }
+                PStack pstack = new PStack(verbose, true);
+                pstack.run(out, debugger.getAgent().getDebugger());
+            }
+        },
+        new Command("quit", true) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 0) {
+                    usage();
+                } else {
+                    debugger.detach();
+                    System.exit(0);
+                }
+            }
+        },
+        new Command("echo", "echo [ true | false ]", true) {
+            public void doit(Tokens t) {
+                if (t.countTokens() == 0) {
+                    out.println("echo is " + doEcho);
+                } else if (t.countTokens() == 1) {
+                    doEcho = Boolean.valueOf(t.nextToken()).booleanValue();
+                } else {
+                    usage();
+                }
+            }
+        },
+        new Command("versioncheck", "versioncheck [ true | false ]", true) {
+            public void doit(Tokens t) {
+                if (t.countTokens() == 0) {
+                    out.println("versioncheck is " +
+                                (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null));
+                } else if (t.countTokens() == 1) {
+                    if (Boolean.valueOf(t.nextToken()).booleanValue()) {
+                        System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", null);
+                    } else {
+                        System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", "true");
+                    }
+                } else {
+                    usage();
+                }
+            }
+        },
+        new Command("scanoops", "scanoops start end [ type ]", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 2 && t.countTokens() != 3) {
+                    usage();
+                } else {
+                    long stride = VM.getVM().getAddressSize();
+                    Address base = VM.getVM().getDebugger().parseAddress(t.nextToken());
+                    Address end  = VM.getVM().getDebugger().parseAddress(t.nextToken());
+                    Klass klass = null;
+                    if (t.countTokens() == 1) {
+                        klass = SystemDictionaryHelper.findInstanceKlass(t.nextToken());
+                    }
+                    while (base != null && base.lessThan(end)) {
+                        long step = stride;
+                        OopHandle handle = base.addOffsetToAsOopHandle(0);
+                        if (RobustOopDeterminator.oopLooksValid(handle)) {
+                            try {
+                                Oop oop = VM.getVM().getObjectHeap().newOop(handle);
+                                if (klass == null || oop.getKlass().isSubtypeOf(klass))
+                                    out.println(handle.toString() + " " + oop.getKlass().getName().asString());
+                                step = oop.getObjectSize();
+                            } catch (UnknownOopException ex) {
+                                // ok
+                            } catch (RuntimeException ex) {
+                                ex.printStackTrace();
+                            }
+                        }
+                        base = base.addOffsetTo(step);
+                    }
+                }
+            }
+        },
+        new Command("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) {
+                    usage();
+                    return;
+                }
+                if (t.countTokens() == 1) {
+                    Type type = agent.getTypeDataBase().lookupType(t.nextToken());
+                    dumpFields(type);
+                } else if (t.countTokens() == 0) {
+                    Iterator i = agent.getTypeDataBase().getTypes();
+                    while (i.hasNext()) {
+                        dumpFields((Type)i.next());
+                    }
+                } else {
+                    BasicType containingType = (BasicType)agent.getTypeDataBase().lookupType(t.nextToken());
+
+                    String fieldName = t.nextToken();
+
+                    // The field's Type must already be in the database -- no exceptions
+                    Type fieldType = agent.getTypeDataBase().lookupType(t.nextToken());
+
+                    boolean isStatic = Boolean.valueOf(t.nextToken()).booleanValue();
+                    long offset = Long.parseLong(t.nextToken());
+                    Address staticAddress = parseAddress(t.nextToken());
+                    if (isStatic && staticAddress == null) {
+                        staticAddress = lookup(containingType.getName() + "::" + fieldName);
+                    }
+
+                    // check to see if the field already exists
+                    Iterator i = containingType.getFields();
+                    while (i.hasNext()) {
+                        Field f = (Field) i.next();
+                        if (f.getName().equals(fieldName)) {
+                            if (f.isStatic() != isStatic) {
+                                throw new RuntimeException("static/nonstatic mismatch: " + t.input);
+                            }
+                            if (!isStatic) {
+                                if (f.getOffset() != offset) {
+                                    throw new RuntimeException("bad redefinition of field offset: " + t.input);
+                                }
+                            } else {
+                                if (!f.getStaticFieldAddress().equals(staticAddress)) {
+                                    throw new RuntimeException("bad redefinition of field location: " + t.input);
+                                }
+                            }
+                            if (f.getType() != fieldType) {
+                                throw new RuntimeException("bad redefinition of field type: " + t.input);
+                            }
+                            return;
+                        }
+                    }
+
+                    // Create field by type
+                    HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
+                    db.createField(containingType,
+                                   fieldName, fieldType,
+                                   isStatic,
+                                   offset,
+                                   staticAddress);
+
+                }
+            }
+
+        },
+        new Command("tokenize", "tokenize ...", true) {
+            public void doit(Tokens t) {
+                while (t.hasMoreTokens()) {
+                    out.println("\"" + t.nextToken() + "\"");
+                }
+            }
+        },
+        new Command("type", "type [ type [ name super isOop isInteger isUnsigned size ] ]", true) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) {
+                    usage();
+                    return;
+                }
+                if (t.countTokens() == 6) {
+                    String typeName = t.nextToken();
+                    String superclassName = t.nextToken();
+                    if (superclassName.equals("null")) {
+                        superclassName = null;
+                    }
+                    boolean isOop = Boolean.valueOf(t.nextToken()).booleanValue();
+                    boolean isInteger = Boolean.valueOf(t.nextToken()).booleanValue();
+                    boolean isUnsigned = Boolean.valueOf(t.nextToken()).booleanValue();
+                    long size = Long.parseLong(t.nextToken());
+
+                    BasicType type = null;
+                    try {
+                        type = (BasicType)agent.getTypeDataBase().lookupType(typeName);
+                    } catch (RuntimeException e) {
+                    }
+                    if (type != null) {
+                        if (type.isOopType() != isOop) {
+                            throw new RuntimeException("oop mismatch in type definition: " + t.input);
+                        }
+                        if (type.isCIntegerType() != isInteger) {
+                            throw new RuntimeException("integer type mismatch in type definition: " + t.input);
+                        }
+                        if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) {
+                            throw new RuntimeException("unsigned mismatch in type definition: " + t.input);
+                        }
+                        if (type.getSuperclass() == null) {
+                            if (superclassName != null) {
+                                if (type.getSize() == -1) {
+                                    type.setSuperclass(agent.getTypeDataBase().lookupType(superclassName));
+                                } else {
+                                    throw new RuntimeException("unexpected superclass in type definition: " + t.input);
+                                }
+                            }
+                        } else {
+                            if (superclassName == null) {
+                                throw new RuntimeException("missing superclass in type definition: " + t.input);
+                            }
+                            if (!type.getSuperclass().getName().equals(superclassName)) {
+                                throw new RuntimeException("incorrect superclass in type definition: " + t.input);
+                            }
+                        }
+                        if (type.getSize() != size) {
+                            if (type.getSize() == -1) {
+                                type.setSize(size);
+                            }
+                            throw new RuntimeException("size mismatch in type definition: " + t.input);
+                        }
+                        return;
+                    }
+
+                    // Create type
+                    HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
+                    db.createType(typeName, superclassName, isOop, isInteger, isUnsigned, size);
+                } else if (t.countTokens() == 1) {
+                    Type type = agent.getTypeDataBase().lookupType(t.nextToken());
+                    dumpType(type);
+                } else {
+                    Iterator i = agent.getTypeDataBase().getTypes();
+                    while (i.hasNext()) {
+                        dumpType((Type)i.next());
+                    }
+                }
+            }
+
+        },
+        new Command("source", "source filename", true) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 1) {
+                    usage();
+                    return;
+                }
+                String file = t.nextToken();
+                BufferedReader savedInput = in;
+                try {
+                    BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
+                    in = input;
+                    run(false);
+                } catch (Exception e) {
+                    out.println("Error: " + e);
+                    if (verboseExceptions) {
+                        e.printStackTrace(out);
+                    }
+                } finally {
+                    in = savedInput;
+                }
+
+            }
+        },
+        new Command("search", "search [ heap | codecache | threads ] value", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 2) {
+                    usage();
+                } else {
+                    String type = t.nextToken();
+                    final Address value = VM.getVM().getDebugger().parseAddress(t.nextToken());
+                    final long stride = VM.getVM().getAddressSize();
+                    if (type.equals("threads")) {
+                        Threads threads = VM.getVM().getThreads();
+                        for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+                            Address base = thread.getBaseOfStackPointer();
+                            Address end = thread.getLastJavaSP();
+                            if (end == null) continue;
+                            if (end.lessThan(base)) {
+                                Address tmp = base;
+                                base = end;
+                                end = tmp;
+                            }
+                            out.println("Searching " + base + " " + end);
+                            while (base != null && base.lessThan(end)) {
+                                Address val = base.getAddressAt(0);
+                                if (AddressOps.equal(val, value)) {
+                                    out.println(base);
+                                }
+                                base = base.addOffsetTo(stride);
+                            }
+                        }
+                    } else if (type.equals("heap")) {
+                        RawHeapVisitor iterator = new RawHeapVisitor() {
+                                public void prologue(long used) {
+                                }
+
+                                public void visitAddress(Address addr) {
+                                    Address val = addr.getAddressAt(0);
+                                    if (AddressOps.equal(val, value)) {
+                                        out.println("found at " + addr);
+                                    }
+                                }
+
+                                public void epilogue() {
+                                }
+                            };
+                        VM.getVM().getObjectHeap().iterateRaw(iterator);
+                    } else if (type.equals("codecache")) {
+                        CodeCacheVisitor v = new CodeCacheVisitor() {
+                                public void prologue(Address start, Address end) {
+                                }
+                                public void visit(CodeBlob blob) {
+                                    boolean printed = false;
+                                    Address base = blob.getAddress();
+                                    Address end = base.addOffsetTo(blob.getSize());
+                                    while (base != null && base.lessThan(end)) {
+                                        Address val = base.getAddressAt(0);
+                                        if (AddressOps.equal(val, value)) {
+                                            if (!printed) {
+                                                printed = true;
+                                                blob.printOn(out);
+                                            }
+                                            out.println("found at " + base + "\n");
+                                        }
+                                        base = base.addOffsetTo(stride);
+                                    }
+                                }
+                                public void epilogue() {
+                                }
+
+
+                            };
+                        VM.getVM().getCodeCache().iterate(v);
+
+                    }
+                }
+            }
+        },
+        new Command("where", "where { -a | id }", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 1) {
+                    usage();
+                } else {
+                    String name = t.nextToken();
+                    Threads threads = VM.getVM().getThreads();
+                    boolean all = name.equals("-a");
+                    for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+                        StringWriter sw = new StringWriter();
+                        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                        thread.printThreadIDOn(new PrintStream(bos));
+                        if (all || bos.toString().equals(name)) {
+                            HTMLGenerator gen = new HTMLGenerator(false);
+                            out.println(gen.genHTMLForJavaStackTrace(thread));
+                            if (!all) return;
+                        }
+                    }
+                    if (!all) out.println("Couldn't find thread " + name);
+                }
+            }
+        },
+
+        new Command("threads", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 0) {
+                    usage();
+                } else {
+                    Threads threads = VM.getVM().getThreads();
+                    for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+                        thread.printThreadIDOn(out);
+                        out.println(" " + thread.getThreadName());
+                    }
+                }
+            }
+        },
+
+        new Command("livenmethods", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 0) {
+                    usage();
+                } else {
+                    ArrayList nmethods = new ArrayList();
+                    Threads threads = VM.getVM().getThreads();
+                    HTMLGenerator gen = new HTMLGenerator(false);
+                    for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+                        try {
+                            for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
+                                if (vf instanceof CompiledVFrame) {
+                                    NMethod c = ((CompiledVFrame)vf).getCode();
+                                    if (!nmethods.contains(c)) {
+                                        nmethods.add(c);
+                                        out.println(gen.genHTML(c));
+                                    }
+                                }
+                            }
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                    }
+                }
+            }
+        },
+        new Command("universe", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 0) {
+                    usage();
+                } else {
+                    Universe u = VM.getVM().getUniverse();
+                    out.println("Heap Parameters:");
+                    u.heap().printOn(out);
+                }
+            }
+        },
+        new Command("verbose", "verbose true | false", true) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 1) {
+                    usage();
+                } else {
+                    verboseExceptions = Boolean.valueOf(t.nextToken()).booleanValue();
+                }
+            }
+        },
+        new Command("assert", "assert true | false", true) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 1) {
+                    usage();
+                } else {
+                    Assert.ASSERTS_ENABLED = Boolean.valueOf(t.nextToken()).booleanValue();
+                }
+            }
+        },
+    };
+
+    private boolean verboseExceptions = false;
+    private ArrayList history = new ArrayList();
+    private HashMap commands = new HashMap();
+    private boolean doEcho = false;
+
+    private Command findCommand(String key) {
+        return (Command)commands.get(key);
+    }
+
+    public void printPrompt() {
+        out.print("hsdb> ");
+    }
+
+    private DebuggerInterface debugger;
+    private HotSpotAgent agent;
+    private JSJavaScriptEngine jsengine;
+    private BufferedReader in;
+    private PrintStream out;
+    private PrintStream err;
+
+    // called before debuggee attach
+    private void preAttach() {
+        // nothing for now..
+    }
+
+    // called after debuggee attach
+    private void postAttach() {
+        // create JavaScript engine and start it
+        jsengine = new JSJavaScriptEngine() {
+                        private ObjectReader reader = new ObjectReader();
+                        private JSJavaFactory factory = new JSJavaFactoryImpl();
+                        public ObjectReader getObjectReader() {
+                            return reader;
+                        }
+                        public JSJavaFactory getJSJavaFactory() {
+                            return factory;
+                        }
+                        protected void quit() {
+                            debugger.detach();
+                            System.exit(0);
+                        }
+                        protected BufferedReader getInputReader() {
+                            return in;
+                        }
+                        protected PrintStream getOutputStream() {
+                            return out;
+                        }
+                        protected PrintStream getErrorStream() {
+                            return err;
+                        }
+                   };
+        try {
+            jsengine.defineFunction(this,
+                     this.getClass().getMethod("registerCommand",
+                                new Class[] {
+                                     String.class, String.class, String.class
+                                }));
+        } catch (NoSuchMethodException exp) {
+            // should not happen, see below...!!
+            exp.printStackTrace();
+        }
+        jsengine.start();
+    }
+
+    public void registerCommand(String cmd, String usage, final String func) {
+        commands.put(cmd, new Command(cmd, usage, false) {
+                              public void doit(Tokens t) {
+                                  final int len = t.countTokens();
+                                  Object[] args = new Object[len];
+                                  for (int i = 0; i < len; i++) {
+                                      args[i] = t.nextToken();
+                                  }
+                                  jsengine.call(func, args);
+                              }
+                          });
+    }
+
+    public void setOutput(PrintStream o) {
+        out = o;
+    }
+
+    public void setErr(PrintStream e) {
+        err = e;
+    }
+
+    public CommandProcessor(DebuggerInterface debugger, BufferedReader in, PrintStream out, PrintStream err) {
+        this.debugger = debugger;
+        this.agent = debugger.getAgent();
+        this.in = in;
+        this.out = out;
+        this.err = err;
+        for (int i = 0; i < commandList.length; i++) {
+            Command c = commandList[i];
+            commands.put(c.name, c);
+        }
+        if (debugger.isAttached()) {
+            postAttach();
+        }
+    }
+
+
+    public void run(boolean prompt) {
+        // Process interactive commands.
+        while (true) {
+            if (prompt) printPrompt();
+            String ln = null;
+            try {
+                ln = in.readLine();
+            } catch (IOException e) {
+            }
+            if (ln == null) {
+                if (prompt) err.println("Input stream closed.");
+                return;
+            }
+
+            executeCommand(ln);
+        }
+    }
+
+    static Pattern historyPattern = Pattern.compile("((!\\*)|(!\\$)|(!!-?)|(!-?[0-9][0-9]*))");
+
+    public void executeCommand(String ln) {
+        if (ln.indexOf('!') != -1) {
+            int size = history.size();
+            if (size == 0) {
+                ln = "";
+                err.println("History is empty");
+            } else {
+                StringBuffer result = new StringBuffer();
+                Matcher m = historyPattern.matcher(ln);
+                int start = 0;
+                while (m.find()) {
+                    if (m.start() > start) {
+                        result.append(ln.substring(start, m.start() - start));
+                    }
+                    start = m.end();
+
+                    String cmd = m.group();
+                    if (cmd.equals("!!")) {
+                        result.append((String)history.get(history.size() - 1));
+                    } else if (cmd.equals("!!-")) {
+                        Tokens item = new Tokens((String)history.get(history.size() - 1));
+                        item.trim(1);
+                        result.append(item.join(" "));
+                    } else if (cmd.equals("!*")) {
+                        Tokens item = new Tokens((String)history.get(history.size() - 1));
+                        item.nextToken();
+                        result.append(item.join(" "));
+                    } else if (cmd.equals("!$")) {
+                        Tokens item = new Tokens((String)history.get(history.size() - 1));
+                        result.append(item.at(item.countTokens() - 1));
+                    } else {
+                        String tail = cmd.substring(1);
+                        int index = Integer.parseInt(tail);
+                        if (index < 0) {
+                            index = history.size() + index;
+                        }
+                        if (index > size) {
+                            err.println("No such history item");
+                        } else {
+                            result.append((String)history.get(index));
+                        }
+                    }
+                }
+                if (result.length() == 0) {
+                    err.println("malformed history reference");
+                    ln = "";
+                } else {
+                    if (start < ln.length()) {
+                        result.append(ln.substring(start));
+                    }
+                    ln = result.toString();
+                    if (!doEcho) {
+                        out.println(ln);
+                    }
+                }
+            }
+        }
+
+        if (doEcho) {
+            out.println("+ " + ln);
+        }
+
+        PrintStream redirect = null;
+        Tokens t = new Tokens(ln);
+        if (t.hasMoreTokens()) {
+            boolean error = false;
+            history.add(ln);
+            int len = t.countTokens();
+            if (len > 2) {
+                String r = t.at(len - 2);
+                if (r.equals(">") || r.equals(">>")) {
+                    boolean append = r.length() == 2;
+                    String file = t.at(len - 1);
+                    try {
+                        redirect = new PrintStream(new BufferedOutputStream(new FileOutputStream(file, append)));
+                        t.trim(2);
+                    } catch (Exception e) {
+                        out.println("Error: " + e);
+                        if (verboseExceptions) {
+                            e.printStackTrace(out);
+                        }
+                        error = true;
+                    }
+                }
+            }
+            if (!error) {
+                PrintStream savedout = out;
+                if (redirect != null) {
+                    out = redirect;
+                }
+                try {
+                    executeCommand(t);
+                } catch (Exception e) {
+                    err.println("Error: " + e);
+                    if (verboseExceptions) {
+                        e.printStackTrace(err);
+                    }
+                } finally {
+                    if (redirect != null) {
+                        out = savedout;
+                        redirect.close();
+                    }
+                }
+            }
+        }
+    }
+
+    void executeCommand(Tokens args) {
+        String cmd = args.nextToken();
+
+        Command doit = findCommand(cmd);
+
+        /*
+         * Check for an unknown command
+         */
+        if (doit == null) {
+            out.println("Unrecognized command.  Try help...");
+        } else if (!debugger.isAttached() && !doit.okIfDisconnected) {
+            out.println("Command not valid until the attached to a VM");
+        } else {
+            try {
+                doit.doit(args);
+            } catch (Exception e) {
+                out.println("Error: " + e);
+                if (verboseExceptions) {
+                    e.printStackTrace(out);
+                }
+            }
+        }
+    }
+}