View Javadoc

1   // OnlineDebugger.java, created Sat Feb 22 13:35:26 2003 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package joeq.Debugger;
5   
6   import java.util.StringTokenizer;
7   import java.io.BufferedReader;
8   import java.io.IOException;
9   import java.io.InputStreamReader;
10  import joeq.Allocator.CodeAllocator;
11  import joeq.Class.jq_Array;
12  import joeq.Class.jq_Class;
13  import joeq.Class.jq_CompiledCode;
14  import joeq.Class.jq_InstanceField;
15  import joeq.Class.jq_LocalVarTableEntry;
16  import joeq.Class.jq_Method;
17  import joeq.Class.jq_Primitive;
18  import joeq.Class.jq_Reference;
19  import joeq.Compiler.CompilationState;
20  import joeq.Compiler.BytecodeAnalysis.BytecodeVisitor;
21  import joeq.Main.TraceFlags;
22  import joeq.Main.jq;
23  import joeq.Memory.Address;
24  import joeq.Memory.CodeAddress;
25  import joeq.Memory.HeapAddress;
26  import joeq.Memory.StackAddress;
27  import joeq.Runtime.Debug;
28  import joeq.Runtime.Reflection;
29  import joeq.Runtime.StackCodeWalker;
30  import joeq.Runtime.SystemInterface;
31  import joeq.Scheduler.jq_NativeThread;
32  import jwutil.strings.Strings;
33  import jwutil.util.Assert;
34  
35  /***
36   * @author John Whaley <jwhaley@alum.mit.edu>
37   * @version $Id: OnlineDebugger.java 1941 2004-09-30 03:37:06Z joewhaley $
38   */
39  public class OnlineDebugger {
40  
41      public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
42  
43      static boolean inDebugger;
44  
45      public static boolean debuggerEntryPoint() {
46          if (!jq.RunningNative) {
47              new InternalError().printStackTrace();
48              System.exit(-1);
49          }
50          if (inDebugger) {
51              SystemInterface.debugwriteln("Recursively entering debugger!");
52              StackAddress fp = StackAddress.getBasePointer();
53              CodeAddress ip = (CodeAddress) fp.offset(4).peek();
54              Debug.writeln("fp = ", fp);
55              Debug.writeln("ip = ", ip);
56              return false;
57          }
58          inDebugger = true;
59          SystemInterface.debugwriteln(">>> Entering debugger.");
60          StackAddress fp = StackAddress.getBasePointer();
61          CodeAddress ip = (CodeAddress) fp.offset(4).peek();
62          fp = (StackAddress) fp.peek();
63          StackCodeWalker sw = new StackCodeWalker(ip, fp);
64          int frameNum = 0;
65          SystemInterface.debugwriteln("> "+frameNum+":"+sw.toString());
66          
67          //bsh.Interpreter i = null;
68  uphere:
69          for (;;) {
70              SystemInterface.debugwrite("db> ");
71              String s = null;
72              try {
73                  s = in.readLine();
74              } catch (IOException _) { }
75              if (s == null) {
76                  SystemInterface.debugwriteln(">>> Exiting debugger.");
77                  inDebugger = false;
78                  return true;
79              }
80              if (s.equals("")) {
81                  continue;
82              }
83              if (s.equals("c")) {
84                  SystemInterface.debugwriteln(">>> Continuing execution.");
85                  inDebugger = false;
86                  return true;
87              }
88              if (s.equals("s")) {
89                  SystemInterface.debugwriteln("Single-step not yet implemented.");
90                  continue;
91              }
92              if (s.equals("u")) {
93                  if (!sw.hasNext()) {
94                      SystemInterface.debugwriteln("Reached top.");
95                      continue;
96                  }
97                  sw.gotoNext(); ++frameNum;
98                  SystemInterface.debugwriteln("> "+frameNum+":"+sw.toString());
99                  continue;
100             }
101             if (s.equals("d")) {
102                 if (frameNum == 0) {
103                     SystemInterface.debugwriteln("Reached top.");
104                     continue;
105                 }
106                 StackCodeWalker sw2 = new StackCodeWalker(ip, fp);
107                 for (;;) {
108                     if (!sw2.hasNext()) {
109                         SystemInterface.debugwriteln("ERROR! Stack is corrupted.");
110                         continue uphere;
111                     }
112                     if (sw2.getFP().peek().difference(sw.getFP()) == 0)
113                         break;
114                     sw2.gotoNext();
115                 }
116                 sw = sw2; --frameNum;
117                 SystemInterface.debugwriteln("> "+frameNum+":"+sw.toString());
118                 continue;
119             }
120             if (s.equals("bt")) {
121                 StackCodeWalker sw2 = new StackCodeWalker(ip, fp);
122                 int counter = 0;
123                 while (sw2.hasNext()) {
124                     if (counter == frameNum) {
125                         SystemInterface.debugwriteln("> "+counter+":"+sw2.toString());
126                         if (sw2.getFP().difference(sw.getFP()) != 0) {
127                             SystemInterface.debugwriteln("ERROR! Stack is corrupted. Expected "+sw+" but found "+sw2);
128                         }
129                     } else {
130                         SystemInterface.debugwriteln("  "+counter+":"+sw2.toString());
131                     }
132                     sw2.gotoNext(); ++counter;
133                 }
134                 continue;
135             }
136             if (s.equals("t")) {
137                 jq_NativeThread.dumpAllThreads();
138                 continue;
139             }
140             if (s.equals("sf")) {
141                 printStackFrame(sw);
142                 continue;
143             }
144             if (s.equals("l")) {
145                 jq_Method m = sw.getMethod();
146                 if (m == null) {
147                     SystemInterface.debugwriteln("Unknown method!");
148                     continue;
149                 }
150                 if (m.getBytecode() == null) {
151                     SystemInterface.debugwriteln("No bytecode for method "+m+"!");
152                     continue;
153                 }
154                 int currentIndex = sw.getBCIndex();
155                 if (currentIndex < 0) currentIndex = 0;
156                 BytecodeLister bl = new BytecodeLister(m, 0, m.getBytecode().length, currentIndex);
157                 bl.forwardTraversal();
158                 continue;
159             }
160             if (s.equals("?")) {
161                 printUsage();
162                 continue;
163             }
164             if (s.startsWith("toString ")) {
165                 s = s.substring(9);
166                 if (s.startsWith("0x") || s.startsWith("0X")) s = s.substring(2);
167                 int k = (int) Long.parseLong(s, 16);
168                 HeapAddress addr = HeapAddress.address32(k);
169                 Object o = addr.asObject();
170                 SystemInterface.debugwriteln(o.toString());
171                 continue;
172             }
173             if (s.startsWith("dumpObject ")) {
174                 s = s.substring(11);
175                 if (s.startsWith("0x") || s.startsWith("0X")) s = s.substring(2);
176                 int k = (int) Long.parseLong(s, 16);
177                 dumpObject(k);
178                 continue;
179             }
180             
181             String[] commands;
182             StringTokenizer st = new StringTokenizer(s);
183             int size = st.countTokens();
184             commands = new String[size];
185             for (int j = 0; j < size; ++j) {
186                 commands[j] = st.nextToken();
187             }
188             Assert._assert(!st.hasMoreTokens());
189             int index2 = TraceFlags.setTraceFlag(commands, 0);
190             if (0 != index2) {
191                 continue;
192             }
193             
194             /*
195             if (i == null) i = new bsh.Interpreter();
196             try {
197                 Object result = i.eval(s);
198                 SystemInterface.debugwriteln("Result: "+result);
199             } catch (bsh.EvalError x) {
200                 SystemInterface.debugwriteln("Evaluation error: "+x);
201             }
202             */
203         }
204     }
205 
206     public static void printUsage() {
207         SystemInterface.debugwriteln("c: continue, s: step");
208         SystemInterface.debugwriteln("l: list bytecode");
209         SystemInterface.debugwriteln("dumpObject, toString");
210         SystemInterface.debugwriteln("u: up, d: down, sf: stack frame, bt: back trace, t: thread dump");
211     }
212     
213     public static void dumpObject(int k) {
214         HeapAddress addr = HeapAddress.address32(k);
215         Object o = addr.asObject();
216         dumpObject(o);
217     }
218     
219     public static void dumpObject(Object o) {
220         HeapAddress addr = HeapAddress.addressOf(o);
221         jq_Reference t = jq_Reference.getTypeOf(o);
222         SystemInterface.debugwriteln(addr.stringRep()+" type "+t);
223         if (t.isClassType()) {
224             jq_Class c = (jq_Class) t;
225             jq_InstanceField[] f = c.getInstanceFields();
226             for (int j=0; j<f.length; ++j) {
227                 StringBuffer sb = new StringBuffer();
228                 sb.append(Strings.left(f[j].getName().toString(), 15));
229                 sb.append(':');
230                 if (f[j].getType().isReferenceType()) {
231                     Address addr2 = addr.offset(f[j].getOffset()).peek();
232                     sb.append(addr2.stringRep());
233                 } else {
234                     sb.append(Reflection.getfield(o, f[j]));
235                 }
236                 SystemInterface.debugwriteln(sb.toString());
237             }
238         } else {
239             jq_Array a = (jq_Array) t;
240             int length = Reflection.arraylength(o);
241             for (int j=0; j<length; ++j) {
242                 if (a.getElementType().isReferenceType()) {
243                     SystemInterface.debugwriteln(j+": "+addr.offset(j*HeapAddress.size()).peek().stringRep());
244                 } else if (a.getElementType() == jq_Primitive.FLOAT) {
245                     SystemInterface.debugwriteln(j+": "+Float.intBitsToFloat(addr.offset(j*4).peek4()));
246                 } else if (a.getElementType() == jq_Primitive.DOUBLE) {
247                     SystemInterface.debugwriteln(j+": "+Double.longBitsToDouble(addr.offset(j*8).peek8()));
248                 } else if (a.getElementType().getReferenceSize() == 1) {
249                     SystemInterface.debugwriteln(j+": "+addr.offset(j).peek1());
250                 } else if (a.getElementType().getReferenceSize() == 2) {
251                     SystemInterface.debugwriteln(j+": "+addr.offset(j*2).peek2());
252                 } else if (a.getElementType().getReferenceSize() == 4) {
253                     SystemInterface.debugwriteln(j+": "+addr.offset(j*4).peek4());
254                 } else if (a.getElementType().getReferenceSize() == 8) {
255                     SystemInterface.debugwriteln(j+": "+addr.offset(j*8).peek8());
256                 }
257             }
258         }
259     }
260     
261     public static void printStackFrame(StackCodeWalker sw) {
262         StackAddress my_fp = sw.getFP();
263         if (my_fp.isNull()) {
264             SystemInterface.debugwriteln("Cannot dump this frame!"+Strings.lineSep);
265             return;
266         }
267         CodeAddress my_ip = (CodeAddress) my_fp.offset(4).peek();
268         StackAddress next_fp = (StackAddress) my_fp.peek();
269         if (my_fp.isNull()) {
270             SystemInterface.debugwriteln("Cannot dump this frame!"+Strings.lineSep);
271             return;
272         }
273         jq_CompiledCode cc = CodeAllocator.getCodeContaining(my_ip);
274         jq_Method m = null;
275         if (cc != null) m = cc.getMethod();
276         SystemInterface.debugwriteln("Stack frame for "+cc);
277         if (m != null) {
278             SystemInterface.debugwriteln(((int)m.getMaxLocals())+" locals, "+((int)m.getParamWords())+" param words");
279         }
280         // b0: next->| caller's saved FP  |
281         // ac:       | caller's locals    |
282         //           |        ...         |
283         // 94:       | caller's opstack   |
284         //           |        ...         |
285         // 80:       | pushed params      |
286         //           |        ...         |
287         // 74:       | ret addr in caller |
288         // 70:   my->| callee's FP (b0)   |
289         StackAddress ptr = my_fp;
290         int framesize = 0;
291         if (m != null) framesize = (m.getParamWords()+1)*StackAddress.size();
292         while (ptr.difference(next_fp) <= framesize) {
293             if (ptr.difference(my_fp) == 0) {
294                 SystemInterface.debugwriteln("Callee FP:      "+ptr.stringRep()+" : "+ptr.peek().stringRep());
295             } else if (ptr.difference(next_fp) == StackAddress.size()) {
296                 CodeAddress my_ip2 = (CodeAddress) ptr.peek();
297                 jq_CompiledCode cc2 = CodeAllocator.getCodeContaining(my_ip2);
298                 int code_offset = 0;
299                 if (cc2 != null)
300                     code_offset = my_ip2.difference(cc2.getStart());
301                 SystemInterface.debugwriteln("Caller retaddr: "+ptr.stringRep()+" : "+ptr.peek().stringRep()+"  (offset "+Strings.hex(code_offset)+")");
302             } else if (m != null && ptr.difference(next_fp) > 0) {
303                 int n = m.getParamWords() - ptr.difference(next_fp) / StackAddress.size() + 1;
304                 SystemInterface.debugwriteln(Strings.left("Incoming arg "+n+":", 16)+ptr.stringRep()+" : "+ptr.peek().stringRep());
305             } else if (ptr.difference(my_fp) == StackAddress.size()) {
306                 int code_offset = 0;
307                 if (cc != null)
308                     code_offset = my_ip.difference(cc.getStart());
309                 SystemInterface.debugwriteln("Return address: "+ptr.stringRep()+" : "+ptr.peek().stringRep()+"  (offset "+Strings.hex(code_offset)+")");
310             } else if (next_fp.difference(ptr) == 0) {
311                 SystemInterface.debugwriteln("Caller FP:      "+ptr.stringRep()+" : "+ptr.peek().stringRep());
312             } else if (m != null && next_fp.difference(ptr) <= StackAddress.size()*(m.getMaxLocals()-m.getParamWords())) {
313                 int n = next_fp.difference(ptr) / StackAddress.size() - 1;
314                 int offset = sw.getBCIndex();
315                 jq_LocalVarTableEntry e = m.getLocalVarTableEntry(offset, n);
316                 String nd = (e != null) ? e.getNameAndDesc().toString() : "";
317                 SystemInterface.debugwriteln(Strings.left("Local "+n+": ", 16)+ptr.stringRep()+" : "+ptr.peek().stringRep()+"\t"+nd);
318             } else if (m != null && ptr.difference(my_fp) > StackAddress.size()) {
319                 int n = next_fp.difference(ptr) / StackAddress.size() - m.getMaxLocals() + m.getParamWords() - 2;
320                 SystemInterface.debugwriteln(Strings.left("Stack "+n+": ", 16)+ptr.stringRep()+" : "+ptr.peek().stringRep());
321             } else {
322                 SystemInterface.debugwriteln("                "+ptr.stringRep()+" : "+ptr.peek().stringRep());
323             }
324             ptr = (StackAddress) ptr.offset(StackAddress.size());
325         }
326     }
327     
328     public static class BytecodeLister extends BytecodeVisitor {
329         
330         protected int i_loc;
331         protected int i_stop;
332         
333         public BytecodeLister(jq_Method m, int start, int stop, int loc) {
334             super(CompilationState.DEFAULT, m);
335             this.i_end = start-1;
336             this.i_start = start;
337             this.i_stop = stop;
338             this.i_loc = loc;
339             this.out = System.err;
340             this.TRACE = true;
341         }
342         public void forwardTraversal() throws VerifyError {
343             for (i_end=-1; ; ) {
344                 i_start = i_end+1;
345                 if (i_start == i_loc) {
346                     out.println("Current location:");
347                 }
348                 if (i_start >= i_stop) break;
349                 this.visitBytecode();
350             }
351         }
352         public String toString() { return Strings.left(method.getName().toString(), 12); }
353     }
354     
355 }