Initial Commit
[packages] / xemacs-packages / jde / java / src / jde / debugger / Rep.java
1 package jde.debugger;
2
3 import com.sun.jdi.*;
4
5 import java.util.*;
6
7 /**
8  * Rep.java
9  * <p>
10  * Responsible for providing static methods used in spewing out string
11  * representations.
12  * <ul>
13  * <li> A useful hierarchy:
14  *  <ul>
15  *  <li> Value
16  *   <ul>
17  *   <li> ObjectReference
18  *    <ul>
19  *    <li> StringReference
20  *    <li> ArrayReference
21  *    <li> ThreadReference
22  *    <li> ThreadGroupReference
23  *    <li> Other...
24  *    </ul>
25  *   <li> PrimitiveValue
26  *    <ul>
27  *    <li> BooleanValue
28  *    <li> etc....
29  *    </ul>
30  *   </ul>
31  *  </ul>
32  * </ul> 
33  * In our design, whenever we encounter an objectReference, we pass a
34  * sort of summary to jde, as well as an 'id' to identify it with.
35  * Whenever jde needs info about the objectReference, it uses the id to
36  * uniquely identify the object.
37  * <p>
38  * Now, the representation that is sent across for the threads (ie to the
39  * jde) depends on the context. When it is sent with reference to thread
40  * commands, eg. get_threads, get_thread, get_object_monitors; it has
41  * a lot of thread specific information, eg. its state and all.
42  * <p>
43  * When it's sent treating the thread as an object, eg. get_object, it's
44  * represented differently, and a different set of information is sent.
45  * <p>
46  * Similary, when an array command is used, a different set of information
47  * is sent across, as against when it's treated as an object.
48  * <p>
49  * Created: Tue Aug  3 16:36:54 1999
50  *
51  *
52  * Copyright (c) 2000, 2001, 2003    Paul Kinnucan
53  *
54  * 
55  *
56  * @author Amit Kumar
57  * @author Paul Kinnucan
58  * @since 0.1
59  * @version $Revision: 1.18 $
60  */
61
62 public class Rep implements Protocol {
63
64   /**
65    * Returns a representation of a Location
66    * <p>
67    *
68    * <b>Syntax:</b>
69    * <pre>
70    * (list "type-name" "sourcefile" lineNumber)
71    * (list "type-name" nil lineNumber)
72    * </pre>
73    *
74    * <b>Comments:</b>
75    * <ul>
76    * <li> lineNumber is -1 if that information is not available
77    * </ul>
78    */
79   public static String getLocationRep(Location loc) {
80     StringBuffer locationString = new StringBuffer();
81     locationString.append("(list \"");
82     locationString.append(loc.declaringType().name());
83     locationString.append("\"");
84     try {
85       locationString.append(" \"");
86       locationString.append(loc.sourceName());
87       locationString.append("\"");
88     } catch (AbsentInformationException ex) {
89       locationString.append(" nil"); // XXX - check if this is OK, or if we need to remove the \".
90     }
91     locationString.append(" ");
92     locationString.append(loc.lineNumber());
93     locationString.append(")");
94     return locationString.toString();
95   }
96     
97
98   /**
99    * Returns a representation of a method
100    * <p>
101    *
102    * <b>Syntax:</b>
103    * <pre>
104    * (list "name of method" return-type-name
105    *    (list [argument-type-name]*)
106    *    ["final"] ["static"] ["native"] ["constructor"] ["abstract"]
107    *    ["synchronized"] ["static_initializer"])
108    * </pre>
109    */
110   static String getMethodRep(Method m) {
111     List l = m.argumentTypeNames();
112     StringBuffer argList = new StringBuffer("(list");
113     Iterator it = l.iterator();
114     while (it.hasNext()) {
115       argList.append(" \"");
116       argList.append(it.next().toString());
117       argList.append("\"");
118     }
119     argList.append(")");
120         
121     // The below code results in an extra StringBuffer being created, but I think
122     // that's OK from a performance perspective.
123     return "(list \""+m.declaringType().name()+"\""
124       +" \""+m.name()+"\""
125       +" \""+m.returnTypeName()+"\""
126       + BR + argList.toString()
127       +(m.isFinal()?" \"final\"":"")
128       +(m.isStatic()?" \"static\"":"")
129       +(m.isNative()?" \"native\"":"")
130       +(m.isConstructor()?" \"constructor\"":"")
131       +(m.isAbstract()?" \"abstract\"":"")
132       +(m.isSynchronized()?" \"synchronized\"":"")
133       +(m.isStaticInitializer()
134         ?" \"static_initializer\"":"")
135       +")";
136   }
137     
138
139     
140   /**
141    * Returns a representation of a local variable on a stack frame
142    * <p>
143    * <b>Syntax:</b>
144    * <pre>
145    * (list "name of variable" "type of variable")
146    * </pre>
147    */
148   static public String getLocalVariableRep(LocalVariable lv) {
149     return "(list" + " \""+lv.name()+"\" \""+lv.typeName()+"\")";
150   }
151     
152   /**
153    * Returns a representation of a (local variable, value) pair.
154    * <p>
155    * <b>Syntax:</b>
156    * <pre>
157    * ({@link #getLocalVariableRep local-variable} . {@link #getValueRep value})
158    * </pre>
159    */
160   static public String getLocalVariableValueRep(LocalVariable lv, Value v) {
161     return "(cons "+getLocalVariableRep(lv)
162       +" "+getValueRep(v)+")";
163   }
164
165   /**
166    * Returns a list of (local variable, value) pairs.
167    * <p>
168    * <b>Syntax:</b>
169    * <pre>
170    * (list [{@link #getLocalVariableValueRep (local variable, value) pair}]*)
171    * </pre>
172    */
173   static public String getLocalVariableValueMapRep(Map map) {
174     StringBuffer localVariablesValuesString = new StringBuffer("(list ");
175     Set keys = map.keySet();
176     Iterator iter = keys.iterator();
177     while (iter.hasNext()) {
178       LocalVariable localVariable = (LocalVariable)iter.next();
179       Value val = (Value)map.get(localVariable);
180       localVariablesValuesString.append(BR);
181       localVariablesValuesString.append(getLocalVariableValueRep(localVariable, val));
182     }
183     localVariablesValuesString.append(")");
184     return localVariablesValuesString.toString();
185   }
186
187
188   /**
189    * Returns a representation of a field.
190    * <p>
191    * <b>Syntax:</b>
192    * <pre>
193    * (list "name of field" "type of field" ["transient"] ["volatile"]
194    *                                       ["final"] ["static"])
195    * </pre>
196    */
197   static String getFieldRep(Field f) {
198     return "(list"
199       + " \""+f.name()+"\""
200       + " \""+f.typeName()+"\""
201       + (f.isTransient() ? " \"transient\"" : "")
202       + (f.isVolatile() ? " \"volatile\"" : "")
203       + (f.isFinal() ? " \"final\"" : "")
204       + (f.isStatic() ? " \"static\"" : "")
205       +")";
206   }
207
208   /**
209    * Returns a representation of a (field, value) pair.
210    * <p>
211    * <b>Syntax:</b>
212    * <pre>
213    * ({@link #getFieldRep field} . {@link #getValueRep value})
214    * </pre>
215    */
216   static String getFieldValueRep(Field f, Value v) {
217     return "(cons "+getFieldRep(f)+" "+getValueRep(v)+")";
218   }
219     
220   /**
221    * Returns a list of (field, value) pairs.
222    * <p>
223    * <b>Syntax:</b>
224    * <pre>
225    * (list [{@link #getFieldValueRep (field, value) pair}]*)
226    * </pre>
227    */
228   static String getFieldValueMapRep(Map map) {
229     StringBuffer fieldsValuesString = new StringBuffer("(list ");
230     Set keys = map.keySet();
231     Iterator iter = keys.iterator();
232     while (iter.hasNext()) {
233       Field field = (Field)iter.next();
234       Value val = (Value)map.get(field);
235       fieldsValuesString.append(BR);
236       fieldsValuesString.append(getFieldValueRep(field, val));
237     }
238     fieldsValuesString.append(")");
239     return fieldsValuesString.toString();
240   }
241     
242   private static String filterFPValue(String fpValue) {
243     if (fpValue.equals("NaN"))
244       return "\"NaN\"";
245     else if (fpValue.equals("-Infinity"))
246       return "\"-Infinity\"";
247     else if (fpValue.equals("Infinity"))
248       return "\"Infinity\"";
249     else
250       return fpValue;    
251   }
252
253
254
255   /**
256    * Returns a representation of a 'value', that can be primitive
257    * or an object reference, or void.
258    * <p>
259    * <b>Syntax:</b>
260    * <pre>
261    * (list "null")
262    * (list "void")
263    *
264    * {@link #getObjectRep(ObjectReference) object-rep}
265    * 
266    * (list "boolean" "true")      (list "boolean" "false")
267    * (list "byte"    'byte-value')
268    * (list "char"    'char-value')
269    * (list "double"  double-value)
270    * (list "float"   float-value)
271    * (list "int"     int-value)
272    * (list "long"    long-value)
273    * (list "short"   short-value)
274    * </pre>
275    */
276   static public String getValueRep(Value value) {
277     if (value == null) {
278       return "(list \"null\")";
279     } else if (value instanceof VoidValue) {
280       return "(list \"void\")";
281     } else if (value instanceof ObjectReference) {
282       return getObjectRep((ObjectReference)value);
283     } else {
284       PrimitiveValue v = (PrimitiveValue)value;
285       if (v instanceof BooleanValue) {
286         return "(list \"boolean\" \""+v.booleanValue()+"\")";
287       } else if (v instanceof ByteValue) {
288         return "(list \"byte\" \""+v.byteValue()+"\")";
289       } else if (v instanceof CharValue) {
290         return "(list \"char\" \""+
291           escapeString(String.valueOf(v.charValue()))+"\")";
292       } else if (v instanceof DoubleValue) {
293         return "(list \"double\" " + filterFPValue(String.valueOf(v.doubleValue()))+")";
294       } else if (v instanceof FloatValue) {
295         return "(list \"float\" "+filterFPValue(String.valueOf(v.floatValue()))+")";
296       } else if (v instanceof IntegerValue) {
297         return "(list \"int\" \""+v.intValue()+"\")";
298       } else if (v instanceof LongValue) {
299         return "(list \"long\" \""+v.longValue()+"\")";
300       } else if (v instanceof ShortValue) {
301         return "(list \"short\" "+v.shortValue()+")";
302       }
303     }
304     return null;
305   }
306
307   /**
308    * Returns information about an array
309    * <p>
310    *
311    * <b>Syntax:</b>
312    * <pre>
313    * "Error message"
314    * (list "type name" uniqueID ['t|nil] length [element]*)
315    * </pre>
316    *
317    * <b>Comments:</b>
318    * <ul>
319    * <li> The third argument (['t|nil]) indicates if the object has
320    * been garbage collected in the debugee vm: it's nil if it hasn't.
321    * <li> elements are only present if the index/length make sense. See
322    * param list.
323    * </ul>
324    * <p>
325    *
326    * @param String a description of the array elements
327    */
328   static public String getArrayRep(ArrayReference a, String elements) {
329     if (a == null) {
330       return "\"Error! null array reference in Rep.getArrayRep!\"";
331     } else {
332             
333       return "(list "
334         + "\""+a.referenceType().name()+"\""
335         + " " +a.uniqueID()
336         + (a.isCollected() ? " 't":" nil")
337         + " " + a.length()
338         + elements + ")";
339     }
340   }
341
342
343   /**
344    * Prefix \ escapes to all \ and " characters in a string so that
345    * the string can be read byte the Lisp interpreter. For efficiency,
346    * if no such characters are found, the argument String itself
347    * is returned.
348    *
349    * @param  str   String to be prefixed.
350    * @return A String.
351    *
352    * @author David Hay
353    * @author Mark Gibson
354    * @author Steve Haflich
355    * @author Charles Hart
356    * @author David Dagon
357    */
358   public static String escapeString (String str) {
359         
360     if ( str.indexOf('\\') == -1 &&
361          str.indexOf('"')  == -1 )
362       {
363         return str;
364       }
365     else
366       {
367         StringBuffer buf = new StringBuffer(str.length() + 16);
368         for ( int i = 0; i < str.length(); i++ ) {
369           char ch = str.charAt( i );
370           switch ( ch ) {
371           case '"':  buf.append("\\\"" ); break;
372           case '\\': buf.append("\\\\" ); break;
373           default:   buf.append( ch );    break;
374           }
375         }
376         return buf.toString();
377       }
378   }
379     
380     
381
382   /**
383    * Returns the value of a string
384    * <p>
385    *
386    * <b>Syntax:</b>
387    * <pre>
388    * "Error message"
389    * (list "java.lang.String" uniqueID ['t|nil] "string-value")
390    * </pre>
391    * <b>Comments:</b>
392    * <ul>
393    * <li> The third argument (['t|nil]) indicates if the object has
394    * been garbage collected in the debugee vm: it's nil if it hasn't.
395    * </ul>
396    * <p>
397    */
398   static public String getStringRep(StringReference s) {
399     if (s == null) {
400       return "\"Error!\"";
401     } else {
402             
403       return "(list "
404         + "\""+s.referenceType().name()+"\""
405         + " "+s.uniqueID()
406         + (s.isCollected() ? " 't":" nil")
407         + " \"" + escapeString(s.value()) + "\")";
408     }
409   }
410     
411
412   /**
413    * Returns a non-detailed representation of an object.
414    *
415    * @see #getObjectRep(ObjectReference,boolean)
416    */
417   static public String getObjectRep(ObjectReference o) {
418     return getObjectRep(o, false);
419   }
420
421   /**
422    * Returns a canonical representation of an object.
423    * <p>
424    *
425    * <b>Syntax:</b>
426    * <pre>
427    * "Error Message"
428    * (list "null")
429    * <i>Non-detailed</i>
430    * (list "type of object" uniqueID ['t|nil])
431    * <i>Detailed</i>
432    * (list "type of object" uniqueID ['t|nil] {@link #getFieldValueMapRep fields-values})
433    * </pre>
434    *
435    * <b>Comments:</b>
436    * <ul>
437    * <li> The third argument (['t|nil]) indicates if the object has
438    * been garbage collected in the debugee vm: it's nil if it hasn't.
439    * </ul>
440    */
441   static public String getObjectRep(ObjectReference o, boolean detailed) {
442     if (o == null) {
443       return "(list \"null\")";
444     } else {
445       if (detailed) {
446         // fields and values
447         String fieldsValuesString;
448         try {
449           // XXX a more complete list is available using
450           // allFields().... fyi
451           fieldsValuesString = getFieldValueMapRep(o.getValues(o.referenceType().visibleFields()));
452         } catch (ClassNotPreparedException ex) {
453           fieldsValuesString = "\"The class isn't prepared\"";
454         } catch (ObjectCollectedException ex) {
455           fieldsValuesString = "\"The object has already been collected\"";
456         } catch (Exception ex) {
457           fieldsValuesString = "\"Unable to access fields and values. Optimized class?\"";
458         }
459                 
460         return "(list "
461           + "\""+o.referenceType().name()+"\""
462           + " "+o.uniqueID()
463           + (o.isCollected() ? " 't":" nil")+BR
464           + fieldsValuesString+")";
465       } else {
466         return "(list "
467           + "\""+o.referenceType().name()+"\""
468           + " "+o.uniqueID()
469           + (o.isCollected() ? " 't":" nil")
470           +")";
471       }
472     }
473   }
474     
475     
476   /*
477    * THREAD REPRESENTATIONS
478    */
479
480   /**
481    * Returns information about monitors of an object.
482    * <p>
483    *
484    * <b>Syntax:</b>
485    * <pre>
486    * (list uniqueID "type of object" ['t|nil] {@link #getThreadRep owning-thread} (list [{@link #getThreadRep waiting-thread}]*))
487    * </pre>
488    *
489    * <b>Comments:</b>
490    * <ul>
491    * <li> The third argument (['t|nil]) indicates if the object has
492    * been garbage collected in the debugee vm: it's nil if it hasn't.
493    * </ul>
494    */
495   static public String getObjectMonitorsRep(ObjectReference o) {
496     if (o == null) {
497       return "null";
498     } else {
499
500       // owning thread
501       String owningThread;
502       try {
503         ThreadReference t = o.owningThread();
504         if (t == null) {
505           owningThread = "nil";
506         } else {
507           owningThread = getThreadRep(t);
508         }
509       } catch (IncompatibleThreadStateException ex) {
510         owningThread = "\"Information Not Available\"";
511       } catch (UnsupportedOperationException ex) {
512         owningThread = "\"VM has no information\"";
513       }
514             
515       // waiting threads
516       StringBuffer waitingThreadsStringBuffer = new StringBuffer("(list");
517       String       waitingThreadsString;
518       try {
519         List waitingThreads = o.waitingThreads();
520         Iterator it = waitingThreads.iterator();
521         while (it.hasNext()) {
522           waitingThreadsStringBuffer.append(BR);
523           waitingThreadsStringBuffer.append(getThreadRep((ThreadReference)it.next()));
524         }
525         waitingThreadsStringBuffer.append(")");
526         waitingThreadsString = waitingThreadsStringBuffer.toString();
527       } catch (IncompatibleThreadStateException ex) {
528         waitingThreadsString = "\"Information Not Available\"";
529       } catch (UnsupportedOperationException ex) {
530         waitingThreadsString = "\"VM has no information\"";
531       }
532             
533             
534       return "(list "+o.uniqueID()+" "
535         +"\""+o.referenceType().name()+"\""
536         + (o.isCollected() ? " 't":" nil")+BR
537         +owningThread+ BR 
538         +waitingThreadsString+")";
539     }
540   }
541
542   /* thread information retrieval routines */
543
544     
545
546   /**
547    * Returns a canonical representation of a given ThreadGroupReference.
548    * <p>
549    * <b>Syntax:</b>
550    * <pre>
551    * (list "ThreadGroup" uniqueID "name of threadgroup"
552    *                     (list [{@link #getThreadRep(ThreadReference) child thread}]*)
553    *                     (list [{@link #getThreadGroupRep child threadgroup}]*))
554    * </pre>
555    */
556   public static String getThreadGroupRep(ThreadGroupReference t) {
557     StringBuffer rep = new StringBuffer("(list \"ThreadGroup\" ");
558     rep.append(t.uniqueID());
559     rep.append(" \"");
560     rep.append(t.name());
561     rep.append("\" ");
562
563     List     list = t.threads();
564     Iterator it   = list.iterator();
565
566     rep.append(BR);
567     rep.append("(list");
568
569     while (it.hasNext()) {
570       rep.append(BR);
571       rep.append(getThreadRep((ThreadReference)it.next()));
572     }
573     rep.append(")");
574
575     list = t.threadGroups();
576     it   = list.iterator();
577     rep.append(BR);
578     rep.append("(list");
579     while (it.hasNext()) {
580       rep.append(BR);
581       rep.append(getThreadGroupRep((ThreadGroupReference)it.next()));
582     }
583     rep.append("))");
584         
585     return rep.toString();
586   }
587
588   /**
589    * Returns a detailed thread representation.
590    * @see #getThreadRep(ThreadReference, boolean)
591    */
592   static public String getThreadRep(ThreadReference t) {
593     return getThreadRep(t, true);
594   }
595
596   /**
597    * Returns a canonical representation of a given ThreadReference.
598    * <p>
599    *
600    * <b>Syntax:</b>
601    * <pre>
602    * <i>Non-detailed</i>
603    * (list "Thread" uniqueID "name of thread" <u>status</u> <u>currentState</u>)
604    * <i>Detailed</i>
605    * (list "Thread" uniqueID "name of thread" status currentState
606    *                (list [{@link #getStackFrameRep stack-frame}]*)
607    *                <u>owned-monitors-string</u>
608    *                <u>current-contended-monitor-string</u>)
609    * </pre>
610    *
611    * <b>Comments:</b>
612    * <ul>
613    * <li> <u>status</u> is one of: "unknown", "waiting on monitor",
614    *      "not started", "runnable", "sleeping", "waiting", and "zombie"
615    *
616    * <li> <u>currentState</u> is one of "normal", "suspended by debugger",
617    *      and "suspended at breakpoint"
618
619    * <li> <u>owned-monitors-string</u>:
620    *  <pre>
621    *  "Error Message"
622    *  (list [{@link #getObjectRep(ObjectReference) owned monitor}]*)
623    *  </pre>
624    * <li> <u>current-contended-monitor-string</u>:
625    *  <pre>
626    *  "Error Message"
627    *  nil
628    *  {@link #getObjectRep(ObjectReference) current contended monitor}
629    *  </pre>
630    * <li>
631    * Examples:
632    * <pre>
633    *    (list "Thread" 53 "Thread 1, continuous"
634    *          "suspended by debugger" "waiting on monitor"
635    *          (list 
636    *             (list 0 "test.Test" "Test.java" 45))
637    *          (list)
638    *          (list "java.lang.String" 55))
639    *
640    *    (list "Thread" 54 "Thread 2"
641    *          "suspended by debugger" "waiting on monitor"
642    *          (list 
643    *             (list 0 "java.lang.Thread" "Thread.java" -1)
644    *             (list 1 "test.Test" "Test.java" 47))
645    *          (list 
646    *             (list "java.lang.String" 55)
647    *             (list "java.lang.Integer" 61))
648    *          (list))
649    * </pre>
650    * </ul>
651    *
652    * <p>
653    * @param detailed True if a more detailed representation is desired:
654    * includes the stackframe as well as information about the monitors.
655    */
656   static public String getThreadRep(ThreadReference t,
657                                     boolean detailed) {
658     int    status       = t.status();
659     String statusString = "unknown";
660     switch (status) {
661     case ThreadReference.THREAD_STATUS_MONITOR:
662       statusString = "waiting on monitor";
663       break;
664     case ThreadReference.THREAD_STATUS_NOT_STARTED: 
665       statusString = "not started";
666       break;
667     case ThreadReference.THREAD_STATUS_RUNNING:
668       statusString = "runnable";
669       break;
670     case ThreadReference.THREAD_STATUS_SLEEPING:
671       statusString = "sleeping";
672       break;
673     case ThreadReference.THREAD_STATUS_WAIT:
674       statusString = "waiting";
675       break;
676     case ThreadReference.THREAD_STATUS_ZOMBIE:
677       statusString = "zombie";
678       break;
679     case ThreadReference.THREAD_STATUS_UNKNOWN:
680       statusString = "unknown";
681       break;
682     default:
683       break;
684     }
685
686     // note that the above status string refers to the state of the 
687     // thread *before* a suspension, if there was a suspension.
688
689     /* Due to a bug in ThreadReference.isSuspended(), we need to
690        use suspendCount() */
691     String stateString = "normal";
692     if (t.isAtBreakpoint()) {
693       stateString = "suspended at breakpoint";
694     } else if (t.suspendCount() > 0) {
695       stateString = "suspended by debugger";
696     }
697
698     if (detailed) {
699
700       // info on the stack
701
702       StringBuffer stackStringBuffer = new StringBuffer("(list");
703       String       stackString;
704       try {
705         // a list of the stackframes is also sent...
706         List stackFrames = t.frames();
707         Iterator it = stackFrames.iterator();
708         int index = 0;
709         while (it.hasNext()) {
710           stackStringBuffer.append(BR);
711           stackStringBuffer.append(getStackFrameRep((StackFrame)it.next(), index++));
712         }
713         stackStringBuffer.append(")");
714         stackString = stackStringBuffer.toString();
715       } catch (IncompatibleThreadStateException ex) {
716         stackString = "\"Information Not Available\"";
717       }
718
719       // info on the monitors
720
721       // owned monitors
722
723       StringBuffer ownedMonitorsStringBuffer = new StringBuffer("(list");
724       String ownedMonitorsString;
725       try {
726         List ownedMonitors = t.ownedMonitors();
727         Iterator it = ownedMonitors.iterator();
728         while (it.hasNext()) {
729           ownedMonitorsStringBuffer.append(BR);
730           ownedMonitorsStringBuffer.append(getObjectRep((ObjectReference)it.next()));
731         }
732         ownedMonitorsStringBuffer.append(")");
733         ownedMonitorsString = ownedMonitorsStringBuffer.toString();
734       } catch (IncompatibleThreadStateException ex) {
735         ownedMonitorsString = "\"Information Not Available\"";
736       } catch (UnsupportedOperationException ex) {
737         ownedMonitorsString = "\"VM has no information\"";
738       } catch (ObjectCollectedException ex) {
739         ownedMonitorsString = "\"The object has been collected\"";
740       }
741             
742       // current contended monitor
743       // note, however, from the jdi api:
744       // The thread can be waiting for a monitor through entry into a
745       // synchronized method, the synchronized statement, or
746       // Object.wait(). The status() method can be used to
747       // differentiate between the first two cases and the third. 
748             
749       String currentContendedMonitorString;
750       try {
751         ObjectReference o = t.currentContendedMonitor();
752         if (o == null) {
753           currentContendedMonitorString = "nil";
754         } else {
755           currentContendedMonitorString =
756             getObjectRep(o);
757         }
758       } catch (IncompatibleThreadStateException ex) {
759         currentContendedMonitorString =
760           "\"Information Not Available\"";
761       } catch (UnsupportedOperationException ex) {
762         currentContendedMonitorString =
763           "\"VM has no information\"";
764       } catch (ObjectCollectedException ex) {
765         currentContendedMonitorString =
766           "\"The object has been collected\"";
767       }
768
769       return "(list \"Thread\""
770         +" "+t.uniqueID()
771         +" \""+t.name()+"\""
772         +" \""+statusString+"\""
773         +" \""+stateString+"\""
774         + BR +stackString
775         + BR +ownedMonitorsString
776         + BR +currentContendedMonitorString
777         +")";
778     } else {
779       return "(list \"Thread\""
780         +" "+t.uniqueID()
781         +" \""+t.name()+"\""
782         +" \""+statusString+"\""
783         +" \""+stateString+"\")";
784     }
785   }
786
787   /**
788    * Returns a canonical representation of a given StackFrame.
789    * <p>
790    *
791    * <b>Syntax:</b>
792    * <pre>
793    * (list "StackFrame" index "Information not available")
794    * (list "StackFrame" index "type name" "source name" lineNumber "method name")
795    * </pre>
796    *
797    * <b>Comments:</b>
798    * <ul>
799    * <li> lineNumber is -1 for native methods
800    * </ul>
801    *
802    * @param index Gives the index of this particular stack frame for
803    * the thread. This basically goes into the string returned as a
804    * convenience.
805    */
806   static String getStackFrameRep(StackFrame s, int index) {
807     try {
808       Location loc = s.location();
809       Method method = loc.method();
810       return "(list "+index+" "
811         +"\""+loc.declaringType().name()+"\" "
812         // Source file name can be a path with a backslash.
813         // Need to escape the backslash.
814         + "\"" + escapeString(loc.sourceName()) + "\" "
815         +loc.lineNumber()+" "
816         +"\""+method.name()+"\")";
817     } catch (AbsentInformationException ex) {
818       return "(list \"StackFrame\" "+index
819         +" \"Information not available\")";
820     }
821   }
822     
823 } // Rep
824
825 /*
826  * $Log: Rep.java,v $
827  * Revision 1.18  2003/01/08 06:53:37  paulk
828  * Integrate Petter Mahlen's updates.
829  *
830  * Revision 1.17  2002/10/23 05:54:05  paulk
831  * Updated the getStackFrameRep method to escape backslashes in the name of the source file
832  * corresponding to a stack frame. The name of the source file can be a relative path in
833  * some obscure cases and the relative path can include backslashes.
834  *
835  * Revision 1.16  2001/08/14 05:15:01  paulk
836  * Miscellaneous updates.
837  *
838  * Revision 1.15  2001/04/19 04:43:55  paulk
839  * Now escapes char values.
840  *
841  * Revision 1.14  2001/03/24 05:36:49  paulk
842  * Updated to reflect reorganization of debuggee code.
843  *
844  * Revision 1.13  2000/07/28 06:26:31  paulk
845  * Committing all modified files.
846  *
847  * Revision 1.12  2000/04/10 05:57:30  paulk
848  * Publicized some methods.
849  *
850  * Revision 1.11  2000/04/01 06:02:37  paulk
851  * Wrap NaN, Infinity, and -Infinity values in quotes to prevent Lisp evaluation errors.
852  *
853  * Revision 1.10  2000/03/17 03:35:23  paulk
854  * Enhanced getStackFrameRep to return method. Thanks to Paul Michael Reilly <pmr@pajato.com>.
855  *
856  * Revision 1.9  2000/03/10 06:53:25  paulk
857  * Escape quotes in strings.
858  *
859  * Revision 1.8  2000/03/04 08:58:11  paulk
860  * Put quotes around byte, int, and long values to avoid Lisp
861  * representation problems. Thanks to Charles Hart <cfhart@Z-TEL.com> for this fix.
862  *
863  */
864
865 // End Rep.java