netscape-revival
sun-java/classsrc/sun/tools/debug/RemoteAgent.java
/*
* @(#)RemoteAgent.java 1.45 96/01/31
*
* Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies. Please refer to the file "copyright.html"
* for further important copyright and licensing information.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*/
package sun.tools.debug;
import java.io.*;
import java.net.*;
import java.util.*;
import java.lang.SecurityManager;
class RemoteAgent implements AgentConstants {
/* The agent socket */
private Socket socket;
/* The input stream from the remote agent */
private DataInputStream in;
/* The output stream to the remote agent */
private DataOutputStream out;
/* Hashtable of active objects */
private Hashtable objects = new Hashtable();
/* The DebuggerCallback object. */
private DebuggerCallback client;
/* The client side of the Agent's stdout redirector */
private AgentIn debugIn = null;
private Thread debugInThread = null;
private RemoteClass classObject;
RemoteClass classClass;
RemoteClass classString;
boolean closeRemoteInterpreter = false;
private RemoteThreadGroup systemThreadGroup;
private boolean verbose = false;
private boolean closing = false;
private int readPassword(String s) {
int cookie = 0;
int radix = PSWDCHARS.length();
for (int i = 0; i < s.length(); i++) {
int x = PSWDCHARS.indexOf(s.charAt(i));
if (x == -1) {
return 0; // bad password
}
cookie = (cookie * radix) + x;
}
int port = 0;
for (int i = 0; i < 8; i++) {
int bits = (cookie & (6 << (i * 3)));
port |= (bits >> (i + 1));
}
return port;
}
/* Connect to a remote agent */
RemoteAgent(String host, String password, String javaArgs,
DebuggerCallback client, boolean verbose) throws Exception {
this.verbose = verbose;
if (host == InetAddress.getLocalHost().getHostName() &&
password == null) {
// No remote (or local) interpreter to debug, so spawn one.
SecurityManager.setScopePermission();
String slash = System.getProperty("file.separator");
String cmd = new String(System.getProperty("java.home") +
slash + "bin" + slash +
"java_g -debug " + javaArgs +
" sun.tools.debug.EmptyApp");
SecurityManager.resetScopePermission();
Process pr = Runtime.getRuntime().exec(cmd);
DataInputStream dis = new DataInputStream(pr.getInputStream());
String agentStatus = dis.readLine();
if (agentStatus == null) {
error("Failed to exec a child java interpreter.");
System.exit(1);
}
password = agentStatus.substring(agentStatus.indexOf("=") + 1);
message("password returned: " + password);
closeRemoteInterpreter = true;
}
this.client = client;
socket = new Socket(host, readPassword(password));
debugIn = new AgentIn(this, new Socket(host, getDebugPort()),
client, verbose);
debugInThread = new Thread(debugIn, "Agent input");
debugInThread.start();
in = new DataInputStream(new
BufferedInputStream(socket.getInputStream()));
out = new DataOutputStream(new
BufferedOutputStream(socket.getOutputStream()));
message("connected");
/* Check that agent is the same version */
int version = in.readInt();
if (version != AGENT_VERSION) {
System.err.println(
"Version mismatch between debugger and remote agent.");
System.exit(1);
}
/* Load current Agent classes */
classObject = (RemoteClass)readValue(in);
classClass = (RemoteClass)readValue(in);
classString = (RemoteClass)readValue(in);
message("loading classes ...");
int nClasses = in.readInt();
for (int i = 0 ; i < nClasses ; i++) {
RemoteClass c = (RemoteClass)readValue(in);
}
systemThreadGroup = (RemoteThreadGroup)readValue(in);
setVerbose(verbose);
}
/* Return the socket port being used. */
int getDebugPort() {
return socket.getPort();
}
/* Read in a remote source file. */
InputStream getSourceFile(String clsName, String name) throws Exception {
synchronized (out) {
out.write(CMD_GET_SOURCE_FILE);
out.writeUTF(name);
out.writeUTF(clsName);
try {
getReply(CMD_GET_SOURCE_FILE);
} catch (Exception e) {
return null;
}
int length = in.readInt();
if (length == -1) {
return null;
}
message("getSourceFile: allocating " + length + " bytes.");
byte buffer[] = new byte[length];
try {
in.readFully(buffer);
} catch (IOException e) {
error("unable to read " + name);
return null;
}
return new ByteArrayInputStream(buffer);
}
}
/* Ask a remote object for a string description of itself. */
String objectToString(int id) {
synchronized (out) {
try {
out.write(CMD_OBJECT_TO_STRING);
out.writeInt(id);
getReply(CMD_OBJECT_TO_STRING);
return in.readUTF();
} catch (Exception ex) {
return("<communication error>");
}
}
}
/* Close the connection */
void close() {
message("close(" + closeRemoteInterpreter + ")");
closing = true;
try {
SecurityManager.setScopePermission();
debugInThread.stop();
SecurityManager.resetScopePermission();
if (closeRemoteInterpreter) {
synchronized (out) {
out.write(CMD_QUIT);
getReply(CMD_QUIT);
}
}
socket.close();
} catch (Exception e) {}
}
/* Get an object from the cache */
RemoteObject get(Integer h) {
return (RemoteObject)objects.get(h);
}
/* Put an object in the cache */
private void put(Integer h, RemoteObject obj) {
objects.put(h, obj);
}
/* Read a value */
RemoteValue readValue(DataInputStream in) throws Exception {
while(true) {
int type = in.readInt();
switch (type) {
case TP_OBJECT: {
int id = in.readInt();
if (id == 0) {
return null;
}
Integer h = new Integer(id);
RemoteClass c = (RemoteClass)get(h);
if (c == null) {
put(h, c = new RemoteClass(this, id));
}
id = in.readInt();
h = new Integer(id);
RemoteObject obj = get(h);
if (obj == null) {
put(h, obj = new RemoteObject(this, id, c));
}
return obj;
}
case TP_CLASS: {
int id = in.readInt();
Integer h = new Integer(id);
RemoteClass c = (RemoteClass)get(h);
if (c == null) {
put(h, c = new RemoteClass(this, id));
}
return c;
}
case TP_THREAD: {
int id = in.readInt();
Integer h = new Integer(id);
RemoteClass c = (RemoteClass)get(h);
if (c == null) {
put(h, c = new RemoteClass(this, id));
}
id = in.readInt();
h = new Integer(id);
RemoteThread t = (RemoteThread)get(h);
if (t == null) {
put(h, t = new RemoteThread(this, id, c));
}
return t;
}
case TP_THREADGROUP: {
int id = in.readInt();
Integer h = new Integer(id);
RemoteClass c = (RemoteClass)get(h);
if (c == null) {
put(h, c = new RemoteClass(this, id));
}
id = in.readInt();
h = new Integer(id);
RemoteThreadGroup tg = (RemoteThreadGroup)get(h);
if (tg == null) {
SecurityManager.setScopePermission();
put(h, tg = new RemoteThreadGroup(this, id, c));
}
return tg;
}
case TP_STRING: {
int id = in.readInt();
Integer h = new Integer(id);
RemoteString s = (RemoteString)get(h);
if (s == null) {
put(h, s = new RemoteString(this, id));
}
return s;
}
case TC_ARRAY: {
int id = in.readInt();
if (id == 0) {
return null;
}
Integer h = new Integer(id);
RemoteClass c = (RemoteClass)get(h);
if (c == null) {
put(h, c = new RemoteClass(this, id));
}
id = in.readInt();
h = new Integer(id);
int size = in.readInt();
RemoteArray array = (RemoteArray)get(h);
if (array == null) {
put(h, array = new RemoteArray(this, id, c, size));
}
return array;
}
case TC_BOOLEAN:
return (RemoteValue)(new RemoteBoolean(in.readBoolean()));
case TC_BYTE:
return (RemoteValue)(new RemoteByte(in.readByte()));
case TC_CHAR:
return (RemoteValue)(new RemoteChar(in.readChar()));
case TC_SHORT:
return (RemoteValue)(new RemoteShort(in.readShort()));
case TC_INT:
return (RemoteValue)(new RemoteInt(in.readInt()));
case TC_LONG:
return (RemoteValue)(new RemoteLong(in.readLong()));
case TC_FLOAT:
return (RemoteValue)(new RemoteFloat(in.readFloat()));
case TC_DOUBLE:
return (RemoteValue)(new RemoteDouble(in.readDouble()));
default: {
error("invalid type code: " + type);
return null;
}
}
}
}
/* get a reply */
private void getReply(int cmd) throws Exception {
out.flush();
while (true) {
int c = 0;
try {
c = in.readInt();
} catch (EOFException e) {
if (!closing) {
error("unexpected eof");
}
return;
}
if (c == CMD_EXCEPTION) {
Exception e = new Exception(in.readUTF());
throw e;
} else if (c != cmd) {
error("unexpected reply: wanted " + cmd + ", got " + c);
} else {
return;
}
}
}
/* List the currently known classes. */
RemoteClass[] listClasses() throws Exception {
synchronized (out) {
out.write(CMD_LIST_CLASSES);
getReply(CMD_LIST_CLASSES);
int n = in.readInt();
message("reading " + n + " classes...");
RemoteClass list[] = new RemoteClass[n];
for (int i = 0 ; i < n ; i++) {
list[i] = (RemoteClass)readValue(in);
}
return list;
}
}
/* Find a specified class. */
RemoteClass findClass(String name) throws Exception {
RemoteClass list[] = listClasses();
for (int i = 0; i < list.length; i++) {
String className = list[i].getName();
/* Try full name (ie "java.lang.Object") */
if (name.equals(className)) {
return list[i];
}
/* Next, try short name (ie "Object") */
int iDot = className.lastIndexOf(".");
if (iDot >= 0 && className.length() > iDot) {
className = className.substring(iDot + 1);
}
if (name.equals(className)) {
return list[i];
}
}
return getClassByName(name);
}
/* List threadgroups */
RemoteThreadGroup[] listThreadGroups(RemoteThreadGroup tg)
throws Exception {
RemoteThreadGroup list[] = null;
synchronized (out) {
out.write(CMD_LIST_THREADGROUPS);
out.writeInt((tg == null) ? 0 : tg.getId());
getReply(CMD_LIST_THREADGROUPS);
int n = in.readInt();
SecurityManager.setScopePermission();
list = new RemoteThreadGroup[n];
SecurityManager.resetScopePermission();
message("listThreadGroups: " + n + " groups");
for (int i = 0 ; i < n ; i++) {
list[i] = (RemoteThreadGroup)readValue(in);
}
}
return list;
}
/* List a threadgroup's threads */
RemoteThread[] listThreads(RemoteThreadGroup tg,
boolean recurse) throws Exception {
synchronized (out) {
out.write(CMD_LIST_THREADS);
out.writeInt((tg == null) ? systemThreadGroup.getId() : tg.getId());
out.writeBoolean(recurse);
getReply(CMD_LIST_THREADS);
int n = in.readInt();
RemoteThread list[] = new RemoteThread[n];
for (int i = 0 ; i < n ; i++) {
list[i] = (RemoteThread)readValue(in);
}
return list;
}
}
/* Suspend a specified thread. */
void suspendThread(int id) throws Exception {
synchronized (out) {
out.write(CMD_SUSPEND_THREAD);
out.writeInt(id);
getReply(CMD_SUSPEND_THREAD);
}
}
/* Resume a specified thread. */
void resumeThread(int id) throws Exception {
synchronized (out) {
out.write(CMD_RESUME_THREAD);
out.writeInt(id);
getReply(CMD_RESUME_THREAD);
}
}
/* Dump a thread's stack. */
RemoteStackFrame[] dumpStack(RemoteThread thread) throws Exception {
synchronized (out) {
out.write(CMD_GET_STACK_TRACE);
out.writeInt(thread.getId());
getReply(CMD_GET_STACK_TRACE);
int n = in.readInt();
RemoteStackFrame list[] = new RemoteStackFrame[n];
for (int i = 0 ; i < n ; i++) {
RemoteObject remoteFrame = (RemoteObject)readValue(in);
list[i] = new RemoteStackFrame(remoteFrame, thread, i, this);
list[i].className = in.readUTF();
list[i].methodName = in.readUTF();
list[i].lineno = in.readInt();
list[i].pc = in.readInt();
list[i].setRemoteClass((RemoteClass)readValue(in));
int nVars = in.readInt();
list[i].localVariables = new LocalVariable[nVars];
for (int j = 0; j < nVars; j++) {
LocalVariable lvar = new LocalVariable();
lvar.slot = in.readInt();
lvar.name = in.readUTF();
lvar.signature = in.readUTF();
lvar.methodArgument = in.readBoolean();
message("lvar " + j + ": slot=" + lvar.slot +
", name=" + lvar.name + ", sig=" +
lvar.signature + ", arg=" + lvar.methodArgument);
list[i].localVariables[j] = lvar;
}
}
return list;
}
}
/* Stop the specified thread */
void stopThread(int id) throws Exception {
synchronized (out) {
out.write(CMD_STOP_THREAD);
out.writeInt(id);
getReply(CMD_STOP_THREAD);
}
}
/* Stop the specified threadgroup */
void stopThreadGroup(int id) throws Exception {
synchronized (out) {
out.write(CMD_STOP_THREAD_GROUP);
out.writeInt(id);
getReply(CMD_STOP_THREAD_GROUP);
}
}
/* Get the class name of a class */
void getClassInfo(RemoteClass c) throws Exception {
synchronized (out) {
out.write(CMD_GET_CLASS_INFO);
out.writeInt(c.id);
getReply(CMD_GET_CLASS_INFO);
c.name = in.readUTF();
c.sourceName = in.readUTF();
c.intf = in.readInt() != 0;
c.superclass = (RemoteClass)readValue(in);
c.loader = (RemoteObject)readValue(in);
c.interfaces = new RemoteClass[in.readInt()];
for (int i = 0 ; i < c.interfaces.length ; i++) {
c.interfaces[i] = (RemoteClass)readValue(in);
}
}
}
/* Get a remote class by name */
RemoteClass getClassByName(String name) throws Exception {
synchronized (out) {
out.write(CMD_GET_CLASS_BY_NAME);
out.writeUTF(name);
getReply(CMD_GET_CLASS_BY_NAME);
return (RemoteClass)readValue(in);
}
}
/* Get threadgroup internal information */
void getThreadGroupInfo(RemoteThreadGroup c) throws Exception {
synchronized (out) {
out.write(CMD_GET_THREADGROUP_INFO);
out.writeInt(c.id);
getReply(CMD_GET_THREADGROUP_INFO);
c.parent = (RemoteThreadGroup)readValue(in);
c.name = in.readUTF();
c.maxPriority = in.readInt();
c.daemon = in.readBoolean();
}
}
/* Get the name of a thread */
String getThreadName(int id) throws Exception {
synchronized (out) {
out.write(CMD_GET_THREAD_NAME);
out.writeInt(id);
getReply(CMD_GET_THREAD_NAME);
return in.readUTF();
}
}
/* Get the current status of a thread */
int getThreadStatus(int id) throws Exception {
synchronized (out) {
out.write(CMD_GET_THREAD_STATUS);
out.writeInt(id);
getReply(CMD_GET_THREAD_STATUS);
return in.readInt();
}
}
/* Free all unreferenced objects */
void gc(RemoteObject[] objs) throws Exception {
synchronized (out) {
out.write(CMD_MARK_OBJECTS);
/* Send a list of all objects we want to keep. */
out.writeInt(objs.length);
for (int i = 0; i < objs.length; i++) {
if (objs[i] == null) {
out.writeInt(0);
} else {
out.writeInt(objs[i].id);
}
}
getReply(CMD_MARK_OBJECTS);
out.write(CMD_FREE_OBJECTS);
getReply(CMD_FREE_OBJECTS);
// Read in a new list of cache objects.
objects = new Hashtable();
while (readValue(in) != null) {
// Side effect: readValue() fills the objects cache as needed.
}
}
}
/* Turn on/off method call tracing. */
void trace(boolean traceOn) throws Exception {
synchronized (out) {
out.write(CMD_SYSTEM);
out.writeInt(SYS_TRACE_METHOD_CALLS);
out.writeInt(traceOn ? 1 : 0);
getReply(CMD_SYSTEM);
}
}
/* Turn on/off instruction tracing */
void itrace(boolean traceOn) throws Exception {
synchronized (out) {
out.write(CMD_SYSTEM);
out.writeInt(SYS_TRACE_INSTRUCTIONS);
out.writeInt(traceOn ? 1 : 0);
getReply(CMD_SYSTEM);
}
}
/* Report Agent's total memory usage. */
int totalMemory() throws Exception {
synchronized (out) {
out.write(CMD_SYSTEM);
out.writeInt(SYS_MEMORY_TOTAL);
getReply(CMD_SYSTEM);
return in.readInt();
}
}
/* Report Agent's free memory. */
int freeMemory() throws Exception {
synchronized (out) {
out.write(CMD_SYSTEM);
out.writeInt(SYS_MEMORY_FREE);
getReply(CMD_SYSTEM);
return in.readInt();
}
}
/* Run main program */
RemoteThreadGroup run(int argc, String argv[]) throws Exception {
synchronized (out) {
out.write(CMD_RUN);
out.write(argc);
for (int i = 0 ; i < argc ; i++) {
out.writeUTF(argv[i]);
}
getReply(CMD_RUN);
return (RemoteThreadGroup)readValue(in);
}
}
/* Get remote copies of all the fields of an Object. */
RemoteField[] getFields(int id) throws Exception {
synchronized (out) {
out.write(CMD_GET_FIELDS);
out.writeInt(id);
getReply(CMD_GET_FIELDS);
int n = in.readInt();
RemoteField list[] = new RemoteField[n];
for (int i = 0 ; i < n ; i++) {
int slot = in.readInt();
String name = in.readUTF();
String signature = in.readUTF();
short access = in.readShort();
RemoteClass clazz = (RemoteClass)readValue(in);
list[i] = new RemoteField(this, slot, name, signature,
access, clazz);
}
return list;
}
}
/* Get all the elements of an array. */
RemoteValue[] getElements(int id, int type,
int beginIndex, int endIndex) throws Exception
{
synchronized (out) {
out.write(CMD_GET_ELEMENTS);
out.writeInt(id);
out.writeInt(type);
out.writeInt(beginIndex);
out.writeInt(endIndex);
getReply(CMD_GET_ELEMENTS);
RemoteValue elements[] = new RemoteValue[in.readInt()];
for (int i = 0 ; i < elements.length ; i++) {
elements[i] = readValue(in);
}
return elements;
}
}
/* Get remote copies of all the methods of an Object. */
RemoteField[] getMethods(int id) throws Exception {
synchronized (out) {
out.write(CMD_GET_METHODS);
out.writeInt(id);
getReply(CMD_GET_METHODS);
int n = in.readInt();
message("getting (" + n + ") methods");
RemoteField list[] = new RemoteField[n];
for (int i = 0 ; i < n ; i++) {
int slot = in.readInt();
String name = in.readUTF();
String signature = in.readUTF();
short access = in.readShort();
RemoteClass clazz = (RemoteClass)readValue(in);
list[i] = new RemoteField(this, slot, name, signature,
access, null);
}
return list;
}
}
/* Get the type signature of a Class's field. */
int getSlotSignature(int id, int n)[] throws Exception {
synchronized (out) {
out.write(CMD_GET_SLOT_SIGNATURE);
out.writeInt(id);
out.writeInt(n);
getReply(CMD_GET_SLOT_SIGNATURE);
int sig[] = new int[in.readInt()];
for (int i = 0; i < sig.length; i++) {
sig[i] = in.readInt();
}
return sig;
}
}
/* Get the object in slot n of an Object. */
RemoteValue getSlotValue(int id, int slot) throws Exception {
synchronized (out) {
out.write(CMD_GET_SLOT_VALUE);
out.writeInt(id);
out.writeInt(slot);
getReply(CMD_GET_SLOT_VALUE);
RemoteValue rv = readValue(in);
if (rv != null && rv.isObject() && rv.getClass().getName().equals(
"java.lang.ArrayIndexOutOfBoundsException")) {
throw new
ArrayIndexOutOfBoundsException("invalid slot index "+slot);
}
return rv;
}
}
/* Get the object in slot n of a StackFrame. */
RemoteValue getStackValue(int threadId, int frame, int slot,
char type) throws Exception {
synchronized (out) {
out.write(CMD_GET_STACK_VALUE);
out.writeInt(threadId);
out.writeInt(frame);
out.writeInt(slot);
out.writeChar(type);
getReply(CMD_GET_STACK_VALUE);
return readValue(in);
}
}
/* Set slot n of an Object to an integer value. */
void setSlotValue(int id, int slot, int value) throws Exception {
synchronized (out) {
out.write(CMD_SET_SLOT_VALUE);
out.writeInt(id);
out.writeInt(slot);
out.writeInt(TC_INT);
out.writeInt(value);
getReply(CMD_SET_SLOT_VALUE);
}
}
/* Set slot n of an Object to a boolean value. */
void setSlotValue(int id, int slot, boolean value) throws Exception {
synchronized (out) {
out.write(CMD_SET_SLOT_VALUE);
out.writeInt(id);
out.writeInt(slot);
out.writeInt(TC_BOOLEAN);
out.writeBoolean(value);
getReply(CMD_SET_SLOT_VALUE);
}
}
/* Set slot n of an Object to a char value. */
void setSlotValue(int id, int slot, char value) throws Exception {
synchronized (out) {
out.write(CMD_SET_SLOT_VALUE);
out.writeInt(id);
out.writeInt(slot);
out.writeInt(TC_INT);
out.writeInt((int)value);
getReply(CMD_SET_SLOT_VALUE);
}
}
/* Set slot n of an Object to a long value. */
void setSlotValue(int id, int slot, long value) throws Exception {
synchronized (out) {
out.write(CMD_SET_SLOT_VALUE);
out.writeInt(id);
out.writeInt(slot);
out.writeInt(TC_LONG);
out.writeLong(value);
getReply(CMD_SET_SLOT_VALUE);
}
}
/* Set slot n of an Object to a float value. */
void setSlotValue(int id, int slot, float value) throws Exception {
synchronized (out) {
out.write(CMD_SET_SLOT_VALUE);
out.writeInt(id);
out.writeInt(slot);
out.writeInt(TC_DOUBLE);
out.writeDouble((double)value);
getReply(CMD_SET_SLOT_VALUE);
}
}
/* Set slot n of an Object to a double value. */
void setSlotValue(int id, int slot, double value) throws Exception {
synchronized (out) {
out.write(CMD_SET_SLOT_VALUE);
out.writeInt(id);
out.writeInt(slot);
out.writeInt(TC_DOUBLE);
out.writeDouble(value);
getReply(CMD_SET_SLOT_VALUE);
}
}
/* Set slot n of a stackframe to an integer value. */
void setStackValue(int threadId, int frame, int slot, int value) throws Exception {
synchronized (out) {
out.write(CMD_SET_STACK_VALUE);
out.writeInt(threadId);
out.writeInt(frame);
out.writeInt(slot);
out.writeInt(TC_INT);
out.writeInt(value);
getReply(CMD_SET_STACK_VALUE);
}
}
/* Set slot n of a stackframe to a boolean value. */
void setStackValue(int threadId, int frame, int slot, boolean value) throws Exception {
synchronized (out) {
out.write(CMD_SET_STACK_VALUE);
out.writeInt(threadId);
out.writeInt(frame);
out.writeInt(slot);
out.writeInt(TC_BOOLEAN);
out.writeBoolean(value);
getReply(CMD_SET_STACK_VALUE);
}
}
/* Set slot n of a stackframe to a char value. */
void setStackValue(int threadId, int frame, int slot, char value) throws Exception {
synchronized (out) {
out.write(CMD_SET_STACK_VALUE);
out.writeInt(threadId);
out.writeInt(frame);
out.writeInt(slot);
out.writeInt(TC_INT);
out.writeInt((int)value);
getReply(CMD_SET_STACK_VALUE);
}
}
/* Set slot n of a stackframe to a long value. */
void setStackValue(int threadId, int frame, int slot, long value) throws Exception {
synchronized (out) {
out.write(CMD_SET_STACK_VALUE);
out.writeInt(threadId);
out.writeInt(frame);
out.writeInt(slot);
out.writeInt(TC_LONG);
out.writeLong(value);
getReply(CMD_SET_STACK_VALUE);
}
}
/* Set slot n of a stackframe to a float value. */
void setStackValue(int threadId, int frame, int slot, float value) throws Exception {
synchronized (out) {
out.write(CMD_SET_STACK_VALUE);
out.writeInt(threadId);
out.writeInt(frame);
out.writeInt(slot);
out.writeInt(TC_DOUBLE);
out.writeDouble((double)value);
getReply(CMD_SET_STACK_VALUE);
}
}
/* Set slot n of a stackframe to a double value. */
void setStackValue(int threadId, int frame, int slot, double value) throws Exception {
synchronized (out) {
out.write(CMD_SET_STACK_VALUE);
out.writeInt(threadId);
out.writeInt(frame);
out.writeInt(slot);
out.writeInt(TC_DOUBLE);
out.writeDouble(value);
getReply(CMD_SET_STACK_VALUE);
}
}
/* Set a breakpoint at a specified source line number in a class. */
String setBreakpointLine(RemoteClass clazz, int lineno) throws Exception {
synchronized (out) {
out.write(CMD_SET_BRKPT_LINE);
out.writeInt(clazz.getId());
out.writeInt(lineno);
getReply(CMD_SET_BRKPT_LINE);
return in.readUTF();
}
}
/* Set a breakpoint at the first line of a specified class method. */
String setBreakpointMethod(RemoteClass clazz,
RemoteField method) throws Exception
{
synchronized (out) {
out.write(CMD_SET_BRKPT_METHOD);
out.writeInt(clazz.getId());
out.writeInt(method.slot);
getReply(CMD_SET_BRKPT_METHOD);
return in.readUTF();
}
}
/* Return a list of breakpoints that are currently set. */
String listBreakpoints()[] throws Exception {
synchronized (out) {
out.write(CMD_LIST_BREAKPOINTS);
getReply(CMD_LIST_BREAKPOINTS);
String list[] = new String[in.readInt()];
for (int i = 0; i < list.length; i++) {
list[i] = in.readUTF();
}
return list;
}
}
/* Clear a breakpoint at a specific address. */
String clearBreakpoint(RemoteClass clazz, int pc) throws Exception {
synchronized (out) {
message("clearing bkpt at " + clazz.getName() + ", pc " + pc);
out.write(CMD_CLEAR_BRKPT);
out.writeInt(clazz.getId());
out.writeInt(pc);
getReply(CMD_CLEAR_BRKPT);
return in.readUTF();
}
}
/* Clear a breakpoint at a specified line. */
String clearBreakpointLine(RemoteClass clazz, int lineno) throws Exception {
synchronized (out) {
message("clearing bkpt at " + clazz.getName() + ":" + lineno);
out.write(CMD_CLEAR_BRKPT_LINE);
out.writeInt(clazz.getId());
out.writeInt(lineno);
getReply(CMD_CLEAR_BRKPT_LINE);
return in.readUTF();
}
}
/* Clear a breakpoint at the start of a specified method. */
String clearBreakpointMethod(RemoteClass clazz,
RemoteField method) throws Exception
{
synchronized (out) {
message("clearing bkpt at " + clazz.getName() + ":" + method.getName());
out.write(CMD_CLEAR_BRKPT_METHOD);
out.writeInt(clazz.getId());
out.writeInt(method.slot);
getReply(CMD_CLEAR_BRKPT_METHOD);
return in.readUTF();
}
}
/* Add an exception class to be "caught", i.e. enter the debugger when
* thrown.
*/
void catchExceptionClass(RemoteClass c) throws Exception {
synchronized (out) {
out.write(CMD_CATCH_EXCEPTION_CLS);
out.writeInt(c.getId());
getReply(CMD_CATCH_EXCEPTION_CLS);
}
}
/* Don't enter the debugger when the specified exception class is
* thrown.
*/
void ignoreExceptionClass(RemoteClass c) throws Exception {
synchronized (out) {
out.write(CMD_IGNORE_EXCEPTION_CLS);
out.writeInt(c.getId());
getReply(CMD_IGNORE_EXCEPTION_CLS);
}
}
/* Return a list of the exceptions the debugger will stop on. */
String[] getExceptionCatchList() throws Exception {
synchronized (out) {
out.write(CMD_GET_CATCH_LIST);
getReply(CMD_GET_CATCH_LIST);
int n = in.readInt();
String list[] = new String[n];
for (int i = 0; i < n; i++) {
RemoteClass c = (RemoteClass)readValue(in);
list[i] = c.getName();
}
return list;
}
}
/* Get the source file path the Agent is currently using. */
String getSourcePath() throws Exception {
synchronized (out) {
out.write(CMD_GET_SOURCEPATH);
getReply(CMD_GET_SOURCEPATH);
return in.readUTF();
}
}
/* Set the Agent's source file path. */
void setSourcePath(String pathList) throws Exception {
synchronized (out) {
out.write(CMD_SET_SOURCEPATH);
out.writeUTF(pathList);
getReply(CMD_SET_SOURCEPATH);
}
}
/* Step through code an instruction or line. */
void stepThread(int id, boolean stepLine) throws Exception {
synchronized (out) {
out.write(CMD_STEP_THREAD);
out.writeInt(id);
out.writeBoolean(stepLine);
getReply(CMD_STEP_THREAD);
}
}
/* Step through code an instruction or line. */
void stepNextThread(int id) throws Exception {
synchronized (out) {
out.write(CMD_NEXT_STEP_THREAD);
out.writeInt(id);
getReply(CMD_NEXT_STEP_THREAD);
}
}
/* Set whether internal debugging messages are reported. */
private void setVerbose(boolean b) throws Exception {
synchronized (out) {
out.write(CMD_SET_VERBOSE);
out.writeBoolean(b);
getReply(CMD_SET_VERBOSE);
}
}
/* Error message */
void error(String msg) {
try {
client.printToConsole("[Internal debugger error: " + msg + "]\n");
} catch (Exception e) {
System.out.println("[Internal debugger error: " + msg + "]");
}
}
/* Agent debugging message (only printed in verbose mode) */
void message(String msg) {
if (verbose) {
try {
client.printToConsole("[debugger: " + msg + "]\n");
} catch (Exception e) {
System.out.println("[debugger: " + msg + "]");
}
}
}
}