private int printThreadGroup(OutputSink out, ThreadGroupReference tg, int iThread) {
    out.println("Group " + tg.name() + ":");
    List<ThreadReference> tlist = tg.threads();
    int maxId = 0;
    int maxName = 0;
    for (int i = 0; i < tlist.size(); i++) {
      ThreadReference thr = tlist.get(i);
      int len = Utils.description(thr).length();
      if (len > maxId) {
        maxId = len;
      }
      String name = thr.name();
      int iDot = name.lastIndexOf('.');
      if (iDot >= 0 && name.length() > iDot) {
        name = name.substring(iDot + 1);
      }
      if (name.length() > maxName) {
        maxName = name.length();
      }
    }
    String maxNumString = String.valueOf(iThread + tlist.size());
    int maxNumDigits = maxNumString.length();
    for (int i = 0; i < tlist.size(); i++) {
      ThreadReference thr = tlist.get(i);
      char buf[] = new char[80];
      for (int j = 0; j < 79; j++) {
        buf[j] = ' ';
      }
      buf[79] = '\0';
      StringBuffer sbOut = new StringBuffer();
      sbOut.append(buf);

      // Right-justify the thread number at start of output string
      String numString = String.valueOf(iThread + i + 1);
      sbOut.insert(maxNumDigits - numString.length(), numString);
      sbOut.insert(maxNumDigits, ".");

      int iBuf = maxNumDigits + 2;
      sbOut.insert(iBuf, Utils.description(thr));
      iBuf += maxId + 1;
      String name = thr.name();
      int iDot = name.lastIndexOf('.');
      if (iDot >= 0 && name.length() > iDot) {
        name = name.substring(iDot + 1);
      }
      sbOut.insert(iBuf, name);
      iBuf += maxName + 1;
      sbOut.insert(iBuf, Utils.getStatus(thr));
      sbOut.setLength(79);
      out.println(sbOut.toString());
    }
    for (ThreadGroupReference tg0 : tg.threadGroups()) {
      if (!tg.equals(tg0)) { // TODO ref mgt
        iThread += printThreadGroup(out, tg0, iThread + tlist.size());
      }
    }
    return tlist.size();
  }
 private void printVar(OutputSink out, LocalVariable var, StackFrame frame) {
   out.print("  " + var.name());
   if (var.isVisible(frame)) {
     Value val = frame.getValue(var);
     out.println(" = " + val.toString());
   } else {
     out.println(" is not in scope");
   }
 }
 private void listEventRequests() throws NoSessionException {
   // Print set breakpoints
   List<EventRequestSpec> specs = runtime.eventRequestSpecs();
   if (specs.isEmpty()) {
     env.notice("No breakpoints/watchpoints/exceptions set.");
   } else {
     OutputSink out = env.getOutputSink();
     out.println("Current breakpoints/watchpoints/exceptions set:");
     for (EventRequestSpec bp : specs) {
       out.println("\t" + bp);
     }
     out.show();
   }
 }
  private void commandLocals() throws NoSessionException {
    ThreadReference current = context.getCurrentThread();
    if (current == null) {
      env.failure("No default thread specified: " + "use the \"thread\" command first.");
      return;
    }
    StackFrame frame;
    try {
      frame = context.getCurrentFrame(current);
      if (frame == null) {
        env.failure("Thread has not yet created any stack frames.");
        return;
      }
    } catch (VMNotInterruptedException e) {
      env.failure("Target VM must be in interrupted state.");
      return;
    }

    List<LocalVariable> vars;
    try {
      vars = frame.visibleVariables();
      if (vars == null || vars.size() == 0) {
        env.failure("No local variables");
        return;
      }
    } catch (AbsentInformationException e) {
      env.failure(
          "Local variable information not available."
              + " Compile with -g to generate variable information");
      return;
    }

    OutputSink out = env.getOutputSink();
    out.println("Method arguments:");
    for (LocalVariable var : vars) {
      if (var.isArgument()) {
        printVar(out, var, frame);
      }
    }
    out.println("Local variables:");
    for (LocalVariable var : vars) {
      if (!var.isArgument()) {
        printVar(out, var, frame);
      }
    }
    out.show();
    return;
  }
 private void commandWhere(StringTokenizer t, boolean showPC) throws NoSessionException {
   ThreadReference current = context.getCurrentThread();
   if (!t.hasMoreTokens()) {
     if (current == null) {
       env.error("No thread specified.");
       return;
     }
     dumpStack(current, showPC);
   } else {
     String token = t.nextToken();
     if (token.toLowerCase().equals("all")) {
       ThreadIterator it = allThreads();
       while (it.hasNext()) {
         ThreadReference thread = it.next();
         out.println(thread.name() + ": ");
         dumpStack(thread, showPC);
       }
     } else {
       ThreadReference thread = findThread(t.nextToken());
       // ### Do we want to set current thread here?
       // ### Should notify user of change.
       if (thread != null) {
         context.setCurrentThread(thread);
       }
       dumpStack(thread, showPC);
     }
   }
 }
 private void commandMethods(StringTokenizer t) throws NoSessionException {
   if (!t.hasMoreTokens()) {
     env.error("No class specified.");
     return;
   }
   String idClass = t.nextToken();
   ReferenceType cls = findClass(idClass);
   if (cls != null) {
     List<Method> methods = cls.allMethods();
     OutputSink out = env.getOutputSink();
     for (int i = 0; i < methods.size(); i++) {
       Method method = methods.get(i);
       out.print(method.declaringType().name() + " " + method.name() + "(");
       Iterator<String> it = method.argumentTypeNames().iterator();
       if (it.hasNext()) {
         while (true) {
           out.print(it.next());
           if (!it.hasNext()) {
             break;
           }
           out.print(", ");
         }
       }
       out.println(")");
     }
     out.show();
   } else {
     // ### Should validate class name syntax.
     env.failure("\"" + idClass + "\" is not a valid id or class name.");
   }
 }
 private void commandPrint(StringTokenizer t, boolean dumpObject) throws NoSessionException {
   if (!t.hasMoreTokens()) {
     // ### Probably confused if expresion contains whitespace.
     env.error("No expression specified.");
     return;
   }
   ThreadReference current = context.getCurrentThread();
   if (current == null) {
     env.failure("No default thread specified: " + "use the \"thread\" command first.");
     return;
   }
   StackFrame frame;
   try {
     frame = context.getCurrentFrame(current);
     if (frame == null) {
       env.failure("Thread has not yet created any stack frames.");
       return;
     }
   } catch (VMNotInterruptedException e) {
     env.failure("Target VM must be in interrupted state.");
     return;
   }
   while (t.hasMoreTokens()) {
     String expr = t.nextToken("");
     Value val = null;
     try {
       val = runtime.evaluate(frame, expr);
     } catch (Exception e) {
       env.error("Exception: " + e);
       // ### Fix this!
     }
     if (val == null) {
       return; // Error message already printed
     }
     OutputSink out = env.getOutputSink();
     if (dumpObject && (val instanceof ObjectReference) && !(val instanceof StringReference)) {
       ObjectReference obj = (ObjectReference) val;
       ReferenceType refType = obj.referenceType();
       out.println(expr + " = " + val.toString() + " {");
       dump(out, obj, refType, refType);
       out.println("}");
     } else {
       out.println(expr + " = " + val.toString());
     }
     out.show();
   }
 }
 private void commandClasses() throws NoSessionException {
   OutputSink out = env.getOutputSink();
   // out.println("** classes list **");
   for (ReferenceType refType : runtime.allClasses()) {
     out.println(refType.name());
   }
   out.show();
 }
 private void commandClasspath(StringTokenizer t) {
   if (!t.hasMoreTokens()) {
     out.println(classManager.getClassPath().asString());
   } else {
     // ### Should throw exception for invalid path.
     // ### E.g., vetoable property change.
     classManager.setClassPath(new SearchPath(t.nextToken()));
   }
 }
 private void dumpStack(ThreadReference thread, boolean showPC) {
   // ### Check for these.
   // env.failure("Thread no longer exists.");
   // env.failure("Target VM must be in interrupted state.");
   // env.failure("Current thread isn't suspended.");
   // ### Should handle extremely long stack traces sensibly for user.
   List<StackFrame> stack = null;
   try {
     stack = thread.frames();
   } catch (IncompatibleThreadStateException e) {
     env.failure("Thread is not suspended.");
   }
   // ### Fix this!
   // ### Previously mishandled cases where thread was not current.
   // ### Now, prints all of the stack regardless of current frame.
   int frameIndex = 0;
   // int frameIndex = context.getCurrentFrameIndex();
   if (stack == null) {
     env.failure("Thread is not running (no stack).");
   } else {
     OutputSink out = env.getOutputSink();
     int nFrames = stack.size();
     for (int i = frameIndex; i < nFrames; i++) {
       StackFrame frame = stack.get(i);
       Location loc = frame.location();
       Method meth = loc.method();
       out.print("  [" + (i + 1) + "] ");
       out.print(meth.declaringType().name());
       out.print('.');
       out.print(meth.name());
       out.print(" (");
       if (meth.isNative()) {
         out.print("native method");
       } else if (loc.lineNumber() != -1) {
         try {
           out.print(loc.sourceName());
         } catch (AbsentInformationException e) {
           out.print("<unknown>");
         }
         out.print(':');
         out.print(loc.lineNumber());
       }
       out.print(')');
       if (showPC) {
         long pc = loc.codeIndex();
         if (pc != -1) {
           out.print(", pc = " + pc);
         }
       }
       out.println();
     }
     out.show();
   }
 }
 private void commandThreadGroups() throws NoSessionException {
   ThreadGroupIterator it = allThreadGroups();
   int cnt = 0;
   OutputSink out = env.getOutputSink();
   while (it.hasNext()) {
     ThreadGroupReference tg = it.nextThreadGroup();
     ++cnt;
     out.println("" + cnt + ". " + Utils.description(tg) + " " + tg.name());
   }
   out.show();
 }
 private void dump(
     OutputSink out, ObjectReference obj, ReferenceType refType, ReferenceType refTypeBase) {
   for (Field field : refType.fields()) {
     out.print("    ");
     if (!refType.equals(refTypeBase)) {
       out.print(refType.name() + ".");
     }
     out.print(field.name() + ": ");
     Object o = obj.getValue(field);
     out.println((o == null) ? "null" : o.toString()); // Bug ID 4374471
   }
   if (refType instanceof ClassType) {
     ClassType sup = ((ClassType) refType).superclass();
     if (sup != null) {
       dump(out, obj, sup, refTypeBase);
     }
   } else if (refType instanceof InterfaceType) {
     for (InterfaceType sup : ((InterfaceType) refType).superinterfaces()) {
       dump(out, obj, sup, refTypeBase);
     }
   }
 }
 private void commandList(StringTokenizer t) throws NoSessionException {
   ThreadReference current = context.getCurrentThread();
   if (current == null) {
     env.error("No thread specified.");
     return;
   }
   Location loc;
   try {
     StackFrame frame = context.getCurrentFrame(current);
     if (frame == null) {
       env.failure("Thread has not yet begun execution.");
       return;
     }
     loc = frame.location();
   } catch (VMNotInterruptedException e) {
     env.failure("Target VM must be in interrupted state.");
     return;
   }
   SourceModel source = sourceManager.sourceForLocation(loc);
   if (source == null) {
     if (loc.method().isNative()) {
       env.failure("Current method is native.");
       return;
     }
     env.failure("No source available for " + Utils.locationString(loc) + ".");
     return;
   }
   ReferenceType refType = loc.declaringType();
   int lineno = loc.lineNumber();
   if (t.hasMoreTokens()) {
     String id = t.nextToken();
     // See if token is a line number.
     try {
       lineno = Integer.valueOf(id).intValue();
     } catch (NumberFormatException nfe) {
       // It isn't -- see if it's a method name.
       List<Method> meths = refType.methodsByName(id);
       if (meths == null || meths.size() == 0) {
         env.failure(
             id + " is not a valid line number or " + "method name for class " + refType.name());
         return;
       } else if (meths.size() > 1) {
         env.failure(id + " is an ambiguous method name in" + refType.name());
         return;
       }
       loc = meths.get(0).location();
       lineno = loc.lineNumber();
     }
   }
   int startLine = (lineno > 4) ? lineno - 4 : 1;
   int endLine = startLine + 9;
   String sourceLine = source.sourceLine(lineno);
   if (sourceLine == null) {
     env.failure("" + lineno + " is an invalid line number for " + refType.name());
   } else {
     OutputSink out = env.getOutputSink();
     for (int i = startLine; i <= endLine; i++) {
       sourceLine = source.sourceLine(i);
       if (sourceLine == null) {
         break;
       }
       out.print(i);
       out.print("\t");
       if (i == lineno) {
         out.print("=> ");
       } else {
         out.print("   ");
       }
       out.println(sourceLine);
     }
     out.show();
   }
 }
 public void executeCommand(String command) {
   // ### Treatment of 'out' here is dirty...
   out = env.getOutputSink();
   if (echo) {
     out.println(">>> " + command);
   }
   StringTokenizer t = new StringTokenizer(command);
   try {
     String cmd;
     if (t.hasMoreTokens()) {
       cmd = t.nextToken().toLowerCase();
       lastCommand = cmd;
     } else {
       cmd = lastCommand;
     }
     if (cmd.equals("print")) {
       commandPrint(t, false);
     } else if (cmd.equals("eval")) {
       commandPrint(t, false);
     } else if (cmd.equals("dump")) {
       commandPrint(t, true);
     } else if (cmd.equals("locals")) {
       commandLocals();
     } else if (cmd.equals("classes")) {
       commandClasses();
     } else if (cmd.equals("methods")) {
       commandMethods(t);
     } else if (cmd.equals("threads")) {
       commandThreads(t);
     } else if (cmd.equals("thread")) {
       commandThread(t);
     } else if (cmd.equals("suspend")) {
       commandSuspend(t);
     } else if (cmd.equals("resume")) {
       commandResume(t);
     } else if (cmd.equals("cont")) {
       commandCont();
     } else if (cmd.equals("threadgroups")) {
       commandThreadGroups();
     } else if (cmd.equals("threadgroup")) {
       commandThreadGroup(t);
     } else if (cmd.equals("run")) {
       commandRun(t);
     } else if (cmd.equals("load")) {
       commandLoad(t);
     } else if (cmd.equals("connect")) {
       commandConnect(t);
     } else if (cmd.equals("attach")) {
       commandAttach(t);
     } else if (cmd.equals("detach")) {
       commandDetach(t);
     } else if (cmd.equals("interrupt")) {
       commandInterrupt(t);
       // ### Not implemented.
       //          } else if (cmd.equals("catch")) {
       //              commandCatchException(t);
       // ### Not implemented.
       //          } else if (cmd.equals("ignore")) {
       //              commandIgnoreException(t);
     } else if (cmd.equals("step")) {
       commandStep(t);
     } else if (cmd.equals("stepi")) {
       commandStepi();
     } else if (cmd.equals("next")) {
       commandNext();
     } else if (cmd.equals("nexti")) {
       commandNexti();
     } else if (cmd.equals("kill")) {
       commandKill(t);
     } else if (cmd.equals("where")) {
       commandWhere(t, false);
     } else if (cmd.equals("wherei")) {
       commandWhere(t, true);
     } else if (cmd.equals("up")) {
       commandUp(t);
     } else if (cmd.equals("down")) {
       commandDown(t);
     } else if (cmd.equals("frame")) {
       commandFrame(t);
     } else if (cmd.equals("stop")) {
       commandStop(t);
     } else if (cmd.equals("clear")) {
       commandClear(t);
     } else if (cmd.equals("list")) {
       commandList(t);
     } else if (cmd.equals("use")) {
       commandUse(t);
     } else if (cmd.equals("sourcepath")) {
       commandSourcepath(t);
     } else if (cmd.equals("classpath")) {
       commandClasspath(t);
     } else if (cmd.equals("monitor")) {
       commandMonitor(t);
     } else if (cmd.equals("unmonitor")) {
       commandUnmonitor(t);
     } else if (cmd.equals("view")) {
       commandView(t);
       //          } else if (cmd.equals("read")) {
       //              readCommand(t);
     } else if (cmd.equals("help") || cmd.equals("?")) {
       help();
     } else if (cmd.equals("quit") || cmd.equals("exit")) {
       try {
         runtime.detach();
       } catch (NoSessionException e) {
         // ignore
       }
       env.terminate();
     } else {
       // ### Dubious repeat-count feature inherited from 'jdb'
       if (t.hasMoreTokens()) {
         try {
           int repeat = Integer.parseInt(cmd);
           String subcom = t.nextToken("");
           while (repeat-- > 0) {
             executeCommand(subcom);
           }
           return;
         } catch (NumberFormatException exc) {
         }
       }
       out.println("huh? Try help...");
       out.flush();
     }
   } catch (NoSessionException e) {
     out.println("There is no currently attached VM session.");
     out.flush();
   } catch (Exception e) {
     out.println("Internal exception: " + e.toString());
     out.flush();
     System.out.println("JDB internal exception: " + e.toString());
     e.printStackTrace();
   }
   out.show();
 }
 private void help() {
   out.println("** command list **");
   out.println("threads [threadgroup]     -- list threads");
   out.println("thread <thread id>        -- set default thread");
   out.println("suspend [thread id(s)]    -- suspend threads (default: all)");
   out.println("resume [thread id(s)]     -- resume threads (default: all)");
   out.println("where [thread id] | all   -- dump a thread's stack");
   out.println("wherei [thread id] | all  -- dump a thread's stack, with pc info");
   out.println("threadgroups              -- list threadgroups");
   out.println("threadgroup <name>        -- set current threadgroup\n");
   //      out.println("print <expression>        -- print value of expression");
   out.println("dump <expression>         -- print all object information\n");
   //      out.println("eval <expression>         -- evaluate expression (same as print)");
   out.println("locals                    -- print all local variables in current stack frame\n");
   out.println("classes                   -- list currently known classes");
   out.println("methods <class id>        -- list a class's methods\n");
   out.println(
       "stop [in] <class id>.<method>[(argument_type,...)] -- set a breakpoint in a method");
   out.println("stop [at] <class id>:<line> -- set a breakpoint at a line");
   out.println("up [n frames]             -- move up a thread's stack");
   out.println("down [n frames]           -- move down a thread's stack");
   out.println("frame <frame-id>           -- to a frame");
   out.println(
       "clear <class id>.<method>[(argument_type,...)]   -- clear a breakpoint in a method");
   out.println("clear <class id>:<line>   -- clear a breakpoint at a line");
   out.println("clear                     -- list breakpoints");
   out.println("step                      -- execute current line");
   out.println(
       "step up                   -- execute until the current method returns to its caller");
   out.println("stepi                     -- execute current instruction");
   out.println("next                      -- step one line (step OVER calls)");
   out.println("nexti                     -- step one instruction (step OVER calls)");
   out.println("cont                      -- continue execution from breakpoint\n");
   //      out.println("catch <class id>          -- break for the specified exception");
   //      out.println("ignore <class id>         -- ignore when the specified exception\n");
   out.println("view classname|filename   -- display source file");
   out.println("list [line number|method] -- print source code context at line or method");
   out.println("use <source file path>    -- display or change the source path\n");
   // ### new
   out.println("sourcepath <source file path>    -- display or change the source path\n");
   // ### new
   out.println("classpath <class file path>    -- display or change the class path\n");
   out.println(
       "monitor <expression>      -- evaluate an expression each time the program stops\n");
   out.println("unmonitor <monitor#>      -- delete a monitor\n");
   out.println("read <filename>           -- read and execute a command file\n");
   //      out.println("memory                    -- report memory usage");
   //      out.println("gc                        -- free unused objects\n");
   out.println("run <class> [args]        -- start execution of a Java class");
   out.println("run                       -- re-execute last class run");
   out.println(
       "load <class> [args]       -- start execution of a Java class, initially suspended");
   out.println("load                      -- re-execute last class run, initially suspended");
   out.println("attach <portname>         -- debug existing process\n");
   out.println("detach                    -- detach from debuggee process\n");
   out.println("kill <thread(group)>      -- kill a thread or threadgroup\n");
   out.println("!!                        -- repeat last command");
   out.println("help (or ?)               -- list commands");
   out.println("exit (or quit)            -- exit debugger");
 }