You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by hi...@apache.org on 2010/08/17 20:26:40 UTC
svn commit: r986438 - in /harmony/enhanced/java/branches/java6: ./ classlib/
classlib/depends/libs/ drlvm/ jdktools/
jdktools/modules/jdktools/src/main/java/org/apache/harmony/tools/jdb/Main.java
Author: hindessm
Date: Tue Aug 17 18:26:40 2010
New Revision: 986438
URL: http://svn.apache.org/viewvc?rev=986438&view=rev
Log:
Merge change from /harmony/enhanced/java/trunk@986356:
r986356 | hindessm | 2010-08-17 16:23:51 +0100 (Tue, 17 Aug 2010) | 1 line
Applying patch from "[#HARMONY-6625] Final JDB code for GSoC 2010".
Modified:
harmony/enhanced/java/branches/java6/ (props changed)
harmony/enhanced/java/branches/java6/classlib/ (props changed)
harmony/enhanced/java/branches/java6/classlib/depends/libs/ (props changed)
harmony/enhanced/java/branches/java6/drlvm/ (props changed)
harmony/enhanced/java/branches/java6/jdktools/ (props changed)
harmony/enhanced/java/branches/java6/jdktools/modules/jdktools/src/main/java/org/apache/harmony/tools/jdb/Main.java
Propchange: harmony/enhanced/java/branches/java6/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Aug 17 18:26:40 2010
@@ -1,4 +1,4 @@
/harmony/enhanced/java/branches/mrh:935751-941490
-/harmony/enhanced/java/trunk:929253-979569,979593,979613,979615,979647,979659,979682,979897,980326,980632,981356,981763,981811,981820,982146,982148,982183,982250,982377,982498,982614,982650,982777,982887,983879,983902,984367,984577,984597-984598,984613,984682,984708,984731,984779,984784,984798,985098,985141,986136,986141,986147,986150,986205,986223-986224,986228,986248
+/harmony/enhanced/java/trunk:929253-979569,979593,979613,979615,979647,979659,979682,979897,980326,980632,981356,981763,981811,981820,982146,982148,982183,982250,982377,982498,982614,982650,982777,982887,983879,983902,984367,984577,984597-984598,984613,984682,984708,984731,984779,984784,984798,985098,985141,986136,986141,986147,986150,986205,986223-986224,986228,986248,986356
/harmony/enhanced/trunk:476395-929252
/incubator/harmony/enhanced/trunk:292550-476394
Propchange: harmony/enhanced/java/branches/java6/classlib/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Aug 17 18:26:40 2010
@@ -1,7 +1,7 @@
/harmony/enhanced/classlib/trunk:713674-735919,765923-926091,926318-926838
/harmony/enhanced/classlib/trunk/working_classlib:884014-884286
/harmony/enhanced/java/branches/mrh/classlib:935751-941490
-/harmony/enhanced/java/trunk/classlib:929253-979569,979593,979613,979615,979647,979659,979682,979897,980326,980632,981356,981763,981811,981820,982146,982148,982183,982250,982377,982498,982614,982650,982777,982887,983879,983902,984367,984577,984597-984598,984613,984682,984708,984731,984779,984784,984798,985098,985141,986136,986141,986147,986150,986205,986223-986224,986228,986248
+/harmony/enhanced/java/trunk/classlib:929253-979569,979593,979613,979615,979647,979659,979682,979897,980326,980632,981356,981763,981811,981820,982146,982148,982183,982250,982377,982498,982614,982650,982777,982887,983879,983902,984367,984577,984597-984598,984613,984682,984708,984731,984779,984784,984798,985098,985141,986136,986141,986147,986150,986205,986223-986224,986228,986248,986356
/harmony/enhanced/trunk/classlib:476395-929252
/harmony/enhanced/trunk/working_classlib:476396-920147
/incubator/harmony/enhanced/trunk/classlib:292550-476394
Propchange: harmony/enhanced/java/branches/java6/classlib/depends/libs/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Aug 17 18:26:40 2010
@@ -1,4 +1,4 @@
/harmony/enhanced/classlib/trunk/depends/libs:544451-926091
-/harmony/enhanced/java/trunk/classlib/depends/libs:929253-979569,979593,979613,979615,979647,979659,979682,979897,980326,980632,981356,981763,981811,981820,982146,982148,982183,982250,982377,982498,982614,982650,982777,982887,983879,983902,984367,984577,984597-984598,984613,984682,984708,984731,984779,984784,984798,985098,985141,986136,986141,986147,986150,986205,986223-986224,986228,986248
+/harmony/enhanced/java/trunk/classlib/depends/libs:929253-979569,979593,979613,979615,979647,979659,979682,979897,980326,980632,981356,981763,981811,981820,982146,982148,982183,982250,982377,982498,982614,982650,982777,982887,983879,983902,984367,984577,984597-984598,984613,984682,984708,984731,984779,984784,984798,985098,985141,986136,986141,986147,986150,986205,986223-986224,986228,986248,986356
/harmony/enhanced/trunk/classlib/depends/libs:476395-929252
/incubator/harmony/enhanced/trunk/classlib/depends/libs:292550-476394
Propchange: harmony/enhanced/java/branches/java6/drlvm/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Aug 17 18:26:40 2010
@@ -1,5 +1,5 @@
/harmony/enhanced/java/branches/mrh/drlvm:935751-941490
-/harmony/enhanced/java/trunk/drlvm:929253-979569,979593,979613,979615,979647,979659,979682,979897,980326,980632,981356,981763,981811,981820,982146,982148,982183,982250,982377,982498,982614,982650,982777,982887,983879,983902,984367,984577,984597-984598,984613,984682,984708,984731,984779,984784,984798,985098,985141,986136,986141,986147,986150,986205,986223-986224,986228,986248
+/harmony/enhanced/java/trunk/drlvm:929253-979569,979593,979613,979615,979647,979659,979682,979897,980326,980632,981356,981763,981811,981820,982146,982148,982183,982250,982377,982498,982614,982650,982777,982887,983879,983902,984367,984577,984597-984598,984613,984682,984708,984731,984779,984784,984798,985098,985141,986136,986141,986147,986150,986205,986223-986224,986228,986248,986356
/harmony/enhanced/trunk/drlvm:476395-929252
/harmony/enhanced/trunk/working_vm:476396-920147
/incubator/harmony/enhanced/trunk/drlvm:292550-476394
Propchange: harmony/enhanced/java/branches/java6/jdktools/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Aug 17 18:26:40 2010
@@ -1,4 +1,4 @@
-/harmony/enhanced/java/trunk/jdktools:929253-979569,979593,979613,979615,979647,979659,979682,979897,980326,980632,981356,981763,981811,981820,982146,982148,982183,982250,982377,982498,982614,982650,982777,982887,983879,983902,984367,984577,984597-984598,984613,984682,984708,984731,984779,984784,984798,985098,985141,986136,986141,986147,986150,986205,986223-986224,986228,986248
+/harmony/enhanced/java/trunk/jdktools:929253-979569,979593,979613,979615,979647,979659,979682,979897,980326,980632,981356,981763,981811,981820,982146,982148,982183,982250,982377,982498,982614,982650,982777,982887,983879,983902,984367,984577,984597-984598,984613,984682,984708,984731,984779,984784,984798,985098,985141,986136,986141,986147,986150,986205,986223-986224,986228,986248,986356
/harmony/enhanced/jdktools/trunk:630107-925933
/harmony/enhanced/trunk/jdktools:476395-929252
/harmony/enhanced/trunk/working_jdktools:476396-920147
Modified: harmony/enhanced/java/branches/java6/jdktools/modules/jdktools/src/main/java/org/apache/harmony/tools/jdb/Main.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/java/branches/java6/jdktools/modules/jdktools/src/main/java/org/apache/harmony/tools/jdb/Main.java?rev=986438&r1=986437&r2=986438&view=diff
==============================================================================
--- harmony/enhanced/java/branches/java6/jdktools/modules/jdktools/src/main/java/org/apache/harmony/tools/jdb/Main.java (original)
+++ harmony/enhanced/java/branches/java6/jdktools/modules/jdktools/src/main/java/org/apache/harmony/tools/jdb/Main.java Tue Aug 17 18:26:40 2010
@@ -17,7 +17,6 @@
package org.apache.harmony.tools.jdb;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -30,38 +29,45 @@ import org.eclipse.jdi.Bootstrap;
import org.eclipse.jdi.internal.VirtualMachineManagerImpl;
import org.eclipse.jdi.internal.connect.SocketAttachingConnectorImpl;
-import com.sun.jdi.LocalVariable;
import com.sun.jdi.Location;
+import com.sun.jdi.Method;
import com.sun.jdi.ReferenceType;
-import com.sun.jdi.StackFrame;
-import com.sun.jdi.StringReference;
import com.sun.jdi.ThreadReference;
-import com.sun.jdi.Value;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.VirtualMachineManager;
import com.sun.jdi.connect.Connector;
-import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import com.sun.jdi.event.BreakpointEvent;
import com.sun.jdi.event.ClassPrepareEvent;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.EventIterator;
import com.sun.jdi.event.EventQueue;
import com.sun.jdi.event.EventSet;
-import com.sun.jdi.event.ExceptionEvent;
-import com.sun.jdi.event.LocatableEvent;
+import com.sun.jdi.event.MethodExitEvent;
+import com.sun.jdi.event.StepEvent;
+import com.sun.jdi.event.ThreadStartEvent;
import com.sun.jdi.event.VMDisconnectEvent;
import com.sun.jdi.event.VMStartEvent;
import com.sun.jdi.request.BreakpointRequest;
import com.sun.jdi.request.ClassPrepareRequest;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.EventRequestManager;
-import com.sun.jdi.request.ExceptionRequest;
+import com.sun.jdi.request.MethodExitRequest;
+import com.sun.jdi.request.StepRequest;
+import com.sun.jdi.request.ThreadStartRequest;
+/**
+ * The java implementation of Harmony JDB command line tool.
+ */
public class Main {
+ /**
+ * The JDB command enumeration.
+ */
static enum Command {
+ // complete
CONNECTORS("connectors", "connectors", "") {
+ @Override
@SuppressWarnings("unchecked")
final String run(String[] args) {
List<Connector> connectors =
@@ -103,159 +109,318 @@ public class Main {
}
},
+ // seems complete
RUN("run", "run [class [args]]", "") {
+ @Override
final String run(String[] args) {
if (jdb.status == Status.CONNECTED) {
- jdb.targetVM.resume();
+ jdb.debuggee.resume();
+ jdb.status = Status.STARTED;
}
- return "";
+ return EMPTY_MSG;
}
},
THREADS("threads", "threads [threadgroup]", "") {
+ @Override
final String run(String[] args) {
- StringBuilder sb = new StringBuilder("** command list **\n");
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "threads");
+ }
+ StringBuilder sb = new StringBuilder("** thread list **\n");
+ // TODO print the thread list
return sb.toString();
}
},
THREAD("thread", "thread <thread id>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "thread");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
SUSPEND("suspend", "suspend [thread id(s)]", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "suspend");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
RESUME("resume", "resume [thread id(s)]", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "resume");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
WHERE("where", "where [<thread id> | all]", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "where");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
WHEREI("wherei", "wherei [<thread id> | all]", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "wherei");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
UP("up", "up [n frames]", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "up");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
DOWN("down", "down [n frames]", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "down");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
KILL("kill", "kill <thread id> <expr>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "kill");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
INTERRUPT("interrupt", "interrupt <thread id>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "interrupt");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
PRINT("print", "print <expr>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "print");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
DUMP("dump", "dump <expr>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "dump");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
EVAL("eval", "eval <expr>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "eval");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
SET("set", "set <lvalue> = <expr>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "set");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
LOCALS("locals", "locals", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "locals");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
CLASSES("classes", "classes", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "classes");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
CLASS("class", "class <class id>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "class");
+ }
+ return EMPTY_MSG;
}
},
METHODS("methods", "methods <class id>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "methods");
+ }
+ return EMPTY_MSG;
}
},
FIELDS("fields", "fields <class id>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "fields");
+ }
+ return EMPTY_MSG;
}
},
THREADGROUPS("threadgroups", "threadgroups", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "threadgroups");
+ }
+ return EMPTY_MSG;
}
},
THREADGROUP("threadgroup", "threadgroup <name>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "threadgroup");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
- STOP_IN("stop", "stop in <class id>.<method>[(argument_type,...)]", "") {
+ // TODO complete, not working well though
+ STOP_IN("stop", "stop in <class id>.<method>[(argument_type,...)]",
+ "") {
+ @Override
final boolean match(String[] args) {
return super.match(args) && args[1].equals("in");
}
+ @Override
+ @SuppressWarnings("unchecked")
final String run(String[] args) {
- return "";
+ String[] params;
+ try {
+ params = parseClassMethod(args[2]);
+ } catch (Exception e) {
+ return usage;
+ }
+ List<ReferenceType> classes =
+ jdb.debuggee.classesByName(params[0]);
+ // class not loaded yet
+ if (classes.isEmpty()) {
+ if (!jdb.deferringMethodBreakpoint.containsKey(params[0])) {
+ jdb.deferringMethodBreakpoint.put(
+ params[0], new ArrayList<String>());
+ }
+ // method string: "method|argument_type,..."
+ jdb.deferringMethodBreakpoint.get(
+ params[0]).add(params[1] + "|" + params[2]);
+ return String.format(
+ "Deferring breakpoint %s\n" +
+ "it will be set after the class is loaded.",
+ args[2]);
+ } else {
+ // Generate the target argument type string list
+ String[] argTypeNames = params[2].split(",");
+ // Get all methods of the class
+ ReferenceType clazz = classes.get(0);
+ List<Method> methodList = clazz.methodsByName(params[1]);
+ Method matchedMethod = null;
+ /*
+ * As the jdb command argument doesn't supply the result
+ * value type, it's impossible to generate a jni signature
+ * for the specified method. I just have to search...
+ */
+ for (Method m : methodList) {
+ List<String> types = m.argumentTypeNames();
+ if (types.size() != argTypeNames.length) {
+ continue;
+ } else {
+ boolean matched = true;
+ for (int i = 0; i < argTypeNames.length; i++) {
+ if (!types.get(i).equals(argTypeNames[i])) {
+ matched = false;
+ break;
+ }
+ }
+ if (matched) {
+ matchedMethod = m;
+ break;
+ }
+ }
+ }
+ if (null != matchedMethod) {
+ Location loc = matchedMethod.location();
+ if (null != loc) {
+ BreakpointRequest breakpointRequest =
+ jdb.eventRequestManager.
+ createBreakpointRequest(loc);
+ breakpointRequest.setSuspendPolicy(
+ EventRequest.SUSPEND_ALL);
+ breakpointRequest.enable();
+ jdb.breakpointRegisterMap.put(
+ loc.toString(), breakpointRequest);
+ return String.format("Breakpoint set: " + loc);
+ }
+ }
+ }
+ return EMPTY_MSG;
}
},
+ // TODO complete, working well, need more check
STOP_AT("stop", "stop at <class id>:<line>", "") {
+ @Override
final boolean match(String[] args) {
return super.match(args) && args[1].equals("at");
}
+ @Override
+ @SuppressWarnings("unchecked")
final String run(String[] args) throws Exception {
String[] params = args[2].split(":");
List<ReferenceType> classes =
- jdb.targetVM.classesByName(params[0]);
+ jdb.debuggee.classesByName(params[0]);
if (classes.isEmpty()) {
if (!jdb.deferringLineBreakpoint.containsKey(params[0])) {
jdb.deferringLineBreakpoint.put(
@@ -270,68 +435,209 @@ public class Main {
} else {
List<Location> locations = classes.get(0).
locationsOfLine(Integer.parseInt(params[1]));
- if (locations.isEmpty()) {
- Location location = locations.get(0);
- BreakpointRequest breakpointRequest = jdb.eventRequestManager
- .createBreakpointRequest(location);
- breakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
+ if (!locations.isEmpty()) {
+ Location loc = locations.get(0);
+ BreakpointRequest breakpointRequest =
+ jdb.eventRequestManager.
+ createBreakpointRequest(loc);
+ breakpointRequest.setSuspendPolicy(
+ EventRequest.SUSPEND_ALL);
breakpointRequest.enable();
- return String.format("Breakpoint set: " + location);
+ jdb.breakpointRegisterMap.put(
+ loc.toString(), breakpointRequest);
+ return String.format("Breakpoint set: " + loc);
} else {
- return "";
+ return EMPTY_MSG;
}
}
}
},
+ // TODO complete, not working well though
CLEAR_METHOD("clear", "clear <class id>.<method>[(argument_type,...)]", "") {
final boolean match(String[] args) {
- return false;
+ return args.length >= 2
+ && args[0].equals(prefix)
+ && args[1].indexOf(':') == -1
+ && args[1].indexOf('.') != -1;
}
+ @SuppressWarnings("unchecked")
final String run(String[] args) {
- return "";
+ String[] params;
+ boolean isFound = false;
+ try {
+ params = parseClassMethod(args[1]);
+ } catch (Exception e) {
+ return usage;
+ }
+ String methodStr = params[1] + "|" + params[2];
+ List<String> methodStrList =
+ jdb.deferringMethodBreakpoint.get(params[0]);
+ for (String str : methodStrList) {
+ if (str.equals(methodStr)) {
+ methodStrList.remove(str);
+ isFound = true;
+ break;
+ }
+ }
+ if (!isFound) {
+ List<ReferenceType> classes =
+ jdb.debuggee.classesByName(params[0]);
+ if (!classes.isEmpty()) {
+ // Generate the target argument type string list
+ String[] argTypeNames = params[2].split(",");
+ // Get all methods of the class
+ ReferenceType clazz = classes.get(0);
+ List<Method> methodList = clazz.methodsByName(params[1]);
+ Method matchedMethod = null;
+ /*
+ * As the jdb command argument doesn't supply the result
+ * value type, it's impossible to generate a jni signature
+ * for the specified method. I just have to search...
+ */
+ for (Method m : methodList) {
+ List<String> types = m.argumentTypeNames();
+ if (types.size() != argTypeNames.length) {
+ continue;
+ } else {
+ boolean matched = true;
+ for (int i = 0; i < argTypeNames.length; i++) {
+ if (!types.get(i).equals(argTypeNames[i])) {
+ matched = false;
+ break;
+ }
+ }
+ if (matched) {
+ matchedMethod = m;
+ break;
+ }
+ }
+ }
+ if (null != matchedMethod) {
+ Location loc = matchedMethod.location();
+ if (null != loc) {
+ String key = loc.toString();
+ jdb.breakpointRegisterMap.get(key).disable();
+ jdb.breakpointRegisterMap.remove(key);
+ isFound = true;
+ }
+ }
+ }
+ }
+ if (isFound) {
+ return String.format("Breakpoint cleared: " + args[1]);
+ } else {
+ return String.format(
+ "Not found: breakpoint %s", args[1]);
+ }
}
},
+ // TODO complete, not working well though
CLEAR_LINE("clear", "clear <class id>:<line>", "") {
final boolean match(String[] args) {
- return false;
+ return args.length >= 2
+ && args[0].equals(prefix)
+ && args[1].indexOf(':') != -1;
}
- final String run(String[] args) {
- return "";
+ @SuppressWarnings("unchecked")
+ final String run(String[] args) throws Exception {
+ String[] params = args[1].split(":");
+ int line = Integer.parseInt(params[1]);
+ boolean isFound = false;
+ List<Integer> lineList =
+ jdb.deferringLineBreakpoint.get(params[0]);
+ for (Integer i : lineList) {
+ if (i.intValue() == line) {
+ lineList.remove(i);
+ isFound = true;
+ break;
+ }
+ }
+ if (!isFound) {
+ List<ReferenceType> classes =
+ jdb.debuggee.classesByName(params[0]);
+ if (!classes.isEmpty()) {
+ List<Location> locations = classes.get(0).
+ locationsOfLine(line);
+ if (!locations.isEmpty()) {
+ Location loc = locations.get(0);
+ String key = loc.toString();
+ jdb.breakpointRegisterMap.get(key).disable();
+ jdb.breakpointRegisterMap.remove(key);
+ isFound = true;
+ }
+ }
+ }
+ if (isFound) {
+ return String.format("Breakpoint cleared: " + args[1]);
+ } else {
+ return String.format(
+ "Not found: breakpoint %s", args[1]);
+ }
}
},
CLEAR("clear", "clear", "") {
final boolean match(String[] args) {
- return false;
+ return args.length == 1 && args[0].equals(prefix);
}
+ @SuppressWarnings("unchecked")
final String run(String[] args) {
- return "";
+ /*
+ * TODO have not include deferred breakpoints yet
+ */
+ List<BreakpointRequest> list =
+ jdb.eventRequestManager.breakpointRequests();
+ if (list.size() == 0) {
+ return "No breakpoints set.";
+ } else {
+ StringBuilder sb = new StringBuilder();
+ for (BreakpointRequest request : list) {
+ sb.append(request.location() + "\n");
+ }
+ return sb.toString();
+ }
}
},
CATCH("catch", "catch [uncaught|caught|all]", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "catch");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
IGNORE("ignore", "ignore [uncaught|caught|all]", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "ignore");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
WATCH("watch", "watch [access|all] <class id>.<field name>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "watch");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
UNWATCH("unwatch", "unwatch [access|all] <class id>.<field name>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "unwatch");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
@@ -345,7 +651,11 @@ public class Main {
}
}
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "trace");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
@@ -354,16 +664,25 @@ public class Main {
return false;
}
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "trace");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
UNTRACE("untrace", "untrace [methods]", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "untrace");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
+ // TODO complete, not working well though
STEP("step", "step", "") {
final boolean match(String[] args) {
if (args[0].equals(prefix) &&
@@ -374,10 +693,20 @@ public class Main {
}
}
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "step");
+ }
+ StepRequest request =
+ jdb.eventRequestManager.createStepRequest(jdb.thread,
+ StepRequest.STEP_LINE,
+ StepRequest.STEP_INTO);
+ request.addCountFilter(1);// next step only
+ request.enable();
+ return "Step one line.";
}
},
+ // TODO complete, not working well though
STEP_UP("step", "step up", "") {
final boolean match(String[] args) {
if (args[0].equals(prefix) &&
@@ -388,28 +717,67 @@ public class Main {
}
}
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "step up");
+ }
+ MethodExitRequest request =
+ jdb.eventRequestManager.createMethodExitRequest();
+ request.addThreadFilter(jdb.thread);
+ request.addCountFilter(1);
+ request.enable();
+ return "Step up to the caller.";
}
},
+ // TODO complete, not working well though
STEPI("stepi", "stepi", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "stepi");
+ }
+ StepRequest request =
+ jdb.eventRequestManager.createStepRequest(jdb.thread,
+ StepRequest.STEP_MIN,
+ StepRequest.STEP_INTO);
+ request.addCountFilter(1);// next step only
+ request.enable();
+ return "Step one instruction.";
}
},
+ // TODO complete, not working well though
NEXT("next", "next", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "next");
+ }
+ StepRequest request =
+ jdb.eventRequestManager.createStepRequest(jdb.thread,
+ StepRequest.STEP_LINE,
+ StepRequest.STEP_OVER);
+ request.addCountFilter(1);// next step only
+ request.enable();
+ return "Step one line (over calls)";
}
},
+ // TODO, complete, working well, need more check
CONT("cont", "cont", "") {
+ final String run(String[] args) {
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "cont");
+ }
+ return EMPTY_MSG;
+ }
},
LIST("list", "list [line number|method]", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "list");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
@@ -422,99 +790,145 @@ public class Main {
}
}
final String run(String[] args) {
- return "";
+ // TODO command logic
+ return EMPTY_MSG;
}
},
EXCLUDE("exclude", "exclude [<class pattern>, ... | \"none\"]", "") {
final String run(String[] args) {
- return "";
+ // TODO command logic
+ return EMPTY_MSG;
}
},
CLASSPATH("classpath", "classpath", "") {
final String run(String[] args) {
- return "";
+ // TODO command logic
+ return EMPTY_MSG;
}
},
- MONITOR_CMD("monitoer", "monitor <command>", "") {
+ MONITOR_CMD("monitor", "monitor <command>", "") {
final boolean match(String[] args) {
return false;
}
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "monitor");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
- MONITOR("monitoer", "monitor", "") {
+ MONITOR("monitor", "monitor", "") {
final boolean match(String[] args) {
return false;
}
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "monitor");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
UNMONITOR("unmonitor", "unmonitor <monitor#>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "unmonitor");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
READ("read", "read <filename>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "read");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
LOCK("lock", "lock <expr>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "lock");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
THREADLOCKS("threadlocks", "threadlocks [thread id]", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "threadlocks");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
POP("pop", "pop", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "pop");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
REENTER("reenter", "reenter", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "reenter");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
REDEFINE("redefine", "redefine <class id> <class file name>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "redefine");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
DISABLEGC("disablegc", "disablegc <expr>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "disablegc");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
ENABLEGC("enablegc", "enablegc <expr>", "") {
final String run(String[] args) {
- return "";
+ if (jdb.status != Status.STARTED) {
+ return String.format(NOT_VALID_UNTIL_STARTED, "enablegc");
+ }
+ // TODO command logic
+ return EMPTY_MSG;
}
},
REPEAT("!!", "!!", "") {
- Command lastCmd = null;
- String[] lastArgs = null;
final String run(String[] args) {
- return "";
+ // TODO command logic
+ return EMPTY_MSG;
}
},
@@ -528,13 +942,14 @@ public class Main {
}
final String run(String[] args) {
StringBuilder sb = new StringBuilder("** command list **\n");
+ // TODO build the info string
return sb.toString();
}
},
VERSION("version", "version", "") {
final String run(String[] args) {
- return "";
+ return VERSION_STR;
}
},
@@ -546,20 +961,28 @@ public class Main {
return false;
}
}
+ final String run(String[] args) {
+ return EMPTY_MSG;
+ }
},
+ // Returned by the search method when no real command is matched
NONCMD("", "" ,"") {
final String run(String[] args) {
return String.format("Unsupported command: '%s'.", args[0]);
}
};
+ // Expected command prefix
final String usage;
+ // Command format and options
final String comment;
+ // Help information of the command
final String prefix;
+ // Iterate the command list and match the args against them
static final Command search(final String[] args) {
for (Command cmd : Command.values()) {
if (cmd != NONCMD && cmd.match(args)) {
@@ -569,12 +992,48 @@ public class Main {
return NONCMD;
}
+ // parse the "<class id>.<method>[(argument_type,...)]" string
+ static final String[] parseClassMethod(String str) {
+ String[] params = new String[3];
+ int argumentStart = str.indexOf('(');
+ if (argumentStart == -1) {
+ // class id
+ params[0] = str.substring(
+ 0, str.lastIndexOf('.'));
+ // method name
+ params[1] = str.substring(
+ str.lastIndexOf('.') + 1);
+ // empty argument type list
+ params[2] = "";
+ } else {
+ String classMethod = str.substring(argumentStart);
+ // class id
+ params[0] = classMethod.substring(
+ 0, classMethod.lastIndexOf('.'));
+ // method name
+ params[1] = classMethod.substring(
+ classMethod.lastIndexOf('.') + 1);
+ // argument type list
+ params[2] = str.substring(
+ argumentStart + 1, str.length() - 1);
+ }
+ return params;
+ }
+
+ /*
+ * Generally, a command matching only needs to compare its prefix,
+ * override it in enum instance if necessary.
+ */
boolean match(String[] args) {
return args[0].equals(prefix);
}
+ /*
+ * The default command running output is do nothing and return an empty
+ * string, override it in enum instance if necessary.
+ */
String run(String[] args) throws Exception {
- return "";
+ return EMPTY_MSG;
}
Command(String prefix, String usage, String comment) {
@@ -585,19 +1044,42 @@ public class Main {
}
+ // TODO not decided how many statuses needed yet
static enum Status {
- UNDEFINED, NO_VM_CONNECTED, CONNECTED
+ UNDEFINED, NO_VM_CONNECTED, CONNECTED, STARTED
}
+ // The default prompt
private static final String PROMPT = "> ";
- private static Main jdb = new Main();
+ /*
+ * The empty message indicates there's no information coming out with
+ * the command result
+ */
+ private static final String EMPTY_MSG = "";
+
+ // The jdb version information
+ private static final String VERSION_STR =
+ "This is jdb version 1.6 <Apache Harmony 6>";
+
+ /*
+ * The string indicates that a command is not valid until the VM is started
+ * with the 'run' command.
+ */
+ private static final String NOT_VALID_UNTIL_STARTED =
+ "Command '%s' is not valid until " +
+ "the VM is started with the 'run' command";
+
+ // The singleton instance of jdb
+ private static final Main jdb = new Main();
private boolean isExit = false;
+ // The debuggee status
private Status status = Status.UNDEFINED;
- private VirtualMachineManager virturalMachineManager = Bootstrap.virtualMachineManager();
+ private VirtualMachineManager virturalMachineManager =
+ Bootstrap.virtualMachineManager();
private EventRequestManager eventRequestManager = null;
@@ -605,11 +1087,13 @@ public class Main {
private EventSet eventSet = null;
- private VirtualMachine targetVM = null;
+ private VirtualMachine debuggee = null;
- private Process VMProcess = null;
+ //private Process VMProcess = null;
+ // Current thread
+ private ThreadReference thread = null;
- private String mainClass = null;
+ //private String mainClass = null;
private HashMap<String, List<Integer>> deferringLineBreakpoint =
new HashMap<String, List<Integer>>();
@@ -617,6 +1101,16 @@ public class Main {
private HashMap<String, List<String>> deferringMethodBreakpoint =
new HashMap<String, List<String>>();
+ /*
+ * A map that stores references to all breakpoints(not include the deferred
+ * ones). The key of the map is a string indicate the location of the
+ * breakpoint. The map is used by those commands that will clear some
+ * breakpoint in certain location.
+ */
+ private HashMap<String, BreakpointRequest> breakpointRegisterMap =
+ new HashMap<String, BreakpointRequest>();
+
+ // TODO currentPrompt is prompt that indicate current context(fixed for now)
private String currentPrompt = PROMPT;
private Main() {}
@@ -626,36 +1120,50 @@ public class Main {
* and corresponding parameter, then launch jdb and get ready to process
* commands.
*/
+ @SuppressWarnings("unchecked")
private void init(String[] args) throws Exception {
+ /*
+ * TODO As currently jdb just supports "jdb -attach [port]" command,
+ * more work to do to parse the jdb launching command option
+ */
if (args.length >= 2 && args[0].equals("-attach")) {
- SocketAttachingConnectorImpl sac = new SocketAttachingConnectorImpl(
- (VirtualMachineManagerImpl) Bootstrap.virtualMachineManager());
-
+ SocketAttachingConnectorImpl sac =
+ new SocketAttachingConnectorImpl(
+ (VirtualMachineManagerImpl) Bootstrap.
+ virtualMachineManager());
Map argMap = sac.defaultArguments();
Connector.Argument value;
value = (Connector.Argument) argMap.get("hostname");
value.setValue("localhost");
value = (Connector.Argument) argMap.get("port");
value.setValue(args[1]);
- targetVM = sac.attach(argMap);
- VMProcess = targetVM.process();
+ debuggee = sac.attach(argMap);
+ //VMProcess = debuggee.process();
} else {
System.out.println("Wrong command option. " +
"The jdb currently only support jdb -attach [port].");
System.exit(0);
}
- eventRequestManager = targetVM.eventRequestManager();
+ eventRequestManager = debuggee.eventRequestManager();
+ // Enable class prepare request for all classes
ClassPrepareRequest classPrepareRequest
= eventRequestManager.createClassPrepareRequest();
classPrepareRequest.addClassFilter("*");
classPrepareRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
classPrepareRequest.enable();
+
+ // Enable thread start request for all threads
+ ThreadStartRequest threadStartRequest
+ = eventRequestManager.createThreadStartRequest();
+ threadStartRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
+ threadStartRequest.enable();
}
+ // Start the loop
private void start() throws Exception {
- eventQueue = targetVM.eventQueue();
+ eventQueue = debuggee.eventQueue();
while (true) {
if (isExit == true) {
break;
@@ -672,51 +1180,137 @@ public class Main {
}
}
+ @SuppressWarnings("unchecked")
private void execute(Event event) throws Exception {
+ /*
+ * The variable indicates whether go to command looping after handling
+ * the current event
+ */
boolean keepRunning = true;
if (event instanceof VMStartEvent) {
- //eventRequestManager = targetVM.eventRequestManager();
- //ExceptionRequest excReq =
- //eventRequestManager.createExceptionRequest(null, false, true);
- //excReq.setSuspendPolicy(EventRequest.SUSPEND_ALL);
- //excReq.enable();
- //System.out.println("Set uncaught java.lang.Throwable");
- //System.out.println("Set deferred uncaught java.lang.Throwable");
status = Status.CONNECTED;
System.out.println("Initializing jdb ...");
System.out.println(
"VM Started: No frames on the current call stack");
- //currentPrompt = ((VMStartEvent)event).thread().name();
+ // stop after the vm starts
keepRunning = false;
}
+ if (event instanceof ThreadStartEvent) {
+ thread = ((ThreadStartEvent) event).thread();
+ }
+ if (event instanceof MethodExitEvent) {
+ // run command step up -> stop
+ keepRunning = false;
+ }
+ if (event instanceof StepEvent) {
+ // run commands step, stepi, or next -> stop
+ keepRunning = false;
+ }
+ /*
+ * after a class is loaded, check whether there are deferred
+ * breakpoints(both line and method) related to the class; if yes,
+ * set these breakpoints. The jdb won't stop running.
+ */
if (event instanceof ClassPrepareEvent) {
- String className = ((ClassPrepareEvent) event).referenceType().name();
+ // get the class name
+ String className = ((ClassPrepareEvent)
+ event).referenceType().name();
+ // set the possible deferred line breakpoints
List<Integer> lineList = deferringLineBreakpoint.get(className);
if (lineList != null) {
- ReferenceType classType = ((ClassPrepareEvent) event).referenceType();
+ ReferenceType classType = ((ClassPrepareEvent)
+ event).referenceType();
for (Integer line : lineList) {
List<Location> locations = classType.locationsOfLine(line);
if (!locations.isEmpty()) {
- Location location = locations.get(0);
- BreakpointRequest breakpointRequest = jdb.eventRequestManager
- .createBreakpointRequest(location);
- breakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
+ Location loc = locations.get(0);
+ BreakpointRequest breakpointRequest =
+ jdb.eventRequestManager.
+ createBreakpointRequest(loc);
+ breakpointRequest.setSuspendPolicy(
+ EventRequest.SUSPEND_ALL);
breakpointRequest.enable();
- System.out.println(String.format("Breakpoint set: " + location));
+ jdb.breakpointRegisterMap.put(
+ loc.toString(), breakpointRequest);
+ System.out.println(
+ String.format("Breakpoint set: " + loc));
+ }
+ }
+ }
+ // set the possible deferred method breakpoints
+ List<String> methodStrList = deferringMethodBreakpoint.get(className);
+ if (methodStrList != null) {
+ ReferenceType classType = ((ClassPrepareEvent)
+ event).referenceType();
+ for (String methodStr : methodStrList) {
+ String[] params = methodStr.split("|");
+ // Generate the target argument type string list
+ String[] argTypeNames;
+ if (params.length > 1) {
+ argTypeNames = params[1].split(",");
+ } else {
+ argTypeNames = new String[0];
+ }
+ // Get all methods of the class
+ List<Method> methodList = classType.methodsByName(params[0]);
+ Method matchedMethod = null;
+ /*
+ * As the jdb command argument doesn't supply the result
+ * value type, it's impossible to generate a jni signature
+ * for the specified method. I just have to search...
+ */
+ for (Method m : methodList) {
+ List<String> types = m.argumentTypeNames();
+ if (types.size() != argTypeNames.length) {
+ continue;
+ } else {
+ boolean matched = true;
+ for (int i = 0; i < argTypeNames.length; i++) {
+ if (!types.get(i).equals(argTypeNames[i])) {
+ matched = false;
+ break;
+ }
+ }
+ if (matched) {
+ matchedMethod = m;
+ break;
+ }
+ }
+ }
+ if (null != matchedMethod) {
+ Location loc = matchedMethod.location();
+ if (null != loc) {
+ BreakpointRequest breakpointRequest =
+ jdb.eventRequestManager.
+ createBreakpointRequest(loc);
+ breakpointRequest.setSuspendPolicy(
+ EventRequest.SUSPEND_ALL);
+ breakpointRequest.enable();
+ jdb.breakpointRegisterMap.put(
+ loc.toString(), breakpointRequest);
+ System.out.println(
+ String.format("Breakpoint set: " + loc));
+ }
}
}
}
}
if (event instanceof BreakpointEvent) {
+ // reach breakpoint and stop
System.out.println("Reach breakpoint at " +
((BreakpointEvent) event).location());
keepRunning = false;
}
if (event instanceof VMDisconnectEvent) {
+ // The jdb will end when disconnected from target vm
System.out.println("Application ends.");
isExit = true;
}
+ /*
+ * If the event requires the jdb to stop running, the jdb turn to the user
+ * interaction mode before resuming.
+ */
if (!keepRunning) {
Scanner cmdScanner = new Scanner(System.in);
while (true) {
@@ -729,16 +1323,18 @@ public class Main {
isExit = true;
break;
}
- if (cmd == Command.CONT) {
- break;
- }
String result = cmd.run(args);
- if (cmd == Command.RUN) {
- break;
- }
- if (!result.equals("")) {
+ if (!result.equals(EMPTY_MSG)) {
System.out.println(result);
}
+ // If the command is one of those execution control
+ if (cmd == Command.STEP
+ || cmd == Command.STEP_UP
+ || cmd == Command.STEPI
+ || cmd == Command.RUN
+ || cmd == Command.CONT) {
+ break;
+ }
}
}
}
@@ -748,7 +1344,7 @@ public class Main {
jdb.init(args);
jdb.start();
if (jdb.status == Status.CONNECTED) {
- jdb.targetVM.dispose();
+ jdb.debuggee.dispose();
}
}