home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / TTY.java < prev    next >
Text File  |  1997-10-01  |  52KB  |  1,605 lines

  1. /*
  2.  * @(#)TTY.java    1.74 97/08/04
  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 = "97/08/04";
  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 quitEvent() throws Exception {
  115.         String msg = null;
  116.         if (lastArgs != null) {
  117.             StringTokenizer t = new StringTokenizer(lastArgs);
  118.             if (t.hasMoreTokens()) {
  119.                 msg = new String("\n" + t.nextToken() + " exited");
  120.             }
  121.         }
  122.         if (msg == null) {
  123.             msg = new String("\nThe application exited");
  124.         }
  125.         out.println(msg);
  126.         currentThread = null;
  127.         System.exit(0);
  128.     }
  129.  
  130.     void classes() throws Exception {
  131.     RemoteClass list[] = debugger.listClasses();
  132.  
  133.     out.println("** classes list **");
  134.     for (int i = 0 ; i < list.length ; i++) {
  135.         out.println(list[i].description());
  136.     }
  137.     }
  138.  
  139.     void methods(StringTokenizer t) throws Exception {
  140.     if (!t.hasMoreTokens()) {
  141.         out.println("No class specified.");
  142.         return;
  143.     }
  144.  
  145.     String idClass = t.nextToken();
  146.     try {
  147.         RemoteClass cls = getClassFromToken(idClass);
  148.  
  149.         RemoteField methods[] = cls.getMethods();
  150.         for (int i = 0; i < methods.length; i++) {
  151.         out.println(methods[i].getTypedName());
  152.         }
  153.     } catch (IllegalArgumentException e) {
  154.         out.println("\"" + idClass +
  155.                    "\" is not a valid id or class name.");
  156.     }
  157.     }
  158.  
  159.     int printThreadGroup(RemoteThreadGroup tg, int iThread) throws Exception {
  160.     out.println("Group " + tg.getName() + ":");
  161.     RemoteThread tlist[] = tg.listThreads(false);
  162.  
  163.     int maxId = 0;
  164.     int maxName = 0;
  165.     for (int i = 0 ; i < tlist.length ; i++) {
  166.         int len = tlist[i].description().length();
  167.         if (len > maxId)
  168.         maxId = len;
  169.         String name = tlist[i].getName();
  170.         int iDot = name.lastIndexOf('.');
  171.         if (iDot >= 0 && name.length() > iDot) {
  172.         name = name.substring(iDot + 1);
  173.         }
  174.         if (name.length() > maxName)
  175.         maxName = name.length();
  176.     }
  177.  
  178.     for (int i = 0 ; i < tlist.length ; i++) {
  179.         char buf[] = new char[80];
  180.         for (int j = 0; j < 79; j++) {
  181.         buf[j] = ' ';
  182.         }
  183.         buf[79] = '\0';
  184.         StringBuffer sbOut = new StringBuffer();
  185.         sbOut.append(buf);
  186.  
  187.         sbOut.insert(((i + iThread + 1) < 10) ? 1 : 0, (i + iThread + 1));
  188.         sbOut.insert(2, ".");
  189.         int iBuf = 4;
  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.      if (!t.hasMoreTokens()) {
  518.         String exceptionList[] = debugger.getExceptionCatchList();
  519.         for (int i = 0; i < exceptionList.length; i++) {
  520.         out.print("  " + exceptionList[i]);
  521.         if ((i & 4) == 3 || (i == exceptionList.length - 1)) {
  522.             out.println();
  523.         }
  524.         }
  525.     } else {
  526.         String idClass = t.nextToken();
  527.         try {
  528.         RemoteClass cls = getClassFromToken(idClass);
  529.         cls.ignoreExceptions();
  530.         } catch (Exception e) {
  531.         out.println("Invalid exception class name: " + idClass);
  532.         }
  533.     }
  534.     }
  535.     
  536.     void up(StringTokenizer t) throws Exception {
  537.     if (currentThread == null) {
  538.         out.println("Current thread not set.");
  539.         return;
  540.     }
  541.  
  542.     int nLevels = 1;
  543.     if (t.hasMoreTokens()) {
  544.         String idToken = t.nextToken();
  545.         int n;
  546.         try {
  547.         n = Integer.valueOf(idToken).intValue();
  548.         } catch (NumberFormatException e) {
  549.         n = 0;
  550.         }
  551.         if (n == 0) {
  552.         out.println("Usage: up [n frames]");
  553.         return;
  554.         }
  555.         nLevels = n;
  556.     }
  557.  
  558.     try {
  559.         currentThread.up(nLevels);
  560.     } catch (IllegalAccessError e) {
  561.         out.println("Thread isn't suspended.");
  562.     } catch (ArrayIndexOutOfBoundsException e) {
  563.         out.println("End of stack.");
  564.     }
  565.     }
  566.  
  567.     void down(StringTokenizer t) throws Exception {
  568.     if (currentThread == null) {
  569.         out.println("Current thread not set.");
  570.         return;
  571.     }
  572.  
  573.     int nLevels = 1;
  574.     if (t.hasMoreTokens()) {
  575.         String idToken = t.nextToken();
  576.         int n;
  577.         try {
  578.         n = Integer.valueOf(idToken).intValue();
  579.         } catch (NumberFormatException e) {
  580.         n = 0;
  581.         }
  582.         if (n == 0) {
  583.         out.println("usage: down [n frames]");
  584.         return;
  585.         }
  586.         nLevels = n;
  587.     }
  588.  
  589.     try {
  590.         currentThread.down(nLevels);
  591.     } catch (IllegalAccessError e) {
  592.         out.println("Thread isn't suspended.");
  593.     } catch (ArrayIndexOutOfBoundsException e) {
  594.         out.println("End of stack.");
  595.     }
  596.     }
  597.  
  598.     void dumpStack(RemoteThread thread, boolean showPC) throws Exception {
  599.     RemoteStackFrame[] stack = thread.dumpStack();
  600.     if (stack.length == 0) {
  601.         out.println("Thread is not running (no stack).");
  602.     } else {
  603.         int nFrames = stack.length;
  604.         for (int i = thread.getCurrentFrameIndex(); i < nFrames; i++) {
  605.         out.print("  [" + (i + 1) + "] ");
  606.         out.print(stack[i].toString());
  607.         if (showPC) {
  608.             out.print(", pc = " + stack[i].getPC());
  609.         }
  610.         out.println();
  611.         }
  612.     }
  613.     }
  614.  
  615.     void where(StringTokenizer t, boolean showPC) throws Exception {
  616.     if (!t.hasMoreTokens()) {
  617.         if (currentThread == null) {
  618.         out.println("No thread specified.");
  619.         return;
  620.         }
  621.         dumpStack(currentThread, showPC);
  622.     } else {
  623.         String token = t.nextToken();
  624.         if (token.toLowerCase().equals("all")) {
  625.         setDefaultThreadGroup();
  626.         RemoteThread list[] = currentThreadGroup.listThreads(true);
  627.         for (int i = 0; i < list.length; i++) {
  628.             out.println(list[i].getName() + ": ");
  629.             dumpStack(list[i], showPC);
  630.         }
  631.         } else {
  632.         int threadId = parseThreadId(token);
  633.         if (threadId == 0) {
  634.             return;
  635.         }
  636.         dumpStack(indexToThread(threadId), showPC);
  637.         }
  638.     }
  639.     }
  640.  
  641.     void trace(String cmd, StringTokenizer t) throws Exception {
  642.     if (!t.hasMoreTokens()) {
  643.         out.println("(i)trace < \"on\" | \"off\" >");
  644.         return;
  645.     }
  646.     
  647.     String v = t.nextToken();
  648.     boolean traceOn;
  649.     if (v.equals("on")) {
  650.         traceOn = true;
  651.     } else if (v.equals("off")) {
  652.         traceOn = false;
  653.     } else {
  654.         out.println("(i)trace < \"on\" | \"off\" >");
  655.         return;
  656.     }
  657.  
  658.     if (cmd.equals("trace")) {
  659.         debugger.trace(traceOn);
  660.     } else {
  661.         debugger.itrace(traceOn);
  662.     }
  663.     }
  664.  
  665.     void memory() throws Exception {
  666.     out.println("Free: " + debugger.freeMemory() + ", total: " +
  667.                debugger.totalMemory());
  668.     }
  669.  
  670.     void gc() throws Exception {
  671.         RemoteObject[] save_list = new RemoteObject[2];
  672.         save_list[0] = currentThread;
  673.         save_list[1] = currentThreadGroup;
  674.         debugger.gc(save_list);
  675.     }
  676.  
  677.     private RemoteClass getClassFromToken(String idToken) throws Exception {
  678.     RemoteObject obj;
  679.     if (idToken.startsWith("0x") ||
  680.         Character.isDigit(idToken.charAt(0))) {
  681.         /* It's an object id. */
  682.         int id;
  683.         try {
  684.         id = RemoteObject.fromHex(idToken);
  685.         } catch (NumberFormatException e) {
  686.         id = 0;
  687.         }
  688.         if (id == 0 || (obj = debugger.get(new Integer(id))) == null) {
  689.         throw new IllegalArgumentException();
  690.         } else if (!(obj instanceof RemoteClass)) {
  691.         throw new IllegalArgumentException();
  692.         }
  693.     } else {
  694.         /* It's a class */
  695.         obj = debugger.findClass(idToken);
  696.         if (obj == null) {
  697.         throw new IllegalArgumentException();
  698.         }
  699.     }
  700.     return (RemoteClass)obj;
  701.     }
  702.  
  703.     void listBreakpoints() throws Exception {
  704.         String bkptList[] = debugger.listBreakpoints();
  705.     if (bkptList.length > 0) {
  706.             out.println("Current breakpoints set:");
  707.             for(int i = 0; i < bkptList.length; i++) {
  708.                 out.println("\t" + bkptList[i]);
  709.             }
  710.     } else {
  711.         out.println("No breakpoints set.");
  712.     }
  713.     }
  714.  
  715.     void stop(StringTokenizer t) throws Exception {
  716.     if (!t.hasMoreTokens()) {
  717.         listBreakpoints();
  718.         return;
  719.     }
  720.     
  721.     String idClass = null;
  722.     try {
  723.         String modifier = t.nextToken();
  724.         boolean stopAt;
  725.         if (modifier.equals("at")) {
  726.         stopAt = true;
  727.         } else if (modifier.equals("in")) {
  728.         stopAt = false;
  729.         } else {
  730.         out.println("Usage: stop at <class>:<line_number> or");
  731.         out.println("       stop in <class>.<method_name>");
  732.         return;
  733.         }
  734.  
  735.         if (modifier.equals("at")) {
  736.         idClass = t.nextToken(": \t\n\r");
  737.         RemoteClass cls = getClassFromToken(idClass);
  738.  
  739.         String idLine = t.nextToken();
  740.         int lineno = Integer.valueOf(idLine).intValue();
  741.  
  742.         String err = cls.setBreakpointLine(lineno);
  743.         if (err.length() > 0) {
  744.             out.println(err);
  745.         } else {
  746.             out.println("Breakpoint set at " + cls.getName() +
  747.                        ":" + lineno);
  748.         }
  749.         } else {
  750.         idClass = t.nextToken(": \t\n\r");
  751.                 RemoteClass cls = null;
  752.                 String idMethod = null;
  753.  
  754.                 try {
  755.                     cls = getClassFromToken(idClass);
  756.                 } catch (IllegalArgumentException e) {
  757.                     // Try stripping method from class.method token.
  758.                     int idot = idClass.lastIndexOf(".");
  759.                     if (idot == -1) {
  760.                         out.println("\"" + idClass +
  761.                             "\" is not a valid id or class name.");
  762.                         return;
  763.                     }
  764.                     idMethod = idClass.substring(idot + 1);
  765.                     idClass = idClass.substring(0, idot);
  766.                     cls = getClassFromToken(idClass);
  767.                 }
  768.  
  769.                 if (idMethod == null) {
  770.                     idMethod = t.nextToken();
  771.                 }
  772.                 RemoteField method;
  773.                 try {
  774.                     method = cls.getMethod(idMethod);
  775.                 } catch (NoSuchMethodException nsme) {
  776.             out.println("Class " + cls.getName() +
  777.                        " doesn't have a method " + idMethod);
  778.             return;
  779.         }
  780.         String err = cls.setBreakpointMethod(method);
  781.         if (err.length() > 0) {
  782.             out.println(err);
  783.         } else {
  784.             out.println("Breakpoint set in " + cls.getName() +
  785.                        "." + idMethod);
  786.         }
  787.         }
  788.     } catch (NoSuchElementException e) {
  789.         out.println("Usage: stop at <class>:<line_number> or");
  790.         out.println("       stop in <class>.<method_name>");
  791.     } catch (NumberFormatException e) {
  792.         out.println("Invalid line number.");
  793.     } catch (IllegalArgumentException e) {
  794.         out.println("\"" + idClass +
  795.                    "\" is not a valid id or class name.");
  796.     }
  797.     }
  798.  
  799.     void clear(StringTokenizer t) throws Exception {
  800.     if (!t.hasMoreTokens()) {
  801.         listBreakpoints();
  802.         return;
  803.     }
  804.     
  805.     String idClass = null;
  806.     String idMethod = null;
  807.     RemoteClass cls = null;
  808.     try {
  809.         idClass = t.nextToken(": \t\n\r");
  810.         try {
  811.             cls = getClassFromToken(idClass);
  812.             } catch (IllegalArgumentException e) {
  813.                 // Try stripping method from class.method token.
  814.                 int idot = idClass.lastIndexOf(".");
  815.                 if (idot == -1) {
  816.                     out.println("\"" + idClass +
  817.                         "\" is not a valid id or class name.");
  818.                     return;
  819.                 }
  820.                 idMethod = idClass.substring(idot + 1);
  821.                 idClass = idClass.substring(0, idot);
  822.                 cls = getClassFromToken(idClass);
  823.                 RemoteField method;
  824.                 try {
  825.                     method = cls.getMethod(idMethod);
  826.                 } catch (NoSuchMethodException nsme) {
  827.             out.println("\"" + idMethod + 
  828.                 "\" is not a valid method name of class " +
  829.                 cls.getName());
  830.             return;
  831.         }
  832.         String err = cls.clearBreakpointMethod(method);
  833.             if (err.length() > 0) {
  834.             out.println(err);
  835.             } else {
  836.             out.println("Breakpoint cleared at " + 
  837.                 cls.getName() + "." + idMethod);
  838.         }
  839.         return;
  840.             }
  841.  
  842.         String idLine = t.nextToken();
  843.         int lineno = Integer.valueOf(idLine).intValue();
  844.  
  845.         String err = cls.clearBreakpointLine(lineno);
  846.         if (err.length() > 0) {
  847.         out.println(err);
  848.         } else {
  849.         out.println("Breakpoint cleared at " + cls.getName() +
  850.                    ": " + lineno);
  851.         }
  852.     } catch (NoSuchElementException e) {
  853.         out.println("Usage: clear <class>:<line_number>");
  854.         out.println("   or: clear <class>.<method>");
  855.     } catch (NumberFormatException e) {
  856.         out.println("Usage: clear <class>:<line_number>");
  857.         out.println("   or: clear <class>.<method>");
  858.     } catch (IllegalArgumentException e) {
  859.         out.println("\"" + idClass +
  860.                    "\" is not a valid id or class name.");
  861.     }
  862.     }
  863.  
  864.     void list(StringTokenizer t) throws Exception {
  865.     RemoteStackFrame frame = null;
  866.     if (currentThread == null) {
  867.         out.println("No thread specified.");
  868.         return;
  869.     }
  870.     try {
  871.         frame = currentThread.getCurrentFrame();
  872.     } catch (IllegalAccessError e) {
  873.         out.println("Current thread isn't suspended.");
  874.         return;
  875.     } catch (ArrayIndexOutOfBoundsException e) {
  876.         out.println("Thread is not running (no stack).");
  877.         return;
  878.     }
  879.     
  880.     int lineno;
  881.     if (t.hasMoreTokens()) {
  882.         String id = t.nextToken();
  883.  
  884.             // See if token is a line number.
  885.             try {
  886.                 lineno = Integer.valueOf(id).intValue();
  887.             } catch (NumberFormatException nfe) {
  888.                 // It isn't -- see if it's a method name.
  889.                 try {
  890.                     lineno = frame.getRemoteClass().getMethodLineNumber(id);
  891.                 } catch (NoSuchMethodException iobe) {
  892.                     out.println(id + " is not a valid line number or " +
  893.                                 "method name for class " + 
  894.                                 frame.getRemoteClass().getName());
  895.                     return;
  896.                 } catch (NoSuchLineNumberException nse) {
  897.                     out.println("Line number information not found in " +
  898.                                 frame.getRemoteClass().getName());
  899.                     return;
  900.                 }
  901.             }
  902.     } else {
  903.         lineno = frame.getLineNumber();
  904.     }
  905.     int startLine = (lineno > 4) ? lineno - 4 : 1;
  906.     int endLine = startLine + 9;
  907.  
  908.     InputStream rawSourceFile = frame.getRemoteClass().getSourceFile();
  909.     if (rawSourceFile == null) {
  910.         out.println("Unable to find " + 
  911.                         frame.getRemoteClass().getSourceFileName());
  912.         return;
  913.     }
  914.  
  915.     DataInputStream sourceFile = new DataInputStream(rawSourceFile);
  916.     String sourceLine = null;
  917.  
  918.     /* Skip through file to desired window. */
  919.     for (int i = 1; i <= startLine; i++) {
  920.         sourceLine = sourceFile.readLine();
  921.     }
  922.     if (sourceLine == null) {
  923.         out.println(new Integer(lineno).toString() +
  924.                         " is an invalid line number for the file " +
  925.                         frame.getRemoteClass().getSourceFileName());
  926.     }
  927.  
  928.     /* Print lines */
  929.     for (int i = startLine; i < endLine && sourceLine != null; i++) {
  930.         out.print(new Integer(i).toString() + "\t" +
  931.                  ((i == lineno) ? "=> " : "   "));
  932.         out.println(sourceLine);
  933.         sourceLine = sourceFile.readLine();
  934.     }
  935.         
  936.     }
  937.  
  938.     /* Get or set the source file path list. */
  939.     void use(StringTokenizer t) throws Exception {
  940.     if (!t.hasMoreTokens()) {
  941.         out.println(debugger.getSourcePath());
  942.     } else {
  943.         debugger.setSourcePath(t.nextToken());
  944.     }
  945.     }
  946.  
  947.     /* Print a stack variable */
  948.     private void printVar(RemoteStackVariable var) {
  949.         out.print("  " + var.getName());
  950.         if (var.inScope()) {
  951.             RemoteValue val = var.getValue();
  952.             out.println(" = " + (val == null? "null" : val.toString()) );
  953.         } else {
  954.             out.println(" is not in scope");
  955.         }
  956.     }
  957.  
  958.     /* Print all local variables in current stack frame. */
  959.     void locals() throws Exception {
  960.     if (currentThread == null) {
  961.         out.println("No default thread specified: " +
  962.                    "use the \"thread\" command first.");
  963.         return;
  964.     }
  965.         if (!currentThread.isSuspended()) {
  966.             out.println("Thread isn't suspended.");
  967.             return;
  968.         }
  969.     RemoteStackVariable rsv[] = currentThread.getStackVariables();
  970.     if (rsv == null || rsv.length == 0) {
  971.         out.println("No local variables: try compiling with -g");
  972.         return;
  973.     }
  974.     out.println("Method arguments:");
  975.     for (int i = 0; i < rsv.length; i++) {
  976.         if (rsv[i].methodArgument()) {
  977.         printVar(rsv[i]);
  978.         }
  979.     }
  980.     out.println("Local variables:");
  981.     for (int i = 0; i < rsv.length; i++) {
  982.         if (!rsv[i].methodArgument()) {
  983.         printVar(rsv[i]);
  984.             }
  985.     }
  986.     return;
  987.     }
  988.  
  989.     static final String printDelimiters = ".[(";
  990.  
  991.     /* Print a specified reference. 
  992.      * New print() implementation courtesy of S. Blackheath of IBM
  993.      */
  994.     void print(StringTokenizer t, boolean dumpObject) throws Exception {
  995.     if (!t.hasMoreTokens()) {
  996.         out.println("No objects specified.");
  997.             return;
  998.     }
  999.  
  1000.     int id;
  1001.     RemoteValue obj = null;
  1002.  
  1003.         while (t.hasMoreTokens()) {
  1004.         String expr = t.nextToken();
  1005.         StringTokenizer pieces =
  1006.            new StringTokenizer(expr, printDelimiters, true);
  1007.  
  1008.         String idToken = pieces.nextToken(); // There will be at least one.
  1009.         if (idToken.startsWith("t@")) {
  1010.             /* It's a thread */
  1011.             setDefaultThreadGroup();
  1012.             RemoteThread tlist[] = currentThreadGroup.listThreads(true);
  1013.             try {
  1014.                 id = Integer.valueOf(idToken.substring(2)).intValue();
  1015.             } catch (NumberFormatException e) {
  1016.             id = 0;
  1017.             }
  1018.             if (id <= 0 || id > tlist.length) {
  1019.                 out.println("\"" + idToken +
  1020.                    "\" is not a valid thread id.");
  1021.                     continue;
  1022.             }
  1023.             obj = tlist[id - 1];
  1024.  
  1025.         } else if (idToken.startsWith("$s")) {
  1026.             int slotnum;
  1027.             try {
  1028.                 slotnum = Integer.valueOf(idToken.substring(2)).intValue();
  1029.             } catch (NumberFormatException e) {
  1030.  
  1031.                 out.println("\"" + idToken + "\" is not a valid slot.");
  1032.                     continue;
  1033.             }
  1034.             if (currentThread != null) {
  1035.                 RemoteStackVariable rsv[] = currentThread.getStackVariables();
  1036.             if (rsv == null || slotnum >= rsv.length) {
  1037.                 out.println("\"" + idToken + "\" is not a valid slot.");
  1038.                         continue;
  1039.             }
  1040.             obj = rsv[slotnum].getValue();
  1041.             }
  1042.         
  1043.         } else if (idToken.startsWith("0x") ||
  1044.                Character.isDigit(idToken.charAt(0))) {
  1045.             /* It's an object id. */
  1046.             try {
  1047.                 id = RemoteObject.fromHex(idToken);
  1048.             } catch (NumberFormatException e) {
  1049.                 id = 0;
  1050.             }
  1051.                 if (id == 0 || (obj = debugger.get(new Integer(id))) == null) {
  1052.                 out.println("\"" + idToken + "\" is not a valid id.");
  1053.                     continue;
  1054.             }
  1055.         } else {
  1056.             /* See if it's a local stack variable */
  1057.             if (currentThread != null) {
  1058.             RemoteStackVariable rsv = currentThread.getStackVariable(idToken);
  1059.             if (rsv != null && !rsv.inScope()) {
  1060.                 out.println(idToken + " is not in scope.");
  1061.                         continue;
  1062.             }
  1063.             obj = (rsv == null) ? null : rsv.getValue();
  1064.             }
  1065.             if (obj == null) {
  1066.                     String error = null;
  1067.                     /* See if it's an instance variable */
  1068.                     String instanceStr = idToken;
  1069.                     try {
  1070.                         instanceStr = instanceStr + pieces.nextToken("");
  1071.                     }
  1072.                     catch (NoSuchElementException e) {}
  1073.  
  1074.                     RemoteStackVariable rsv = null;
  1075.                     if (currentThread != null)
  1076.                         rsv = currentThread.getStackVariable("this");
  1077.                     if (rsv != null && rsv.inScope()) {
  1078.                         obj = rsv.getValue();
  1079.  
  1080.                         error = printModifiers(expr,
  1081.                               new StringTokenizer("."+instanceStr, printDelimiters, true),
  1082.                               dumpObject, obj, true);
  1083.                         if (error == null)
  1084.                             continue;
  1085.                     }
  1086.  
  1087.                     // If the above failed, then re-construct the same
  1088.                     // string tokenizer we had before.
  1089.                     pieces = new StringTokenizer(instanceStr, printDelimiters, true);
  1090.                     idToken = pieces.nextToken();
  1091.  
  1092.             /* Try interpreting it as a class */
  1093.                     while (true) {
  1094.                 obj = debugger.findClass(idToken);
  1095.                 if (obj != null)             // break if this is a valid class name
  1096.                             break;
  1097.                         if (!pieces.hasMoreTokens()) // break if we run out of input
  1098.                             break;
  1099.                         String dot = pieces.nextToken();
  1100.                         if (!dot.equals("."))        // break if this token is not a dot
  1101.                             break;
  1102.                         if (!pieces.hasMoreTokens())
  1103.                             break;
  1104.                         // If it is a dot, then add the next token, and loop
  1105.                         idToken = idToken + dot + pieces.nextToken();
  1106.                     }
  1107.                     if (obj == null) {
  1108.                         if (error == null)
  1109.                     error = "\"" + expr + "\" is not a " + "valid local or class name.";
  1110.                     }
  1111.                     else {
  1112.                         String error2 = printModifiers(expr, pieces, dumpObject, obj, false);
  1113.                         if (error2 == null)
  1114.                             continue;
  1115.                         if (error == null)
  1116.                             error = error2;
  1117.                     }
  1118.                     out.println(error);
  1119.                     continue;
  1120.             }
  1121.         }
  1122.             String error = printModifiers(expr, pieces, dumpObject, obj, false);
  1123.             if (error != null)
  1124.                 out.println(error);
  1125.         }
  1126.     }
  1127.  
  1128.     String printModifiers(String expr, StringTokenizer pieces, boolean dumpObject, RemoteValue obj,
  1129.         boolean could_be_local_or_class)
  1130.         throws Exception
  1131.     {
  1132.         RemoteInt noValue = new RemoteInt(-1);
  1133.         RemoteValue rv = noValue;
  1134.  
  1135.         // If the object is null, or a non-object type (integer, array, etc...)
  1136.         // then the value must be in rv.
  1137.         if (obj == null)
  1138.             rv = null;
  1139.         else
  1140.         if (!obj.isObject())
  1141.             rv = obj;
  1142.  
  1143.     String lastField = "";
  1144.     String idToken = pieces.hasMoreTokens() ? pieces.nextToken() : null;
  1145.     while (idToken != null) {
  1146.  
  1147.         if (idToken.equals(".")) {
  1148.             if (pieces.hasMoreTokens() == false) {
  1149.             return "\"" + expr + "\" is not a valid expression.";
  1150.         }
  1151.         idToken = pieces.nextToken();
  1152.  
  1153.         if (rv != noValue) {
  1154.             /* attempt made to get a field on a non-object */
  1155.             return "\"" + lastField + "\" is not an object.";
  1156.         }
  1157.         lastField = idToken;
  1158.  
  1159.                 /* Rather than calling RemoteObject.getFieldValue(), we do this so that
  1160.                  * we can report an error if the field doesn't exist. */
  1161.                 {
  1162.                 RemoteField fields[] = ((RemoteObject)obj).getFields();
  1163.                     boolean found = false;
  1164.                     for (int i = fields.length-1; i >= 0; i--)
  1165.                         if (idToken.equals(fields[i].getName())) {
  1166.                             rv = ((RemoteObject)obj).getFieldValue(i);
  1167.                             found = true;
  1168.                             break;
  1169.                         }
  1170.  
  1171.                     if (!found) {
  1172.                         if (could_be_local_or_class)
  1173.                             /* expr is used here instead of idToken, because:
  1174.                              *   1. we know that we're processing the first token in the line,
  1175.                              *   2. if the user specified a class name with dots in it, 'idToken'
  1176.                              *      will only give the first token. */
  1177.                             return "\"" + expr + "\" is not a valid local, class name, or field of "
  1178.                                 + obj.description();
  1179.                         else
  1180.                             return "\"" + idToken + "\" is not a valid field of "
  1181.                                 + obj.description();
  1182.                     }
  1183.                 }
  1184.  
  1185.                   // don't give long error message next time round the loop
  1186.                 could_be_local_or_class = false;
  1187.  
  1188.         if (rv != null && rv.isObject()) {
  1189.             obj = rv;
  1190.             rv = noValue;
  1191.         }
  1192.         idToken =
  1193.             pieces.hasMoreTokens() ? pieces.nextToken() : null;
  1194.  
  1195.         } else if (idToken.equals("[")) {
  1196.         if (pieces.hasMoreTokens() == false) {
  1197.             return "\"" + expr +
  1198.                     "\" is not a valid expression.";
  1199.         }
  1200.         idToken = pieces.nextToken("]");
  1201.         try {
  1202.             int index = Integer.valueOf(idToken).intValue();
  1203.             rv = ((RemoteArray)obj).getElement(index);
  1204.         } catch (NumberFormatException e) {
  1205.             return "\"" + idToken +
  1206.                        "\" is not a valid decimal number.";
  1207.         } catch (ArrayIndexOutOfBoundsException e) {
  1208.             return idToken + " is out of bounds for " +
  1209.                 obj.description();
  1210.         }
  1211.         if (rv != null && rv.isObject()) {
  1212.             obj = rv;
  1213.             rv = noValue;
  1214.         }
  1215.         if (pieces.hasMoreTokens() == false ||
  1216.             (idToken = pieces.nextToken()).equals("]") == false) {
  1217.             return "\"" + expr +
  1218.                         "\" is not a valid expression.";
  1219.         }
  1220.         idToken = pieces.hasMoreTokens() ?
  1221.             pieces.nextToken(printDelimiters) : null;
  1222.  
  1223.         } else if (idToken.equals("(")) {
  1224.             return "print <method> not supported yet.";
  1225.         } else {
  1226.         /* Should never get here. */
  1227.         return "invalid expression";
  1228.         }
  1229.     }
  1230.  
  1231.     out.print(expr + " = ");
  1232.     if (rv != noValue) {
  1233.         out.println((rv == null) ? "null" : rv.description());
  1234.     } else if (dumpObject && obj instanceof RemoteObject) {
  1235.         out.println(obj.description() + " {");
  1236.  
  1237.         if (obj instanceof RemoteClass) {
  1238.         RemoteClass cls = (RemoteClass)obj;
  1239.  
  1240.         out.print("    superclass = ");
  1241.         RemoteClass superClass = cls.getSuperclass();
  1242.         out.println((superClass == null) ?
  1243.                    "null" : superClass.description());
  1244.  
  1245.         out.print("    loader = ");
  1246.         RemoteObject loader = cls.getClassLoader();
  1247.         out.println((loader == null) ?
  1248.                    "null" : loader.description());
  1249.  
  1250.         RemoteClass interfaces[] = cls.getInterfaces();
  1251.         if (interfaces != null && interfaces.length > 0) {
  1252.             out.println("    interfaces:");
  1253.             for (int i = 0; i < interfaces.length; i++) {
  1254.                 out.println("        " + interfaces[i]);
  1255.             }
  1256.         }
  1257.         }
  1258.  
  1259.         RemoteField fields[] = ((RemoteObject)obj).getFields();
  1260.         if (obj instanceof RemoteClass && fields.length > 0) {
  1261.         out.println();
  1262.         }
  1263.         for (int i = 0; i < fields.length; i++) {
  1264.         String name = fields[i].getTypedName();
  1265.         String modifiers = fields[i].getModifiers();
  1266.         out.print("    " + modifiers + name + " = ");
  1267.         RemoteValue v = ((RemoteObject)obj).getFieldValue(i);
  1268.         out.println((v == null) ? "null" : v.description());
  1269.         }
  1270.         out.println("}");
  1271.     } else {
  1272.             out.println(obj.toString());
  1273.         }
  1274.         return null;
  1275.     }
  1276.  
  1277.     void help() {
  1278.         out.println("** command list **");
  1279.         out.println("threads [threadgroup]     -- list threads");
  1280.         out.println("thread <thread id>        -- set default thread");
  1281.         out.println("suspend [thread id(s)]    -- suspend threads (default: all)");
  1282.         out.println("resume [thread id(s)]     -- resume threads (default: all)");
  1283.         out.println("where [thread id] | all   -- dump a thread's stack");
  1284.         out.println("wherei [thread id] | all  -- dump a thread's stack, with pc info");
  1285.         out.println("threadgroups              -- list threadgroups");
  1286.         out.println("threadgroup <name>        -- set current threadgroup\n");
  1287.         out.println("print <id> [id(s)]        -- print object or field");
  1288.         out.println("dump <id> [id(s)]         -- print all object information\n");
  1289.         out.println("locals                    -- print all local variables in current stack frame\n");
  1290.         out.println("classes                   -- list currently known classes");
  1291.         out.println("methods <class id>        -- list a class's methods\n");
  1292.         out.println("stop in <class id>.<method> -- set a breakpoint in a method");
  1293.         out.println("stop at <class id>:<line> -- set a breakpoint at a line");
  1294.         out.println("up [n frames]             -- move up a thread's stack");
  1295.         out.println("down [n frames]           -- move down a thread's stack");
  1296.         out.println("clear <class id>:<line>   -- clear a breakpoint");
  1297.         out.println("step                      -- execute current line");
  1298.         out.println("step up                   -- execute until the current method returns to its caller");  // SAS GVH step out
  1299.         out.println("stepi                     -- execute current instruction");
  1300.         out.println("next                      -- step one line (step OVER calls)");
  1301.         out.println("cont                      -- continue execution from breakpoint\n");
  1302.         out.println("catch <class id>          -- break for the specified exception");
  1303.         out.println("ignore <class id>         -- ignore when the specified exception\n");
  1304.         out.println("list [line number|method] -- print source code");
  1305.         out.println("use [source file path]    -- display or change the source path\n");
  1306.         out.println("memory                    -- report memory usage");
  1307.         out.println("gc                        -- free unused objects\n");
  1308.         out.println("load classname            -- load Java class to be debugged");
  1309.         out.println("run <class> [args]        -- start execution of a loaded Java class");
  1310. //        out.println("kill <thread(group)>      -- kill a thread or threadgroup\n");
  1311.         out.println("!!                        -- repeat last command");
  1312.         out.println("help (or ?)               -- list commands");
  1313.         out.println("exit (or quit)            -- exit debugger");
  1314.     }
  1315.  
  1316.     void executeCommand(StringTokenizer t) {
  1317.     String cmd = t.nextToken().toLowerCase();
  1318.  
  1319.     try {
  1320.         if (cmd.equals("print")) {
  1321.         print(t, false);
  1322.         } else if (cmd.equals("dump")) {
  1323.         print(t, true);
  1324.         } else if (cmd.equals("locals")) {
  1325.         locals();
  1326.         } else if (cmd.equals("classes")) {
  1327.         classes();
  1328.         } else if (cmd.equals("methods")) {
  1329.         methods(t);
  1330.         } else if (cmd.equals("threads")) {
  1331.         threads(t);
  1332.         } else if (cmd.equals("thread")) {
  1333.         thread(t);
  1334.         } else if (cmd.equals("suspend")) {
  1335.         suspend(t);
  1336.         } else if (cmd.equals("resume")) {
  1337.         resume(t);
  1338.         } else if (cmd.equals("threadgroups")) {
  1339.         threadGroups();
  1340.         } else if (cmd.equals("threadgroup")) {
  1341.         threadGroup(t);
  1342.         } else if (cmd.equals("catch")) {
  1343.         catchException(t);
  1344.         } else if (cmd.equals("ignore")) {
  1345.         ignoreException(t);
  1346.         } else if (cmd.equals("cont")) {
  1347.         cont();
  1348.         } else if (cmd.equals("step")) {
  1349.         step(t);
  1350.         } else if (cmd.equals("stepi")) {
  1351.         stepi();
  1352.         } else if (cmd.equals("next")) {
  1353.         next();
  1354.             } else if (cmd.equals("kill")) {
  1355.                 kill(t);
  1356.         } else if (cmd.equals("where")) {
  1357.         where(t, false);
  1358.         } else if (cmd.equals("wherei")) {
  1359.         where(t, true);
  1360.         } else if (cmd.equals("up")) {
  1361.         up(t);
  1362.         } else if (cmd.equals("down")) {
  1363.         down(t);
  1364.         } else if (cmd.equals("load")) {
  1365.         load(t);
  1366.         } else if (cmd.equals("run")) {
  1367.         run(t);
  1368.         } else if (cmd.equals("memory")) {
  1369.         memory();
  1370.             } else if (cmd.equals("gc")) {
  1371.                 gc();
  1372. //                   This cannot reasonably work
  1373. //        } else if (cmd.equals("trace") || cmd.equals("itrace")) {
  1374. //        trace(cmd, t);
  1375.         } else if (cmd.equals("stop")) {
  1376.         stop(t);
  1377.         } else if (cmd.equals("clear")) {
  1378.         clear(t);
  1379.         } else if (cmd.equals("list")) {
  1380.         list(t);
  1381.         } else if (cmd.equals("use")) {
  1382.         use(t);
  1383.         } else if (cmd.equals("help") || cmd.equals("?")) {
  1384.         help();
  1385.         } else if (cmd.equals("quit") || cmd.equals("exit")) {
  1386.         debugger.close();
  1387.         System.exit(0);
  1388.         } else {
  1389.         out.println("huh? Try help...");
  1390.         }
  1391.     } catch (Exception e) {
  1392.         out.println("Internal exception:");
  1393.         out.flush();
  1394.         e.printStackTrace();
  1395.     }
  1396.     }
  1397.  
  1398.     void readCommandFile(File f) {
  1399.     try {
  1400.         if (f.canRead()) {
  1401.         // Process initial commands.
  1402.         DataInputStream inFile = 
  1403.             new DataInputStream(new FileInputStream(f));
  1404.         String ln;
  1405.         while ((ln = inFile.readLine()) != null) {
  1406.             StringTokenizer t = new StringTokenizer(ln);
  1407.             if (t.hasMoreTokens()) {
  1408.             executeCommand(t);
  1409.             }
  1410.         }
  1411.         }
  1412.     } catch (IOException e) {}
  1413.     }
  1414.  
  1415.     public TTY(String host, String password, String javaArgs, String args, 
  1416.                PrintStream outStream, PrintStream consoleStream,
  1417.                boolean verbose) throws Exception {
  1418.         System.out.println("Initializing " + progname + "...");
  1419.     out = outStream;
  1420.     console = consoleStream;
  1421.         if (password == null) {
  1422.             debugger = new RemoteDebugger(javaArgs, this, verbose);
  1423.         } else {
  1424.             debugger = new RemoteDebugger(host, password, this, verbose);
  1425.         }
  1426.     DataInputStream in = new DataInputStream(System.in);
  1427.     String lastLine = null;
  1428.  
  1429.     if (args != null && args.length() > 0) {
  1430.         StringTokenizer t = new StringTokenizer(args);
  1431.         load(t);
  1432.         lastArgs = args;
  1433.     }
  1434.  
  1435.     Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
  1436.  
  1437.     // Try reading user's startup file.
  1438.     File f = new File(System.getProperty("user.home") + 
  1439.         System.getProperty("file.separator") + "jdb.ini");
  1440.         if (!f.canRead()) {
  1441.             // Try opening $HOME/jdb.ini
  1442.             f = new File(System.getProperty("user.home") + 
  1443.                          System.getProperty("file.separator") + ".jdbrc");
  1444.         }
  1445.         readCommandFile(f);
  1446.  
  1447.     // Try opening local jdb.ini
  1448.     f = new File(System.getProperty("user.dir") + 
  1449.         System.getProperty("file.separator") + "startup.jdb");
  1450.         readCommandFile(f);
  1451.  
  1452.     // Process interactive commands.
  1453.     while (true) {
  1454.             printPrompt();
  1455.         String ln = in.readLine();
  1456.         if (ln == null) {
  1457.         out.println("Input stream closed.");
  1458.         return;
  1459.         }
  1460.  
  1461.         if (ln.startsWith("!!") && lastLine != null) {
  1462.         ln = lastLine + ln.substring(2);
  1463.         out.println(ln);
  1464.         }
  1465.  
  1466.         StringTokenizer t = new StringTokenizer(ln);
  1467.         if (t.hasMoreTokens()) {
  1468.         lastLine = ln;
  1469.         executeCommand(t);
  1470.         }
  1471.     }
  1472.     }
  1473.  
  1474.     private static void usage() {
  1475.         System.out.println("Usage: " + progname + " <options> <classes>");
  1476.         System.out.println();
  1477.         System.out.println("where options include:");
  1478.         System.out.println("    -help             print out this message and exit");
  1479.         System.out.println("    -version          print out the build version and exit");
  1480.         System.out.println("    -host <hostname>  host machine of interpreter to attach to");
  1481.         System.out.println("    -password <psswd> password of interpreter to attach to (from -debug)");
  1482.         System.out.println("options forwarded to debuggee process:");
  1483.         System.out.println("    -v -verbose       turn on verbose mode");
  1484.         System.out.println("    -debug            enable remote JAVA debugging");
  1485.         System.out.println("    -noasyncgc        don't allow asynchronous garbage collection");
  1486.         System.out.println("    -verbosegc        print a message when garbage collection occurs");
  1487.         System.out.println("    -noclassgc        disable class garbage collection");
  1488.         System.out.println("    -cs -checksource  check if source is newer when loading classes");
  1489.         System.out.println("    -ss<number>       set the maximum native stack size for any thread");
  1490.         System.out.println("    -oss<number>      set the maximum Java stack size for any thread");
  1491.         System.out.println("    -ms<number>       set the initial Java heap size");
  1492.         System.out.println("    -mx<number>       set the maximum Java heap size");
  1493.         System.out.println("    -D<name>=<value>  set a system property");
  1494.         System.out.println("    -classpath <directories separated by colons>");
  1495.         System.out.println("                      list directories in which to look for classes");
  1496.         System.out.println("    -prof[:<file>]    output profiling data to ./java.prof or ./<file>");
  1497.         System.out.println("    -verify           verify all classes when read in");
  1498.         System.out.println("    -verifyremote     verify classes read in over the network [default]");
  1499.         System.out.println("    -noverify         do not verify any class");
  1500.         System.out.println("    -dbgtrace         print info for debugging " + progname);
  1501.         System.out.println();
  1502.         System.out.println("For command help type 'help' at " + progname + " prompt");
  1503.     }
  1504.  
  1505.     public static void main(String argv[]) {
  1506.     // Get host attribute, if any.
  1507.     String localhost;
  1508.     try {
  1509.         localhost = InetAddress.getLocalHost().getHostName();
  1510.     } catch (Exception ex) {
  1511.         localhost = null;
  1512.     }    
  1513.     if (localhost == null) {
  1514.         localhost = "localhost";
  1515.     }
  1516.     String host = null;
  1517.     String password = null;
  1518.     String classArgs = "";
  1519.     String javaArgs = "";
  1520.         boolean verbose = false;
  1521.     
  1522.     for (int i = 0; i < argv.length; i++) {
  1523.         String token = argv[i];
  1524.         if (token.equals("-dbgtrace")) {
  1525.         verbose = true;
  1526.         } else if (token.equals("-cs") || token.equals("-checksource") ||
  1527.                token.equals("-noasyncgc") || token.equals("-prof") ||
  1528.                token.equals("-v") || token.equals("-verbose") ||
  1529.                token.equals("-verify") || token.equals("-noverify") ||
  1530.                token.equals("-verifyremote") ||
  1531.                token.equals("-verbosegc") ||
  1532.                token.startsWith("-ms") || token.startsWith("-mx") ||
  1533.                token.startsWith("-ss") || token.startsWith("-oss") ||
  1534.                token.startsWith("-D")) {
  1535.         javaArgs += token + " ";
  1536.         } else if (token.equals("-classpath")) {
  1537.         if (i == (argv.length - 1)) {
  1538.             System.out.println("No classpath specified.");
  1539.             usage();
  1540.             System.exit(1);
  1541.         }
  1542.         javaArgs += token + " " + argv[++i] + " ";
  1543.         } else if (token.equals("-host")) {
  1544.         if (i == (argv.length - 1)) {
  1545.             System.out.println("No host specified.");
  1546.             usage();
  1547.             System.exit(1);
  1548.         }
  1549.         host = argv[++i];
  1550.         } else if (token.equals("-password")) {
  1551.         if (i == (argv.length - 1)) {
  1552.             System.out.println("No password specified.");
  1553.             usage();
  1554.             System.exit(1);
  1555.         }
  1556.         password = argv[++i];
  1557.         } else if (token.equals("-help")) {
  1558.         usage();
  1559.         System.exit(0);
  1560.         } else if (token.equals("-version")) {
  1561.         System.out.println(progname + " version " + version);
  1562.         System.exit(0);
  1563.         } else if (token.startsWith("-")) {
  1564.         System.out.println("invalid option: " + token);
  1565.         usage();
  1566.         System.exit(1);
  1567.         } else {
  1568.         classArgs += token + " ";
  1569.         }
  1570.     }
  1571.     if (host != null && password == null) {
  1572.         System.out.println("A debug password must be specified for " +
  1573.                    "remote debugging.");
  1574.         System.exit(1);
  1575.     }
  1576.     if (host == null) {
  1577.         host = localhost;
  1578.     }
  1579.  
  1580.     try {
  1581.         if (!host.equals(localhost) && password.length() == 0) {
  1582.         System.out.println(
  1583.             "No password supplied for accessing remote " +
  1584.             "Java interpreter.");
  1585.         System.out.println(
  1586.             "The password is reported by the remote interpreter" +
  1587.             "when it is started.");
  1588.                 System.exit(1);
  1589.             }
  1590.             new TTY(host, password, javaArgs, classArgs, 
  1591.                     System.out, System.out, verbose);
  1592.     } catch(SocketException se) {
  1593.         System.out.println("Failed accessing debugging session on " +
  1594.                    host + ": invalid password.");
  1595.     } catch(NumberFormatException ne) {
  1596.         System.out.println("Failed accessing debugging session on " +
  1597.                    host + ": invalid password.");
  1598.     } catch(Exception e) {        
  1599.         System.out.print("Internal exception:  ");
  1600.         System.out.flush();
  1601.         e.printStackTrace();
  1602.     }
  1603.     }
  1604. }
  1605.