| /* |
| * 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); |
| } |
| } |
| } |
| } |
| } |