home *** CD-ROM | disk | FTP | other *** search
/ IRIX 6.5 Applications 1999 November / SGI IRIX 6.5 Applications 1999 November.iso / dev / java_dev.idb / usr / java / src / sun / tools / ttydebug / TTY.java.z / TTY.java
Encoding:
Java Source  |  1998-07-14  |  53.5 KB  |  1,742 lines

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