blob: 458e97195db1e738e5ffa257d56e1d1ac7081896 [file] [log] [blame]
/*
* 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);
}
}
}
}
}