home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / sun / tools / ttydebug / TTY.java
Encoding:
Java Source  |  1998-03-20  |  50.2 KB  |  1,640 lines

  1. /*
  2.  * @(#)TTY.java    1.81 98/03/18
  3.  *
  4.  * Copyright 1995-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package sun.tools.ttydebug;
  16. import sun.tools.debug.*;
  17. import java.util.*;
  18. import java.io.*;
  19. import java.net.*;
  20.  
  21. public class TTY implements DebuggerCallback {
  22.     RemoteDebugger debugger;
  23.     RemoteThread currentThread;
  24.     RemoteThreadGroup currentThreadGroup;
  25.     PrintStream out = null;
  26.     PrintStream console = null;
  27.  
  28.     private static final String progname = "jdb";
  29.     private static final String version = "98/03/18";
  30.  
  31.     private String lastArgs = null;
  32.     
  33.     private RemoteThread indexToThread(int index) throws Exception {
  34.     setDefaultThreadGroup();
  35.         RemoteThread list[] = currentThreadGroup.listThreads(true);
  36.     if (index == 0 || index > list.length) {
  37.         return null;
  38.     }
  39.     return list[index-1];
  40.     }
  41.  
  42.     private int parseThreadId(String idToken) throws Exception {
  43.     if (idToken.startsWith("t@")) {
  44.         idToken = idToken.substring(2);
  45.     }
  46.  
  47.     int threadId;
  48.     try {
  49.         threadId = Integer.valueOf(idToken).intValue();
  50.     } catch (NumberFormatException e) {
  51.         threadId = 0;
  52.     }
  53.     if (indexToThread(threadId) == null) {
  54.         out.println("\"" + idToken +
  55.                    "\" is not a valid thread id.");
  56.         return 0;
  57.     }
  58.     return threadId;
  59.     }
  60.  
  61.     private void printPrompt() throws Exception {
  62.         if (currentThread == null) {
  63.             out.print("> ");
  64.         } else {
  65.             out.print(currentThread.getName() + "[" +
  66.                       (currentThread.getCurrentFrameIndex() + 1)
  67.                       + "] ");
  68.         }
  69.         out.flush();
  70.     }
  71.  
  72.     public synchronized void printToConsole(String text) throws Exception {
  73.         console.print(text);
  74.         console.flush();
  75.     }
  76.  
  77.     public void breakpointEvent(RemoteThread t) throws Exception {
  78.     out.print("\nBreakpoint hit: ");
  79.  
  80.     RemoteStackFrame[] stack = t.dumpStack();
  81.     if (stack.length > 0) {
  82.         out.println(stack[0].toString());
  83.             currentThread = t;
  84.     } else {
  85.             currentThread = null; // Avoid misleading results on future "where"
  86.         out.println("Invalid thread specified in breakpoint.");
  87.     }
  88.         printPrompt();
  89.     }
  90.  
  91.     public void exceptionEvent(RemoteThread t, String errorText) 
  92.       throws Exception {
  93.     out.println("\n" + errorText);
  94.     t.setCurrentFrameIndex(0);
  95.     currentThread = t;
  96.         printPrompt();
  97.     }
  98.  
  99.     public void threadDeathEvent(RemoteThread t) throws Exception {
  100.     out.println("\n" + t.getName() + " died.");
  101.         if (t == currentThread) {
  102.             currentThread = null;
  103.         }
  104.         printPrompt();
  105.     }
  106.  
  107.     public void quitEvent() throws Exception {
  108.         String msg = null;
  109.         if (lastArgs != null) {
  110.             StringTokenizer t = new StringTokenizer(lastArgs);
  111.             if (t.hasMoreTokens()) {
  112.                 msg = new String("\n" + t.nextToken() + " exited");
  113.             }
  114.         }
  115.         if (msg == null) {
  116.             msg = new String("\nThe application exited");
  117.         }
  118.         out.println(msg);
  119.         currentThread = null;
  120.         System.exit(0);
  121.     }
  122.  
  123.     void classes() throws Exception {
  124.     RemoteClass list[] = debugger.listClasses();
  125.  
  126.     out.println("** classes list **");
  127.     for (int i = 0 ; i < list.length ; i++) {
  128.         out.println(list[i].description());
  129.     }
  130.     }
  131.  
  132.     void methods(StringTokenizer t) throws Exception {
  133.     if (!t.hasMoreTokens()) {
  134.         out.println("No class specified.");
  135.         return;
  136.     }
  137.  
  138.     String idClass = t.nextToken();
  139.     try {
  140.         RemoteClass cls = getClassFromToken(idClass);
  141.  
  142.         RemoteField methods[] = cls.getMethods();
  143.         for (int i = 0; i < methods.length; i++) {
  144.         out.println(methods[i].getTypedName());
  145.         }
  146.     } catch (IllegalArgumentException e) {
  147.         out.println("\"" + idClass +
  148.                    "\" is not a valid id or class name.");
  149.     }
  150.     }
  151.  
  152.     int printThreadGroup(RemoteThreadGroup tg, int iThread) throws Exception {
  153.     out.println("Group " + tg.getName() + ":");
  154.     RemoteThread tlist[] = tg.listThreads(false);
  155.  
  156.     int maxId = 0;
  157.     int maxName = 0;
  158.     for (int i = 0 ; i < tlist.length ; i++) {
  159.         int len = tlist[i].description().length();
  160.         if (len > maxId)
  161.         maxId = len;
  162.         String name = tlist[i].getName();
  163.         int iDot = name.lastIndexOf('.');
  164.         if (iDot >= 0 && name.length() > iDot) {
  165.         name = name.substring(iDot + 1);
  166.         }
  167.         if (name.length() > maxName)
  168.         maxName = name.length();
  169.     }
  170.  
  171.         String maxNumString = String.valueOf(iThread + tlist.length);
  172.         int maxNumDigits = maxNumString.length();
  173.  
  174.     for (int i = 0 ; i < tlist.length ; i++) {
  175.         char buf[] = new char[80];
  176.         for (int j = 0; j < 79; j++) {
  177.         buf[j] = ' ';
  178.         }
  179.         buf[79] = '\0';
  180.         StringBuffer sbOut = new StringBuffer();
  181.         sbOut.append(buf);
  182.  
  183.             // Right-justify the thread number at start of output string
  184.             String numString = String.valueOf(iThread + i + 1);
  185.         sbOut.insert(maxNumDigits - numString.length(),
  186.                          numString);
  187.         sbOut.insert(maxNumDigits, ".");
  188.  
  189.         int iBuf = maxNumDigits + 2;
  190.         sbOut.insert(iBuf, tlist[i].description());
  191.         iBuf += maxId + 1;
  192.         String name = tlist[i].getName();
  193.         int iDot = name.lastIndexOf('.');
  194.         if (iDot >= 0 && name.length() > iDot) {
  195.         name = name.substring(iDot + 1);
  196.         }
  197.         sbOut.insert(iBuf, name);
  198.         iBuf += maxName + 1;
  199.         sbOut.insert(iBuf, tlist[i].getStatus());
  200.         sbOut.setLength(79);
  201.         out.println(sbOut.toString());
  202.     }
  203.  
  204.     RemoteThreadGroup tglist[] = debugger.listThreadGroups(tg);
  205.     for (int ig = 0; ig < tglist.length; ig++) {
  206.         if (tg != tglist[ig]) {
  207.         iThread += printThreadGroup(tglist[ig], iThread + tlist.length);
  208.         }
  209.     }
  210.     return tlist.length;
  211.     }
  212.  
  213.     private void setDefaultThreadGroup() throws Exception {
  214.     if (currentThreadGroup == null) {
  215.         RemoteThreadGroup tglist[] = debugger.listThreadGroups(null);
  216.         currentThreadGroup = tglist[0];    // system threadgroup
  217.     }
  218.     }
  219.     
  220.     void threads(StringTokenizer t) throws Exception {
  221.     if (!t.hasMoreTokens()) {
  222.         setDefaultThreadGroup();
  223.         printThreadGroup(currentThreadGroup, 0);
  224.         return;
  225.     }
  226.     String name = t.nextToken();
  227.     RemoteThreadGroup tglist[] = debugger.listThreadGroups(null);
  228.     for (int i = 0; i < tglist.length; i++) {
  229.         if (name.equals(tglist[i].getName())) {
  230.         printThreadGroup(tglist[i], 0);
  231.         return;
  232.         }
  233.     }
  234.     out.println(name + " is not a valid threadgroup name.");
  235.     }
  236.  
  237.     void threadGroups() throws Exception {
  238.     RemoteThreadGroup tglist[] = debugger.listThreadGroups(null);
  239.     for (int i = 0; i < tglist.length; i++) {
  240.         out.println(new Integer(i+1).toString() + ". " +
  241.                    tglist[i].description() + " " +
  242.                    tglist[i].getName());
  243.     }
  244.     }
  245.  
  246.     void setThread(int threadId) throws Exception {
  247.     setDefaultThreadGroup();
  248.     RemoteThread thread = indexToThread(threadId);
  249.     if (thread == null) {
  250.         out.println("\"" + threadId +
  251.                    "\" is not a valid thread id.");
  252.         return;
  253.     }
  254.     currentThread = thread;
  255.     }
  256.     
  257.     void thread(StringTokenizer t) throws Exception {
  258.     if (!t.hasMoreTokens()) {
  259.         out.println("Thread number not specified.");
  260.         return;
  261.     }
  262.     int threadId = parseThreadId(t.nextToken());
  263.     if (threadId == 0) {
  264.         return;
  265.     }
  266.     setThread(threadId);
  267.     }
  268.     
  269.     void threadGroup(StringTokenizer t) throws Exception {
  270.     if (!t.hasMoreTokens()) {
  271.         out.println("Threadgroup name not specified.");
  272.         return;
  273.     }
  274.     String name = t.nextToken();
  275.     RemoteThreadGroup tglist[] = debugger.listThreadGroups(null);
  276.     for (int i = 0; i < tglist.length; i++) {
  277.         if (name.equals(tglist[i].getName())) {
  278.         currentThreadGroup = tglist[i];
  279.         return;
  280.         }
  281.     }
  282.     out.println(name + " is not a valid threadgroup name.");
  283.     }
  284.     
  285.     void run(StringTokenizer t) throws Exception {
  286.     String argv[] = new String[100];
  287.     int argc = 0;
  288.  
  289.     if (!t.hasMoreTokens() && lastArgs != null) {
  290.         t = new StringTokenizer(lastArgs);
  291.         out.println("run " + lastArgs);
  292.     }
  293.     while (t.hasMoreTokens()) {
  294.         argv[argc++] = t.nextToken();
  295.             if (argc == 1) {
  296.                 // Expand name, if necessary.
  297.                 RemoteClass cls = debugger.findClass(argv[0]);
  298.                 if (cls == null) {
  299.                     out.println("Could not load the " + argv[0] + " class.");
  300.                     return;
  301.                 }
  302.                 argv[0] = cls.getName();
  303.             }
  304.     }
  305.  
  306.     if (argc > 0) {
  307.         RemoteThreadGroup newGroup = debugger.run(argc, argv);
  308.         if (newGroup != null) {
  309.         currentThreadGroup = newGroup;
  310.         setThread(1);
  311.         out.println("running ...");
  312.         } else {
  313.         out.println(argv[0] + " failed.");
  314.         }
  315.     } else {
  316.         out.println("No class name specified.");
  317.     }
  318.     }
  319.  
  320.     void load(StringTokenizer t) throws Exception {
  321.     if (!t.hasMoreTokens()) {
  322.         out.println("Class name not specified.");
  323.         return;
  324.     }
  325.     String idToken = t.nextToken();
  326.     RemoteClass cls = debugger.findClass(idToken);
  327.     if (cls == null) {
  328.         out.print(idToken + " not found");
  329.         out.println((idToken.indexOf('.') > 0) ?
  330.                    " (try the full name)" : "");
  331.     } else {
  332.         out.println(cls.toString());
  333.     }
  334.     }
  335.  
  336.     void suspend(StringTokenizer t) throws Exception {
  337.     if (!t.hasMoreTokens()) {
  338.         setDefaultThreadGroup();
  339.         RemoteThread list[] = currentThreadGroup.listThreads(true);
  340.         for (int i = 0; i < list.length; i++) {
  341.         list[i].suspend();
  342.         }
  343.         out.println("All (non-system) threads suspended.");
  344.     } else {
  345.         while (t.hasMoreTokens()) {
  346.         String idToken = t.nextToken();
  347.         int threadId;
  348.         try {
  349.             threadId = Integer.valueOf(idToken).intValue();
  350.         } catch (NumberFormatException e) {
  351.             threadId = 0;
  352.         }
  353.         RemoteThread thread = indexToThread(threadId);
  354.         if (thread == null) {
  355.             out.println("\"" + idToken +
  356.                        "\" is not a valid thread id.");
  357.             continue;
  358.         }
  359.         thread.suspend();
  360.         }
  361.     }
  362.     }
  363.  
  364.     void resume(StringTokenizer t) throws Exception {
  365.      if (!t.hasMoreTokens()) {
  366.         setDefaultThreadGroup();
  367.         RemoteThread list[] = currentThreadGroup.listThreads(true);
  368.         for (int i = 0; i < list.length; i++) {
  369.         list[i].resume();
  370.         }
  371.         if (currentThread != null) {
  372.         currentThread.resetCurrentFrameIndex();
  373.         }
  374.          out.println("All threads resumed.");
  375.      } else {
  376.          while (t.hasMoreTokens()) {
  377.          String idToken = t.nextToken();
  378.          int threadId;
  379.          try {
  380.              threadId = Integer.valueOf(idToken).intValue();
  381.          } catch (NumberFormatException e) {
  382.              threadId = 0;
  383.          }
  384.         RemoteThread thread = indexToThread(threadId);
  385.         if (thread == null) {
  386.              out.println("\"" + idToken +
  387.                        "\" is not a valid thread id.");
  388.              continue;
  389.          }
  390.          thread.resume();
  391.          if (thread == currentThread) {
  392.              currentThread.resetCurrentFrameIndex();
  393.          }
  394.           }
  395.     }
  396.     }
  397.  
  398.     void cont() throws Exception {
  399.         if (currentThread == null) {
  400.             out.println("Nothing suspended.");
  401.             return;
  402.         }
  403.     debugger.cont();
  404.     }
  405.  
  406.     /* step
  407.      *
  408.      * step up (out of a function).
  409.      * Courtesy of Gordon Hirsch of SAS.
  410.      */
  411.     void step(StringTokenizer t) throws Exception {
  412.     if (currentThread == null) {
  413.         out.println("Nothing suspended.");
  414.         return;
  415.     }
  416.     try {
  417.         if (t.hasMoreTokens()) {
  418.         String nt = t.nextToken().toLowerCase();
  419.         if (nt.equals("up")) {
  420.             currentThread.stepOut();               
  421.         } else {
  422.             currentThread.step(true);
  423.         }
  424.         } else {
  425.         currentThread.step(true);
  426.         }
  427.     } catch (IllegalAccessError e) {
  428.         out.println("Current thread is not suspended.");
  429.     }
  430.     }
  431.  
  432.     /* stepi
  433.      * step instruction.
  434.      * Courtesy of Gordon Hirsch of SAS.
  435.      */
  436.     void stepi() throws Exception {
  437.     if (currentThread == null) {
  438.         out.println("Nothing suspended.");
  439.         return;
  440.     }
  441.     try {
  442.         currentThread.step(false);
  443.     } catch (IllegalAccessError e) {
  444.         out.println("Current thread is not suspended.");
  445.     }
  446.     }
  447.  
  448.     void next() throws Exception {
  449.     if (currentThread == null) {
  450.         out.println("Nothing suspended.");
  451.         return;
  452.     }
  453.     try {
  454.         currentThread.next();
  455.     } catch (IllegalAccessError e) {
  456.         out.println("Current thread is not suspended.");
  457.     }
  458.     }
  459.  
  460.     void kill(StringTokenizer t) throws Exception {
  461.      if (!t.hasMoreTokens()) {
  462.         out.println("Usage: kill <threadgroup name> or <thread id>");
  463.         return;
  464.     }
  465.     while (t.hasMoreTokens()) {
  466.         String idToken = t.nextToken();
  467.         int threadId;
  468.         try {
  469.         threadId = Integer.valueOf(idToken).intValue();
  470.         } catch (NumberFormatException e) {
  471.         threadId = 0;
  472.         }
  473.         RemoteThread thread = indexToThread(threadId);
  474.         if (thread != null) {
  475.                 out.println("killing thread: " + thread.getName());
  476.         thread.stop();
  477.                 return;
  478.         } else {
  479.         /* Check for threadgroup name, skipping "system". */
  480.         RemoteThreadGroup tglist[] = debugger.listThreadGroups(null);
  481.         tglist = debugger.listThreadGroups(tglist[0]);
  482.         for (int i = 0; i < tglist.length; i++) {
  483.             if (tglist[i].getName().equals(idToken)) {
  484.                         out.println("killing threadgroup: " + idToken);
  485.             tglist[i].stop();
  486.             return;
  487.             }
  488.         }
  489.         
  490.         out.println("\"" + idToken +
  491.                    "\" is not a valid threadgroup or id.");
  492.         }
  493.     }
  494.     }
  495.  
  496.     void catchException(StringTokenizer t) throws Exception {
  497.      if (!t.hasMoreTokens()) {
  498.         String exceptionList[] = debugger.getExceptionCatchList();
  499.         for (int i = 0; i < exceptionList.length; i++) {
  500.         out.print("  " + exceptionList[i]);
  501.         if ((i & 4) == 3 || (i == exceptionList.length - 1)) {
  502.             out.println();
  503.         }
  504.         }
  505.     } else {
  506.         String idClass = t.nextToken();
  507.         try {
  508.         RemoteClass cls = getClassFromToken(idClass);
  509.         cls.catchExceptions();
  510.         } catch (Exception e) {
  511.         out.println("Invalid exception class name: " + idClass);
  512.         }
  513.     }
  514.     }
  515.     
  516.     void ignoreException(StringTokenizer t) throws Exception {
  517.         String exceptionList[] = debugger.getExceptionCatchList();
  518.  
  519.      if (!t.hasMoreTokens()) {
  520.         for (int i = 0; i < exceptionList.length; i++) {
  521.         out.print("  " + exceptionList[i]);
  522.         if ((i & 4) == 3 || (i == exceptionList.length - 1)) {
  523.             out.println();
  524.         }
  525.         }
  526.     } else {
  527.         String idClass = t.nextToken();
  528.         try {
  529.         RemoteClass cls = getClassFromToken(idClass);
  530.  
  531.                 /* Display an error if exception not currently caught */
  532.                 boolean caught = false;
  533.                 for (int i = 0; i < exceptionList.length; i++) {
  534.                     if (idClass.equals(exceptionList[i])) {
  535.                         caught = true;
  536.                         break;
  537.                     }
  538.                 }
  539.                 if (!caught) {
  540.                     out.println("Exception not currently caught: " + idClass);
  541.                 } else {
  542.                     cls.ignoreExceptions();
  543.                 }
  544.         } catch (Exception e) {
  545.         out.println("Invalid exception class name: " + idClass);
  546.         }
  547.     }
  548.     }
  549.     
  550.     void up(StringTokenizer t) throws Exception {
  551.     if (currentThread == null) {
  552.         out.println("Current thread not set.");
  553.         return;
  554.     }
  555.  
  556.     int nLevels = 1;
  557.     if (t.hasMoreTokens()) {
  558.         String idToken = t.nextToken();
  559.         int n;
  560.         try {
  561.         n = Integer.valueOf(idToken).intValue();
  562.         } catch (NumberFormatException e) {
  563.         n = 0;
  564.         }
  565.         if (n == 0) {
  566.         out.println("Usage: up [n frames]");
  567.         return;
  568.         }
  569.         nLevels = n;
  570.     }
  571.  
  572.     try {
  573.         currentThread.up(nLevels);
  574.     } catch (IllegalAccessError e) {
  575.         out.println("Thread isn't suspended.");
  576.     } catch (ArrayIndexOutOfBoundsException e) {
  577.         out.println("End of stack.");
  578.     }
  579.     }
  580.  
  581.     void down(StringTokenizer t) throws Exception {
  582.     if (currentThread == null) {
  583.         out.println("Current thread not set.");
  584.         return;
  585.     }
  586.  
  587.     int nLevels = 1;
  588.     if (t.hasMoreTokens()) {
  589.         String idToken = t.nextToken();
  590.         int n;
  591.         try {
  592.         n = Integer.valueOf(idToken).intValue();
  593.         } catch (NumberFormatException e) {
  594.         n = 0;
  595.         }
  596.         if (n == 0) {
  597.         out.println("usage: down [n frames]");
  598.         return;
  599.         }
  600.         nLevels = n;
  601.     }
  602.  
  603.     try {
  604.         currentThread.down(nLevels);
  605.     } catch (IllegalAccessError e) {
  606.         out.println("Thread isn't suspended.");
  607.     } catch (ArrayIndexOutOfBoundsException e) {
  608.         out.println("End of stack.");
  609.     }
  610.     }
  611.  
  612.     void dumpStack(RemoteThread thread, boolean showPC) throws Exception {
  613.     RemoteStackFrame[] stack = thread.dumpStack();
  614.     if (stack.length == 0) {
  615.         out.println("Thread is not running (no stack).");
  616.     } else {
  617.         int nFrames = stack.length;
  618.         for (int i = thread.getCurrentFrameIndex(); i < nFrames; i++) {
  619.         out.print("  [" + (i + 1) + "] ");
  620.         out.print(stack[i].toString());
  621.         if (showPC) {
  622.             out.print(", pc = " + stack[i].getPC());
  623.         }
  624.         out.println();
  625.         }
  626.     }
  627.     }
  628.  
  629.     void where(StringTokenizer t, boolean showPC) throws Exception {
  630.     if (!t.hasMoreTokens()) {
  631.         if (currentThread == null) {
  632.         out.println("No thread specified.");
  633.         return;
  634.         }
  635.         dumpStack(currentThread, showPC);
  636.     } else {
  637.         String token = t.nextToken();
  638.         if (token.toLowerCase().equals("all")) {
  639.         setDefaultThreadGroup();
  640.         RemoteThread list[] = currentThreadGroup.listThreads(true);
  641.         for (int i = 0; i < list.length; i++) {
  642.             out.println(list[i].getName() + ": ");
  643.             dumpStack(list[i], showPC);
  644.         }
  645.         } else {
  646.         int threadId = parseThreadId(token);
  647.         if (threadId == 0) {
  648.             return;
  649.         }
  650.         dumpStack(indexToThread(threadId), showPC);
  651.         }
  652.     }
  653.     }
  654.  
  655.     void trace(String cmd, StringTokenizer t) throws Exception {
  656.     if (!t.hasMoreTokens()) {
  657.         out.println("(i)trace < \"on\" | \"off\" >");
  658.         return;
  659.     }
  660.     
  661.     String v = t.nextToken();
  662.     boolean traceOn;
  663.     if (v.equals("on")) {
  664.         traceOn = true;
  665.     } else if (v.equals("off")) {
  666.         traceOn = false;
  667.     } else {
  668.         out.println("(i)trace < \"on\" | \"off\" >");
  669.         return;
  670.     }
  671.  
  672.     if (cmd.equals("trace")) {
  673.         debugger.trace(traceOn);
  674.     } else {
  675.         debugger.itrace(traceOn);
  676.     }
  677.     }
  678.  
  679.     void memory() throws Exception {
  680.     out.println("Free: " + debugger.freeMemory() + ", total: " +
  681.                debugger.totalMemory());
  682.     }
  683.  
  684.     void gc() throws Exception {
  685.         RemoteObject[] save_list = new RemoteObject[2];
  686.         save_list[0] = currentThread;
  687.         save_list[1] = currentThreadGroup;
  688.         debugger.gc(save_list);
  689.     }
  690.  
  691.     private RemoteClass getClassFromToken(String idToken) throws Exception {
  692.     RemoteObject obj;
  693.     if (idToken.startsWith("0x") ||
  694.         Character.isDigit(idToken.charAt(0))) {
  695.         /* It's an object id. */
  696.         int id;
  697.         try {
  698.         id = RemoteObject.fromHex(idToken);
  699.         } catch (NumberFormatException e) {
  700.         id = 0;
  701.         }
  702.         if (id == 0 || (obj = debugger.get(new Integer(id))) == null) {
  703.         throw new IllegalArgumentException();
  704.         } else if (!(obj instanceof RemoteClass)) {
  705.         throw new IllegalArgumentException();
  706.         }
  707.     } else {
  708.         /* It's a class */
  709.         obj = debugger.findClass(idToken);
  710.         if (obj == null) {
  711.         throw new IllegalArgumentException();
  712.         }
  713.     }
  714.     return (RemoteClass)obj;
  715.     }
  716.  
  717.     void listBreakpoints() throws Exception {
  718.         String bkptList[] = debugger.listBreakpoints();
  719.     if (bkptList.length > 0) {
  720.             out.println("Current breakpoints set:");
  721.             for(int i = 0; i < bkptList.length; i++) {
  722.                 out.println("\t" + bkptList[i]);
  723.             }
  724.     } else {
  725.         out.println("No breakpoints set.");
  726.     }
  727.     }
  728.  
  729.     void stop(StringTokenizer t) throws Exception {
  730.     if (!t.hasMoreTokens()) {
  731.         listBreakpoints();
  732.         return;
  733.     }
  734.     
  735.     String idClass = null;
  736.     try {
  737.         String modifier = t.nextToken();
  738.         boolean stopAt;
  739.         if (modifier.equals("at")) {
  740.         stopAt = true;
  741.         } else if (modifier.equals("in")) {
  742.         stopAt = false;
  743.         } else {
  744.         out.println("Usage: stop at <class>:<line_number> or");
  745.         out.println("       stop in <class>.<method_name>");
  746.         return;
  747.         }
  748.  
  749.         if (modifier.equals("at")) {
  750.         idClass = t.nextToken(": \t\n\r");
  751.         RemoteClass cls = getClassFromToken(idClass);
  752.  
  753.         String idLine = t.nextToken();
  754.         int lineno = Integer.valueOf(idLine).intValue();
  755.  
  756.         String err = cls.setBreakpointLine(lineno);
  757.         if (err.length() > 0) {
  758.             out.println(err);
  759.         } else {
  760.             out.println("Breakpoint set at " + cls.getName() +
  761.                        ":" + lineno);
  762.         }
  763.         } else {
  764.         idClass = t.nextToken(": \t\n\r");
  765.                 RemoteClass cls = null;
  766.                 String idMethod = null;
  767.  
  768.                 try {
  769.                     cls = getClassFromToken(idClass);
  770.                 } catch (IllegalArgumentException e) {
  771.                     // Try stripping method from class.method token.
  772.                     int idot = idClass.lastIndexOf(".");
  773.                     if (idot == -1) {
  774.                         out.println("\"" + idClass +
  775.                             "\" is not a valid id or class name.");
  776.                         return;
  777.                     }
  778.                     idMethod = idClass.substring(idot + 1);
  779.                     idClass = idClass.substring(0, idot);
  780.                     cls = getClassFromToken(idClass);
  781.                 }
  782.  
  783.                 if (idMethod == null) {
  784.                     idMethod = t.nextToken();
  785.                 }
  786.                 RemoteField method;
  787.                 try {
  788.                     method = cls.getMethod(idMethod);
  789.  
  790.                     /*
  791.                      * Prevent a breakpoint on overloaded method, since there
  792.                      * is, currently,  no way to choose among the overloads.
  793.                      */
  794.                     RemoteField[] allMethods = cls.getMethods();
  795.                     for (int i = 0; i < allMethods.length; i++) {
  796.                         if (allMethods[i].getName().equals(idMethod)
  797.                                         && (allMethods[i] != method)) {
  798.                             out.println(cls.getName() + "." + idMethod 
  799.                                 + " is overloaded. Use the 'stop at' command to " 
  800.                                 + "set a breakpoint in one of the overloads");
  801.                             return;
  802.                             
  803.                         }
  804.                     }
  805.  
  806.                 } catch (NoSuchMethodException nsme) {
  807.             out.println("Class " + cls.getName() +
  808.                        " doesn't have a method " + idMethod);
  809.             return;
  810.         }
  811.         String err = cls.setBreakpointMethod(method);
  812.         if (err.length() > 0) {
  813.             out.println(err);
  814.         } else {
  815.             out.println("Breakpoint set in " + cls.getName() +
  816.                        "." + idMethod);
  817.         }
  818.         }
  819.     } catch (NoSuchElementException e) {
  820.         out.println("Usage: stop at <class>:<line_number> or");
  821.         out.println("       stop in <class>.<method_name>");
  822.     } catch (NumberFormatException e) {
  823.         out.println("Invalid line number.");
  824.     } catch (IllegalArgumentException e) {
  825.         out.println("\"" + idClass +
  826.                    "\" is not a valid id or class name.");
  827.     }
  828.     }
  829.  
  830.     void clear(StringTokenizer t) throws Exception {
  831.     if (!t.hasMoreTokens()) {
  832.         listBreakpoints();
  833.         return;
  834.     }
  835.     
  836.     String idClass = null;
  837.     String idMethod = null;
  838.     RemoteClass cls = null;
  839.     try {
  840.         idClass = t.nextToken(": \t\n\r");
  841.         try {
  842.             cls = getClassFromToken(idClass);
  843.             } catch (IllegalArgumentException e) {
  844.                 // Try stripping method from class.method token.
  845.                 int idot = idClass.lastIndexOf(".");
  846.                 if (idot == -1) {
  847.                     out.println("\"" + idClass +
  848.                         "\" is not a valid id or class name.");
  849.                     return;
  850.                 }
  851.                 idMethod = idClass.substring(idot + 1);
  852.                 idClass = idClass.substring(0, idot);
  853.                 cls = getClassFromToken(idClass);
  854.                 RemoteField method;
  855.                 try {
  856.                     method = cls.getMethod(idMethod);
  857.                 } catch (NoSuchMethodException nsme) {
  858.             out.println("\"" + idMethod + 
  859.                 "\" is not a valid method name of class " +
  860.                 cls.getName());
  861.             return;
  862.         }
  863.         String err = cls.clearBreakpointMethod(method);
  864.             if (err.length() > 0) {
  865.             out.println(err);
  866.             } else {
  867.             out.println("Breakpoint cleared at " + 
  868.                 cls.getName() + "." + idMethod);
  869.         }
  870.         return;
  871.             }
  872.  
  873.         String idLine = t.nextToken();
  874.         int lineno = Integer.valueOf(idLine).intValue();
  875.  
  876.         String err = cls.clearBreakpointLine(lineno);
  877.         if (err.length() > 0) {
  878.         out.println(err);
  879.         } else {
  880.         out.println("Breakpoint cleared at " + cls.getName() +
  881.                    ": " + lineno);
  882.         }
  883.     } catch (NoSuchElementException e) {
  884.         out.println("Usage: clear <class>:<line_number>");
  885.         out.println("   or: clear <class>.<method>");
  886.     } catch (NumberFormatException e) {
  887.         out.println("Usage: clear <class>:<line_number>");
  888.         out.println("   or: clear <class>.<method>");
  889.     } catch (IllegalArgumentException e) {
  890.         out.println("\"" + idClass +
  891.                    "\" is not a valid id or class name.");
  892.     }
  893.     }
  894.  
  895.     void list(StringTokenizer t) throws Exception {
  896.     RemoteStackFrame frame = null;
  897.     if (currentThread == null) {
  898.         out.println("No thread specified.");
  899.         return;
  900.     }
  901.     try {
  902.         frame = currentThread.getCurrentFrame();
  903.     } catch (IllegalAccessError e) {
  904.         out.println("Current thread isn't suspended.");
  905.         return;
  906.     } catch (ArrayIndexOutOfBoundsException e) {
  907.         out.println("Thread is not running (no stack).");
  908.         return;
  909.     }
  910.  
  911.         if (frame.getPC() == -1) {
  912.             out.println("Current method is native");
  913.             return;
  914.         }
  915.     
  916.     int lineno;
  917.     if (t.hasMoreTokens()) {
  918.         String id = t.nextToken();
  919.  
  920.             // See if token is a line number.
  921.             try {
  922.                 lineno = Integer.valueOf(id).intValue();
  923.             } catch (NumberFormatException nfe) {
  924.                 // It isn't -- see if it's a method name.
  925.                 try {
  926.                     lineno = frame.getRemoteClass().getMethodLineNumber(id);
  927.                 } catch (NoSuchMethodException iobe) {
  928.                     out.println(id + " is not a valid line number or " +
  929.                                 "method name for class " + 
  930.                                 frame.getRemoteClass().getName());
  931.                     return;
  932.                 } catch (NoSuchLineNumberException nse) {
  933.                     out.println("Line number information not found in " +
  934.                                 frame.getRemoteClass().getName());
  935.                     return;
  936.                 }
  937.             }
  938.     } else {
  939.         lineno = frame.getLineNumber();
  940.     }
  941.     int startLine = (lineno > 4) ? lineno - 4 : 1;
  942.     int endLine = startLine + 9;
  943.  
  944.     InputStream rawSourceFile = frame.getRemoteClass().getSourceFile();
  945.     if (rawSourceFile == null) {
  946.         out.println("Unable to find " + 
  947.                         frame.getRemoteClass().getSourceFileName());
  948.         return;
  949.     }
  950.  
  951.     DataInputStream sourceFile = new DataInputStream(rawSourceFile);
  952.     String sourceLine = null;
  953.  
  954.     /* Skip through file to desired window. */
  955.     for (int i = 1; i <= startLine; i++) {
  956.         sourceLine = sourceFile.readLine();
  957.     }
  958.     if (sourceLine == null) {
  959.         out.println(new Integer(lineno).toString() +
  960.                         " is an invalid line number for the file " +
  961.                         frame.getRemoteClass().getSourceFileName());
  962.     }
  963.  
  964.     /* Print lines */
  965.     for (int i = startLine; i < endLine && sourceLine != null; i++) {
  966.         out.print(new Integer(i).toString() + "\t" +
  967.                  ((i == lineno) ? "=> " : "   "));
  968.         out.println(sourceLine);
  969.         sourceLine = sourceFile.readLine();
  970.     }
  971.         
  972.     }
  973.  
  974.     /* Get or set the source file path list. */
  975.     void use(StringTokenizer t) throws Exception {
  976.     if (!t.hasMoreTokens()) {
  977.         out.println(debugger.getSourcePath());
  978.     } else {
  979.         debugger.setSourcePath(t.nextToken());
  980.     }
  981.     }
  982.  
  983.     /* Print a stack variable */
  984.     private void printVar(RemoteStackVariable var) {
  985.         out.print("  " + var.getName());
  986.         if (var.inScope()) {
  987.             RemoteValue val = var.getValue();
  988.             out.println(" = " + (val == null? "null" : val.toString()) );
  989.         } else {
  990.             out.println(" is not in scope");
  991.         }
  992.     }
  993.  
  994.     /* Print all local variables in current stack frame. */
  995.     void locals() throws Exception {
  996.     if (currentThread == null) {
  997.         out.println("No default thread specified: " +
  998.                    "use the \"thread\" command first.");
  999.         return;
  1000.     }
  1001.         if (!currentThread.isSuspended()) {
  1002.             out.println("Thread isn't suspended.");
  1003.             return;
  1004.         }
  1005.     RemoteStackVariable rsv[] = currentThread.getStackVariables();
  1006.     if (rsv == null || rsv.length == 0) {
  1007.         out.println("No local variables: try compiling with -g");
  1008.         return;
  1009.     }
  1010.     out.println("Method arguments:");
  1011.     for (int i = 0; i < rsv.length; i++) {
  1012.         if (rsv[i].methodArgument()) {
  1013.         printVar(rsv[i]);
  1014.         }
  1015.     }
  1016.     out.println("Local variables:");
  1017.     for (int i = 0; i < rsv.length; i++) {
  1018.         if (!rsv[i].methodArgument()) {
  1019.         printVar(rsv[i]);
  1020.             }
  1021.     }
  1022.     return;
  1023.     }
  1024.  
  1025.     static final String printDelimiters = ".[(";
  1026.  
  1027.     /* Print a specified reference. 
  1028.      * New print() implementation courtesy of S. Blackheath of IBM
  1029.      */
  1030.     void print(StringTokenizer t, boolean dumpObject) throws Exception {
  1031.     if (!t.hasMoreTokens()) {
  1032.         out.println("No objects specified.");
  1033.             return;
  1034.     }
  1035.  
  1036.     int id;
  1037.     RemoteValue obj = null;
  1038.  
  1039.         while (t.hasMoreTokens()) {
  1040.         String expr = t.nextToken();
  1041.         StringTokenizer pieces =
  1042.            new StringTokenizer(expr, printDelimiters, true);
  1043.  
  1044.         String idToken = pieces.nextToken(); // There will be at least one.
  1045.         if (idToken.startsWith("t@")) {
  1046.             /* It's a thread */
  1047.             setDefaultThreadGroup();
  1048.             RemoteThread tlist[] = currentThreadGroup.listThreads(true);
  1049.             try {
  1050.                 id = Integer.valueOf(idToken.substring(2)).intValue();
  1051.             } catch (NumberFormatException e) {
  1052.             id = 0;
  1053.             }
  1054.             if (id <= 0 || id > tlist.length) {
  1055.                 out.println("\"" + idToken +
  1056.                    "\" is not a valid thread id.");
  1057.                     continue;
  1058.             }
  1059.             obj = tlist[id - 1];
  1060.  
  1061.         } else if (idToken.startsWith("$s")) {
  1062.             int slotnum;
  1063.             try {
  1064.                 slotnum = Integer.valueOf(idToken.substring(2)).intValue();
  1065.             } catch (NumberFormatException e) {
  1066.  
  1067.                 out.println("\"" + idToken + "\" is not a valid slot.");
  1068.                     continue;
  1069.             }
  1070.             if (currentThread != null) {
  1071.                 RemoteStackVariable rsv[] = currentThread.getStackVariables();
  1072.             if (rsv == null || slotnum >= rsv.length) {
  1073.                 out.println("\"" + idToken + "\" is not a valid slot.");
  1074.                         continue;
  1075.             }
  1076.             obj = rsv[slotnum].getValue();
  1077.             }
  1078.         
  1079.         } else if (idToken.startsWith("0x") ||
  1080.                Character.isDigit(idToken.charAt(0))) {
  1081.             /* It's an object id. */
  1082.             try {
  1083.                 id = RemoteObject.fromHex(idToken);
  1084.             } catch (NumberFormatException e) {
  1085.                 id = 0;
  1086.             }
  1087.                 if (id == 0 || (obj = debugger.get(new Integer(id))) == null) {
  1088.                 out.println("\"" + idToken + "\" is not a valid id.");
  1089.                     continue;
  1090.             }
  1091.         } else {
  1092.             /* See if it's a local stack variable */
  1093.                 RemoteStackVariable rsv = null;
  1094.             if (currentThread != null) {
  1095.             rsv = currentThread.getStackVariable(idToken);
  1096.             if (rsv != null && !rsv.inScope()) {
  1097.                 out.println(idToken + " is not in scope.");
  1098.                         continue;
  1099.             }
  1100.             obj = (rsv == null) ? null : rsv.getValue();
  1101.             }
  1102.             if (rsv == null) {
  1103.                     String error = null;
  1104.                     /* See if it's an instance variable */
  1105.                     String instanceStr = idToken;
  1106.                     try {
  1107.                         instanceStr = instanceStr + pieces.nextToken("");
  1108.                     }
  1109.                     catch (NoSuchElementException e) {}
  1110.  
  1111.                     if (currentThread != null)
  1112.                         rsv = currentThread.getStackVariable("this");
  1113.                     if (rsv != null && rsv.inScope()) {
  1114.                         obj = rsv.getValue();
  1115.  
  1116.                         error = printModifiers(expr,
  1117.                               new StringTokenizer("."+instanceStr, printDelimiters, true),
  1118.                               dumpObject, obj, true);
  1119.                         if (error == null)
  1120.                             continue;
  1121.                     }
  1122.  
  1123.                     // If the above failed, then re-construct the same
  1124.                     // string tokenizer we had before.
  1125.                     pieces = new StringTokenizer(instanceStr, printDelimiters, true);
  1126.                     idToken = pieces.nextToken();
  1127.  
  1128.             /* Try interpreting it as a class */
  1129.                     while (true) {
  1130.                 obj = debugger.findClass(idToken);
  1131.                 if (obj != null)             // break if this is a valid class name
  1132.                             break;
  1133.                         if (!pieces.hasMoreTokens()) // break if we run out of input
  1134.                             break;
  1135.                         String dot = pieces.nextToken();
  1136.                         if (!dot.equals("."))        // break if this token is not a dot
  1137.                             break;
  1138.                         if (!pieces.hasMoreTokens())
  1139.                             break;
  1140.                         // If it is a dot, then add the next token, and loop
  1141.                         idToken = idToken + dot + pieces.nextToken();
  1142.                     }
  1143.                     if (obj == null) {
  1144.                         if (error == null)
  1145.                     error = "\"" + expr + "\" is not a " + "valid local or class name.";
  1146.                     }
  1147.                     else {
  1148.                         String error2 = printModifiers(expr, pieces, dumpObject, obj, false);
  1149.                         if (error2 == null)
  1150.                             continue;
  1151.                         if (error == null)
  1152.                             error = error2;
  1153.                     }
  1154.                     out.println(error);
  1155.                     continue;
  1156.             }
  1157.         }
  1158.             String error = printModifiers(expr, pieces, dumpObject, obj, false);
  1159.             if (error != null)
  1160.                 out.println(error);
  1161.         }
  1162.     }
  1163.  
  1164.     String printModifiers(String expr, StringTokenizer pieces, boolean dumpObject, RemoteValue obj,
  1165.         boolean could_be_local_or_class)
  1166.         throws Exception
  1167.     {
  1168.         RemoteInt noValue = new RemoteInt(-1);
  1169.         RemoteValue rv = noValue;
  1170.  
  1171.         // If the object is null, or a non-object type (integer, array, etc...)
  1172.         // then the value must be in rv.
  1173.         if (obj == null)
  1174.             rv = null;
  1175.         else
  1176.         if (!obj.isObject())
  1177.             rv = obj;
  1178.  
  1179.     String lastField = "";
  1180.     String idToken = pieces.hasMoreTokens() ? pieces.nextToken() : null;
  1181.     while (idToken != null) {
  1182.  
  1183.         if (idToken.equals(".")) {
  1184.             if (pieces.hasMoreTokens() == false) {
  1185.             return "\"" + expr + "\" is not a valid expression.";
  1186.         }
  1187.         idToken = pieces.nextToken();
  1188.  
  1189.         if (rv != noValue) {
  1190.             /* attempt made to get a field on a non-object */
  1191.             return "\"" + lastField + "\" is not an object.";
  1192.         }
  1193.         lastField = idToken;
  1194.  
  1195.                 /* Rather than calling RemoteObject.getFieldValue(), we do this so that
  1196.                  * we can report an error if the field doesn't exist. */
  1197.                 {
  1198.                 RemoteField fields[] = ((RemoteObject)obj).getFields();
  1199.                     boolean found = false;
  1200.                     for (int i = fields.length-1; i >= 0; i--)
  1201.                         if (idToken.equals(fields[i].getName())) {
  1202.                             rv = ((RemoteObject)obj).getFieldValue(i);
  1203.                             found = true;
  1204.                             break;
  1205.                         }
  1206.  
  1207.                     if (!found) {
  1208.                         if (could_be_local_or_class)
  1209.                             /* expr is used here instead of idToken, because:
  1210.                              *   1. we know that we're processing the first token in the line,
  1211.                              *   2. if the user specified a class name with dots in it, 'idToken'
  1212.                              *      will only give the first token. */
  1213.                             return "\"" + expr + "\" is not a valid local, class name, or field of "
  1214.                                 + obj.description();
  1215.                         else
  1216.                             return "\"" + idToken + "\" is not a valid field of "
  1217.                                 + obj.description();
  1218.                     }
  1219.                 }
  1220.  
  1221.                   // don't give long error message next time round the loop
  1222.                 could_be_local_or_class = false;
  1223.  
  1224.         if (rv != null && rv.isObject()) {
  1225.             obj = rv;
  1226.             rv = noValue;
  1227.         }
  1228.         idToken =
  1229.             pieces.hasMoreTokens() ? pieces.nextToken() : null;
  1230.  
  1231.         } else if (idToken.equals("[")) {
  1232.         if (pieces.hasMoreTokens() == false) {
  1233.             return "\"" + expr +
  1234.                     "\" is not a valid expression.";
  1235.         }
  1236.         idToken = pieces.nextToken("]");
  1237.         try {
  1238.             int index = Integer.valueOf(idToken).intValue();
  1239.             rv = ((RemoteArray)obj).getElement(index);
  1240.         } catch (NumberFormatException e) {
  1241.             return "\"" + idToken +
  1242.                        "\" is not a valid decimal number.";
  1243.         } catch (ArrayIndexOutOfBoundsException e) {
  1244.             return idToken + " is out of bounds for " +
  1245.                 obj.description();
  1246.         }
  1247.         if (rv != null && rv.isObject()) {
  1248.             obj = rv;
  1249.             rv = noValue;
  1250.         }
  1251.         if (pieces.hasMoreTokens() == false ||
  1252.             (idToken = pieces.nextToken()).equals("]") == false) {
  1253.             return "\"" + expr +
  1254.                         "\" is not a valid expression.";
  1255.         }
  1256.         idToken = pieces.hasMoreTokens() ?
  1257.             pieces.nextToken(printDelimiters) : null;
  1258.  
  1259.         } else if (idToken.equals("(")) {
  1260.             return "print <method> not supported yet.";
  1261.         } else {
  1262.         /* Should never get here. */
  1263.         return "invalid expression";
  1264.         }
  1265.     }
  1266.  
  1267.     out.print(expr + " = ");
  1268.     if (rv != noValue) {
  1269.         out.println((rv == null) ? "null" : rv.description());
  1270.     } else if (dumpObject && obj instanceof RemoteObject) {
  1271.         out.println(obj.description() + " {");
  1272.  
  1273.         if (obj instanceof RemoteClass) {
  1274.         RemoteClass cls = (RemoteClass)obj;
  1275.  
  1276.         out.print("    superclass = ");
  1277.         RemoteClass superClass = cls.getSuperclass();
  1278.         out.println((superClass == null) ?
  1279.                    "null" : superClass.description());
  1280.  
  1281.         out.print("    loader = ");
  1282.         RemoteObject loader = cls.getClassLoader();
  1283.         out.println((loader == null) ?
  1284.                    "null" : loader.description());
  1285.  
  1286.         RemoteClass interfaces[] = cls.getInterfaces();
  1287.         if (interfaces != null && interfaces.length > 0) {
  1288.             out.println("    interfaces:");
  1289.             for (int i = 0; i < interfaces.length; i++) {
  1290.                 out.println("        " + interfaces[i]);
  1291.             }
  1292.         }
  1293.         }
  1294.  
  1295.         RemoteField fields[] = ((RemoteObject)obj).getFields();
  1296.         if (obj instanceof RemoteClass && fields.length > 0) {
  1297.         out.println();
  1298.         }
  1299.         for (int i = 0; i < fields.length; i++) {
  1300.         String name = fields[i].getTypedName();
  1301.         String modifiers = fields[i].getModifiers();
  1302.         out.print("    " + modifiers + name + " = ");
  1303.         RemoteValue v = ((RemoteObject)obj).getFieldValue(i);
  1304.         out.println((v == null) ? "null" : v.description());
  1305.         }
  1306.         out.println("}");
  1307.     } else {
  1308.             out.println(obj.toString());
  1309.         }
  1310.         return null;
  1311.     }
  1312.  
  1313.     void help() {
  1314.         out.println("** command list **");
  1315.         out.println("threads [threadgroup]     -- list threads");
  1316.         out.println("thread <thread id>        -- set default thread");
  1317.         out.println("suspend [thread id(s)]    -- suspend threads (default: all)");
  1318.         out.println("resume [thread id(s)]     -- resume threads (default: all)");
  1319.         out.println("where [thread id] | all   -- dump a thread's stack");
  1320.         out.println("wherei [thread id] | all  -- dump a thread's stack, with pc info");
  1321.         out.println("threadgroups              -- list threadgroups");
  1322.         out.println("threadgroup <name>        -- set current threadgroup\n");
  1323.         out.println("print <id> [id(s)]        -- print object or field");
  1324.         out.println("dump <id> [id(s)]         -- print all object information\n");
  1325.         out.println("locals                    -- print all local variables in current stack frame\n");
  1326.         out.println("classes                   -- list currently known classes");
  1327.         out.println("methods <class id>        -- list a class's methods\n");
  1328.         out.println("stop in <class id>.<method> -- set a breakpoint in a method");
  1329.         out.println("stop at <class id>:<line> -- set a breakpoint at a line");
  1330.         out.println("up [n frames]             -- move up a thread's stack");
  1331.         out.println("down [n frames]           -- move down a thread's stack");
  1332.         out.println("clear <class id>:<line>   -- clear a breakpoint");
  1333.         out.println("step                      -- execute current line");
  1334.         out.println("step up                   -- execute until the current method returns to its caller");  // SAS GVH step out
  1335.         out.println("stepi                     -- execute current instruction");
  1336.         out.println("next                      -- step one line (step OVER calls)");
  1337.         out.println("cont                      -- continue execution from breakpoint\n");
  1338.         out.println("catch <class id>          -- break for the specified exception");
  1339.         out.println("ignore <class id>         -- ignore when the specified exception\n");
  1340.         out.println("list [line number|method] -- print source code");
  1341.         out.println("use [source file path]    -- display or change the source path\n");
  1342.         out.println("memory                    -- report memory usage");
  1343.         out.println("gc                        -- free unused objects\n");
  1344.         out.println("load classname            -- load Java class to be debugged");
  1345.         out.println("run <class> [args]        -- start execution of a loaded Java class");
  1346. //        out.println("kill <thread(group)>      -- kill a thread or threadgroup\n");
  1347.         out.println("!!                        -- repeat last command");
  1348.         out.println("help (or ?)               -- list commands");
  1349.         out.println("exit (or quit)            -- exit debugger");
  1350.     }
  1351.  
  1352.     void executeCommand(StringTokenizer t) {
  1353.     String cmd = t.nextToken().toLowerCase();
  1354.  
  1355.     try {
  1356.         if (cmd.equals("print")) {
  1357.         print(t, false);
  1358.         } else if (cmd.equals("dump")) {
  1359.         print(t, true);
  1360.         } else if (cmd.equals("locals")) {
  1361.         locals();
  1362.         } else if (cmd.equals("classes")) {
  1363.         classes();
  1364.         } else if (cmd.equals("methods")) {
  1365.         methods(t);
  1366.         } else if (cmd.equals("threads")) {
  1367.         threads(t);
  1368.         } else if (cmd.equals("thread")) {
  1369.         thread(t);
  1370.         } else if (cmd.equals("suspend")) {
  1371.         suspend(t);
  1372.         } else if (cmd.equals("resume")) {
  1373.         resume(t);
  1374.         } else if (cmd.equals("threadgroups")) {
  1375.         threadGroups();
  1376.         } else if (cmd.equals("threadgroup")) {
  1377.         threadGroup(t);
  1378.         } else if (cmd.equals("catch")) {
  1379.         catchException(t);
  1380.         } else if (cmd.equals("ignore")) {
  1381.         ignoreException(t);
  1382.         } else if (cmd.equals("cont")) {
  1383.         cont();
  1384.         } else if (cmd.equals("step")) {
  1385.         step(t);
  1386.         } else if (cmd.equals("stepi")) {
  1387.         stepi();
  1388.         } else if (cmd.equals("next")) {
  1389.         next();
  1390.             } else if (cmd.equals("kill")) {
  1391.                 kill(t);
  1392.         } else if (cmd.equals("where")) {
  1393.         where(t, false);
  1394.         } else if (cmd.equals("wherei")) {
  1395.         where(t, true);
  1396.         } else if (cmd.equals("up")) {
  1397.         up(t);
  1398.         } else if (cmd.equals("down")) {
  1399.         down(t);
  1400.         } else if (cmd.equals("load")) {
  1401.         load(t);
  1402.         } else if (cmd.equals("run")) {
  1403.         run(t);
  1404.         } else if (cmd.equals("memory")) {
  1405.         memory();
  1406.             } else if (cmd.equals("gc")) {
  1407.                 gc();
  1408. //                   This cannot reasonably work
  1409. //        } else if (cmd.equals("trace") || cmd.equals("itrace")) {
  1410. //        trace(cmd, t);
  1411.         } else if (cmd.equals("stop")) {
  1412.         stop(t);
  1413.         } else if (cmd.equals("clear")) {
  1414.         clear(t);
  1415.         } else if (cmd.equals("list")) {
  1416.         list(t);
  1417.         } else if (cmd.equals("use")) {
  1418.         use(t);
  1419.         } else if (cmd.equals("help") || cmd.equals("?")) {
  1420.         help();
  1421.         } else if (cmd.equals("quit") || cmd.equals("exit")) {
  1422.         debugger.close();
  1423.         System.exit(0);
  1424.         } else {
  1425.         out.println("huh? Try help...");
  1426.         }
  1427.     } catch (Exception e) {
  1428.         out.println("Internal exception:");
  1429.         out.flush();
  1430.         e.printStackTrace();
  1431.     }
  1432.     }
  1433.  
  1434.     void readCommandFile(File f) {
  1435.     try {
  1436.         if (f.canRead()) {
  1437.         // Process initial commands.
  1438.         DataInputStream inFile = 
  1439.             new DataInputStream(new FileInputStream(f));
  1440.         String ln;
  1441.         while ((ln = inFile.readLine()) != null) {
  1442.             StringTokenizer t = new StringTokenizer(ln);
  1443.             if (t.hasMoreTokens()) {
  1444.             executeCommand(t);
  1445.             }
  1446.         }
  1447.         }
  1448.     } catch (IOException e) {}
  1449.     }
  1450.  
  1451.     public TTY(String host, String password, String javaArgs, String args, 
  1452.                PrintStream outStream, PrintStream consoleStream,
  1453.                boolean verbose) throws Exception {
  1454.         System.out.println("Initializing " + progname + "...");
  1455.     out = outStream;
  1456.     console = consoleStream;
  1457.         if (password == null) {
  1458.             debugger = new RemoteDebugger(javaArgs, this, verbose);
  1459.         } else {
  1460.             debugger = new RemoteDebugger(host, password, this, verbose);
  1461.         }
  1462.     DataInputStream in = new DataInputStream(System.in);
  1463.     String lastLine = null;
  1464.  
  1465.     if (args != null && args.length() > 0) {
  1466.         StringTokenizer t = new StringTokenizer(args);
  1467.         load(t);
  1468.         lastArgs = args;
  1469.     }
  1470.  
  1471.     Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
  1472.  
  1473.     // Try reading user's startup file.
  1474.     File f = new File(System.getProperty("user.home") + 
  1475.         System.getProperty("file.separator") + "jdb.ini");
  1476.         if (!f.canRead()) {
  1477.             // Try opening $HOME/jdb.ini
  1478.             f = new File(System.getProperty("user.home") + 
  1479.                          System.getProperty("file.separator") + ".jdbrc");
  1480.         }
  1481.         readCommandFile(f);
  1482.  
  1483.     // Try opening local jdb.ini
  1484.     f = new File(System.getProperty("user.dir") + 
  1485.         System.getProperty("file.separator") + "startup.jdb");
  1486.         readCommandFile(f);
  1487.  
  1488.     // Process interactive commands.
  1489.     while (true) {
  1490.             printPrompt();
  1491.         String ln = in.readLine();
  1492.         if (ln == null) {
  1493.         out.println("Input stream closed.");
  1494.         return;
  1495.         }
  1496.  
  1497.         if (ln.startsWith("!!") && lastLine != null) {
  1498.         ln = lastLine + ln.substring(2);
  1499.         out.println(ln);
  1500.         }
  1501.  
  1502.         StringTokenizer t = new StringTokenizer(ln);
  1503.         if (t.hasMoreTokens()) {
  1504.         lastLine = ln;
  1505.         executeCommand(t);
  1506.         }
  1507.     }
  1508.     }
  1509.  
  1510.     private static void usage() {
  1511.         String separator = System.getProperty("path.separator");
  1512.         System.out.println("Usage: " + progname + " <options> <classes>");
  1513.         System.out.println();
  1514.         System.out.println("where options include:");
  1515.         System.out.println("    -help             print out this message and exit");
  1516.         System.out.println("    -version          print out the build version and exit");
  1517.         System.out.println("    -host <hostname>  host machine of interpreter to attach to");
  1518.         System.out.println("    -password <psswd> password of interpreter to attach to (from -debug)");
  1519.         System.out.println("    -dbgtrace         print info for debugging " + progname);
  1520.         System.out.println();
  1521.         System.out.println("options forwarded to debuggee process:");
  1522.         System.out.println("    -v -verbose[:class|gc|jni]");
  1523.         System.out.println("                      turn on verbose mode");
  1524.         System.out.println("    -D<name>=<value>  set a system property");
  1525.         System.out.println("    -classpath <directories separated by \"" + 
  1526.                            separator + "\">");
  1527.         System.out.println("                      list directories in which to look for classes");
  1528.         System.out.println("    -X<option>        non-standard debuggee VM option");
  1529.         System.out.println();
  1530.         System.out.println("For command help type 'help' at " + progname + " prompt");
  1531.     }
  1532.  
  1533.     public static void main(String argv[]) {
  1534.     // Get host attribute, if any.
  1535.     String localhost;
  1536.     try {
  1537.         localhost = InetAddress.getLocalHost().getHostName();
  1538.     } catch (Exception ex) {
  1539.         localhost = null;
  1540.     }    
  1541.     if (localhost == null) {
  1542.         localhost = "localhost";
  1543.     }
  1544.     String host = null;
  1545.     String password = null;
  1546.     String classArgs = "";
  1547.     String javaArgs = "";
  1548.         boolean verbose = false;
  1549.     
  1550.     for (int i = 0; i < argv.length; i++) {
  1551.         String token = argv[i];
  1552.         if (token.equals("-dbgtrace")) {
  1553.         verbose = true;
  1554.         } else if (
  1555.                    // Standard VM options passed on
  1556.                    token.equals("-v") || token.startsWith("v:") ||  // -v[:...]
  1557.                    token.startsWith("-verbose") ||                  // -verbose[:...]
  1558.                 token.startsWith("-D") ||
  1559.                    // NonStandard options passed on
  1560.                    token.startsWith("-X") ||
  1561.                    // Old-style options (These should remain in place as long as
  1562.                    //  the standard VM accepts them)
  1563.            token.equals("-noasyncgc") || token.equals("-prof") ||
  1564.            token.equals("-verify") || token.equals("-noverify") ||
  1565.            token.equals("-verifyremote") ||
  1566.            token.equals("-verbosegc") ||
  1567.            token.startsWith("-ms") || token.startsWith("-mx") ||
  1568.            token.startsWith("-ss") || token.startsWith("-oss") ) {
  1569.  
  1570.         javaArgs += token + " ";
  1571.         } else if (token.equals("-classpath")) {
  1572.         if (i == (argv.length - 1)) {
  1573.             System.out.println("No classpath specified.");
  1574.             usage();
  1575.             System.exit(1);
  1576.         }
  1577.         javaArgs += token + " " + argv[++i] + " ";
  1578.         } else if (token.equals("-host")) {
  1579.         if (i == (argv.length - 1)) {
  1580.             System.out.println("No host specified.");
  1581.             usage();
  1582.             System.exit(1);
  1583.         }
  1584.         host = argv[++i];
  1585.         } else if (token.equals("-password")) {
  1586.         if (i == (argv.length - 1)) {
  1587.             System.out.println("No password specified.");
  1588.             usage();
  1589.             System.exit(1);
  1590.         }
  1591.         password = argv[++i];
  1592.         } else if (token.equals("-help")) {
  1593.         usage();
  1594.         System.exit(0);
  1595.         } else if (token.equals("-version")) {
  1596.         System.out.println(progname + " version " + version);
  1597.         System.exit(0);
  1598.         } else if (token.startsWith("-")) {
  1599.         System.out.println("invalid option: " + token);
  1600.         usage();
  1601.         System.exit(1);
  1602.         } else {
  1603.         classArgs += token + " ";
  1604.         }
  1605.     }
  1606.     if (host != null && password == null) {
  1607.         System.out.println("A debug password must be specified for " +
  1608.                    "remote debugging.");
  1609.         System.exit(1);
  1610.     }
  1611.     if (host == null) {
  1612.         host = localhost;
  1613.     }
  1614.  
  1615.     try {
  1616.         if (!host.equals(localhost) && password.length() == 0) {
  1617.         System.out.println(
  1618.             "No password supplied for accessing remote " +
  1619.             "Java interpreter.");
  1620.         System.out.println(
  1621.             "The password is reported by the remote interpreter" +
  1622.             "when it is started.");
  1623.                 System.exit(1);
  1624.             }
  1625.             new TTY(host, password, javaArgs, classArgs, 
  1626.                     System.out, System.out, verbose);
  1627.     } catch(SocketException se) {
  1628.         System.out.println("Failed accessing debugging session on " +
  1629.                    host + ": invalid password.");
  1630.     } catch(NumberFormatException ne) {
  1631.         System.out.println("Failed accessing debugging session on " +
  1632.                    host + ": invalid password.");
  1633.     } catch(Exception e) {        
  1634.         System.out.print("Internal exception:  ");
  1635.         System.out.flush();
  1636.         e.printStackTrace();
  1637.     }
  1638.     }
  1639. }
  1640.