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