0
|
1 /*
|
|
2 * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved.
|
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 *
|
|
5 * This code is free software; you can redistribute it and/or modify it
|
|
6 * under the terms of the GNU General Public License version 2 only, as
|
|
7 * published by the Free Software Foundation.
|
|
8 *
|
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT
|
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12 * version 2 for more details (a copy is included in the LICENSE file that
|
|
13 * accompanied this code).
|
|
14 *
|
|
15 * You should have received a copy of the GNU General Public License version
|
|
16 * 2 along with this work; if not, write to the Free Software Foundation,
|
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
18 *
|
|
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or
|
|
21 * have any questions.
|
|
22 *
|
|
23 */
|
|
24
|
|
25 package sun.jvm.hotspot;
|
|
26
|
|
27 import java.io.*;
|
|
28 import java.math.*;
|
|
29 import java.util.*;
|
|
30 import java.util.regex.*;
|
|
31
|
|
32 import sun.jvm.hotspot.types.Type;
|
|
33 import sun.jvm.hotspot.types.Field;
|
|
34 import sun.jvm.hotspot.HotSpotTypeDataBase;
|
|
35 import sun.jvm.hotspot.types.basic.BasicType;
|
|
36 import sun.jvm.hotspot.types.CIntegerType;
|
|
37 import sun.jvm.hotspot.code.*;
|
|
38 import sun.jvm.hotspot.compiler.*;
|
|
39 import sun.jvm.hotspot.debugger.*;
|
|
40 import sun.jvm.hotspot.interpreter.*;
|
|
41 import sun.jvm.hotspot.memory.*;
|
|
42 import sun.jvm.hotspot.oops.*;
|
|
43 import sun.jvm.hotspot.runtime.*;
|
|
44 import sun.jvm.hotspot.utilities.*;
|
|
45 import sun.jvm.hotspot.utilities.soql.*;
|
|
46 import sun.jvm.hotspot.ui.classbrowser.*;
|
|
47 import sun.jvm.hotspot.ui.tree.*;
|
|
48 import sun.jvm.hotspot.tools.*;
|
|
49 import sun.jvm.hotspot.tools.ObjectHistogram;
|
|
50 import sun.jvm.hotspot.tools.StackTrace;
|
|
51
|
|
52 public class CommandProcessor {
|
|
53 public abstract static class DebuggerInterface {
|
|
54 public abstract HotSpotAgent getAgent();
|
|
55 public abstract boolean isAttached();
|
|
56 public abstract void attach(String pid);
|
|
57 public abstract void attach(String java, String core);
|
|
58 public abstract void detach();
|
|
59 public abstract void reattach();
|
|
60 }
|
|
61
|
|
62 static class Tokens {
|
|
63 final String input;
|
|
64 int i;
|
|
65 String[] tokens;
|
|
66 int length;
|
|
67
|
|
68 String[] splitWhitespace(String cmd) {
|
|
69 String[] t = cmd.split("\\s");
|
|
70 if (t.length == 1 && t[0].length() == 0) {
|
|
71 return new String[0];
|
|
72 }
|
|
73 return t;
|
|
74 }
|
|
75
|
|
76 void add(String s, ArrayList t) {
|
|
77 if (s.length() > 0) {
|
|
78 t.add(s);
|
|
79 }
|
|
80 }
|
|
81
|
|
82 Tokens(String cmd) {
|
|
83 input = cmd;
|
|
84
|
|
85 // check for quoting
|
|
86 int quote = cmd.indexOf('"');
|
|
87 ArrayList t = new ArrayList();
|
|
88 if (quote != -1) {
|
|
89 while (cmd.length() > 0) {
|
|
90 if (quote != -1) {
|
|
91 int endquote = cmd.indexOf('"', quote + 1);
|
|
92 if (endquote == -1) {
|
|
93 throw new RuntimeException("mismatched quotes: " + input);
|
|
94 }
|
|
95
|
|
96 String before = cmd.substring(0, quote).trim();
|
|
97 String quoted = cmd.substring(quote + 1, endquote);
|
|
98 cmd = cmd.substring(endquote + 1).trim();
|
|
99 if (before.length() > 0) {
|
|
100 String[] w = splitWhitespace(before);
|
|
101 for (int i = 0; i < w.length; i++) {
|
|
102 add(w[i], t);
|
|
103 }
|
|
104 }
|
|
105 add(quoted, t);
|
|
106 quote = cmd.indexOf('"');
|
|
107 } else {
|
|
108 String[] w = splitWhitespace(cmd);
|
|
109 for (int i = 0; i < w.length; i++) {
|
|
110 add(w[i], t);
|
|
111 }
|
|
112 cmd = "";
|
|
113
|
|
114 }
|
|
115 }
|
|
116 } else {
|
|
117 String[] w = splitWhitespace(cmd);
|
|
118 for (int i = 0; i < w.length; i++) {
|
|
119 add(w[i], t);
|
|
120 }
|
|
121 }
|
|
122 tokens = (String[])t.toArray(new String[0]);
|
|
123 i = 0;
|
|
124 length = tokens.length;
|
|
125
|
|
126 //for (int i = 0; i < tokens.length; i++) {
|
|
127 // System.out.println("\"" + tokens[i] + "\"");
|
|
128 //}
|
|
129 }
|
|
130
|
|
131 String nextToken() {
|
|
132 return tokens[i++];
|
|
133 }
|
|
134 boolean hasMoreTokens() {
|
|
135 return i < length;
|
|
136 }
|
|
137 int countTokens() {
|
|
138 return length - i;
|
|
139 }
|
|
140 void trim(int n) {
|
|
141 if (length >= n) {
|
|
142 length -= n;
|
|
143 } else {
|
|
144 throw new IndexOutOfBoundsException(String.valueOf(n));
|
|
145 }
|
|
146 }
|
|
147 String join(String sep) {
|
|
148 StringBuffer result = new StringBuffer();
|
|
149 for (int w = i; w < length; w++) {
|
|
150 result.append(tokens[w]);
|
|
151 if (w + 1 < length) {
|
|
152 result.append(sep);
|
|
153 }
|
|
154 }
|
|
155 return result.toString();
|
|
156 }
|
|
157
|
|
158 String at(int i) {
|
|
159 if (i < 0 || i >= length) {
|
|
160 throw new IndexOutOfBoundsException(String.valueOf(i));
|
|
161 }
|
|
162 return tokens[i];
|
|
163 }
|
|
164 }
|
|
165
|
|
166
|
|
167 abstract class Command {
|
|
168 Command(String n, String u, boolean ok) {
|
|
169 name = n;
|
|
170 usage = u;
|
|
171 okIfDisconnected = ok;
|
|
172 }
|
|
173
|
|
174 Command(String n, boolean ok) {
|
|
175 name = n;
|
|
176 usage = n;
|
|
177 okIfDisconnected = ok;
|
|
178 }
|
|
179
|
|
180 final String name;
|
|
181 final String usage;
|
|
182 final boolean okIfDisconnected;
|
|
183 abstract void doit(Tokens t);
|
|
184 void usage() {
|
|
185 out.println("Usage: " + usage);
|
|
186 }
|
|
187
|
|
188 void printOopValue(Oop oop) {
|
|
189 if (oop != null) {
|
|
190 Klass k = oop.getKlass();
|
|
191 Symbol s = k.getName();
|
|
192 if (s != null) {
|
|
193 out.print("Oop for " + s.asString() + " @ ");
|
|
194 } else {
|
|
195 out.print("Oop @ ");
|
|
196 }
|
|
197 Oop.printOopAddressOn(oop, out);
|
|
198 } else {
|
|
199 out.print("null");
|
|
200 }
|
|
201 }
|
|
202
|
|
203 void printNode(SimpleTreeNode node) {
|
|
204 int count = node.getChildCount();
|
|
205 for (int i = 0; i < count; i++) {
|
|
206 try {
|
|
207 SimpleTreeNode field = node.getChild(i);
|
|
208 if (field instanceof OopTreeNodeAdapter) {
|
|
209 out.print(field);
|
|
210 out.print(" ");
|
|
211 printOopValue(((OopTreeNodeAdapter)field).getOop());
|
|
212 out.println();
|
|
213 } else {
|
|
214 out.println(field);
|
|
215 }
|
|
216 } catch (Exception e) {
|
|
217 out.println();
|
|
218 out.println("Error: " + e);
|
|
219 if (verboseExceptions) {
|
|
220 e.printStackTrace(out);
|
|
221 }
|
|
222 }
|
|
223 }
|
|
224 }
|
|
225 }
|
|
226
|
|
227 void quote(String s) {
|
|
228 if (s.indexOf(" ") == -1) {
|
|
229 out.print(s);
|
|
230 } else {
|
|
231 out.print("\"");
|
|
232 out.print(s);
|
|
233 out.print("\"");
|
|
234 }
|
|
235 }
|
|
236
|
|
237 void dumpType(Type type) {
|
|
238 out.print("type ");
|
|
239 quote(type.getName());
|
|
240 out.print(" ");
|
|
241 if (type.getSuperclass() != null) {
|
|
242 quote(type.getSuperclass().getName());
|
|
243 out.print(" ");
|
|
244 } else {
|
|
245 out.print("null ");
|
|
246 }
|
|
247 out.print(type.isOopType());
|
|
248 out.print(" ");
|
|
249 if (type.isCIntegerType()) {
|
|
250 out.print("true ");
|
|
251 out.print(((CIntegerType)type).isUnsigned());
|
|
252 out.print(" ");
|
|
253 } else {
|
|
254 out.print("false false ");
|
|
255 }
|
|
256 out.print(type.getSize());
|
|
257 out.println();
|
|
258 }
|
|
259
|
|
260 void dumpFields(Type type) {
|
|
261 Iterator i = type.getFields();
|
|
262 while (i.hasNext()) {
|
|
263 Field f = (Field) i.next();
|
|
264 out.print("field ");
|
|
265 quote(type.getName());
|
|
266 out.print(" ");
|
|
267 out.print(f.getName());
|
|
268 out.print(" ");
|
|
269 quote(f.getType().getName());
|
|
270 out.print(" ");
|
|
271 out.print(f.isStatic());
|
|
272 out.print(" ");
|
|
273 if (f.isStatic()) {
|
|
274 out.print("0 ");
|
|
275 out.print(f.getStaticFieldAddress());
|
|
276 } else {
|
|
277 out.print(f.getOffset());
|
|
278 out.print(" 0x0");
|
|
279 }
|
|
280 out.println();
|
|
281 }
|
|
282 }
|
|
283
|
|
284
|
|
285 Address lookup(String symbol) {
|
|
286 if (symbol.indexOf("::") != -1) {
|
|
287 String[] parts = symbol.split("::");
|
|
288 StringBuffer mangled = new StringBuffer("__1c");
|
|
289 for (int i = 0; i < parts.length; i++) {
|
|
290 int len = parts[i].length();
|
|
291 if (len >= 26) {
|
|
292 mangled.append((char)('a' + (len / 26)));
|
|
293 len = len % 26;
|
|
294 }
|
|
295 mangled.append((char)('A' + len));
|
|
296 mangled.append(parts[i]);
|
|
297 }
|
|
298 mangled.append("_");
|
|
299 symbol = mangled.toString();
|
|
300 }
|
|
301 return VM.getVM().getDebugger().lookup(null, symbol);
|
|
302 }
|
|
303
|
|
304 Address parseAddress(String addr) {
|
|
305 return VM.getVM().getDebugger().parseAddress(addr);
|
|
306 }
|
|
307
|
|
308 private final Command[] commandList = {
|
|
309 new Command("reattach", true) {
|
|
310 public void doit(Tokens t) {
|
|
311 int tokens = t.countTokens();
|
|
312 if (tokens != 0) {
|
|
313 usage();
|
|
314 return;
|
|
315 }
|
|
316 preAttach();
|
|
317 debugger.reattach();
|
|
318 postAttach();
|
|
319 }
|
|
320 },
|
|
321 new Command("attach", "attach pid | exec core", true) {
|
|
322 public void doit(Tokens t) {
|
|
323 int tokens = t.countTokens();
|
|
324 if (tokens == 1) {
|
|
325 preAttach();
|
|
326 debugger.attach(t.nextToken());
|
|
327 postAttach();
|
|
328 } else if (tokens == 2) {
|
|
329 preAttach();
|
|
330 debugger.attach(t.nextToken(), t.nextToken());
|
|
331 postAttach();
|
|
332 } else {
|
|
333 usage();
|
|
334 }
|
|
335 }
|
|
336 },
|
|
337 new Command("detach", false) {
|
|
338 public void doit(Tokens t) {
|
|
339 if (t.countTokens() != 0) {
|
|
340 usage();
|
|
341 } else {
|
|
342 debugger.detach();
|
|
343 }
|
|
344 }
|
|
345 },
|
|
346 new Command("examine", "examine [ address/count ] | [ address,address]", false) {
|
|
347 Pattern args1 = Pattern.compile("^(0x[0-9a-f]+)(/([0-9]*)([a-z]*))?$");
|
|
348 Pattern args2 = Pattern.compile("^(0x[0-9a-f]+),(0x[0-9a-f]+)(/[a-z]*)?$");
|
|
349
|
|
350 String fill(Address a, int width) {
|
|
351 String s = "0x0";
|
|
352 if (a != null) {
|
|
353 s = a.toString();
|
|
354 }
|
|
355 if (s.length() != width) {
|
|
356 return s.substring(0, 2) + "000000000000000000000".substring(0, width - s.length()) + s.substring(2);
|
|
357 }
|
|
358 return s;
|
|
359 }
|
|
360
|
|
361 public void doit(Tokens t) {
|
|
362 if (t.countTokens() != 1) {
|
|
363 usage();
|
|
364 } else {
|
|
365 String arg = t.nextToken();
|
|
366 Matcher m1 = args1.matcher(arg);
|
|
367 Matcher m2 = args2.matcher(arg);
|
|
368 Address start = null;
|
|
369 Address end = null;
|
|
370 String format = "";
|
|
371 int formatSize = (int)VM.getVM().getAddressSize();
|
|
372
|
|
373 if (m1.matches()) {
|
|
374 start = VM.getVM().getDebugger().parseAddress(m1.group(1));
|
|
375 int count = 1;
|
|
376 if (m1.group(2) != null) {
|
|
377 count = Integer.parseInt(m1.group(3));
|
|
378 }
|
|
379 end = start.addOffsetTo(count * formatSize);
|
|
380 } else if (m2.matches()) {
|
|
381 start = VM.getVM().getDebugger().parseAddress(m2.group(1));
|
|
382 end = VM.getVM().getDebugger().parseAddress(m2.group(2));
|
|
383 } else {
|
|
384 usage();
|
|
385 return;
|
|
386 }
|
|
387 int line = 80;
|
|
388 int formatWidth = formatSize * 8 / 4 + 2;
|
|
389
|
|
390 out.print(fill(start, formatWidth));
|
|
391 out.print(": ");
|
|
392 int width = line - formatWidth - 2;
|
|
393
|
|
394 boolean needsPrintln = true;
|
|
395 while (start != null && start.lessThan(end)) {
|
|
396 Address val = start.getAddressAt(0);
|
|
397 out.print(fill(val, formatWidth));
|
|
398 needsPrintln = true;
|
|
399 width -= formatWidth;
|
|
400 start = start.addOffsetTo(formatSize);
|
|
401 if (width <= formatWidth) {
|
|
402 out.println();
|
|
403 needsPrintln = false;
|
|
404 if (start.lessThan(end)) {
|
|
405 out.print(fill(start, formatWidth));
|
|
406 out.print(": ");
|
|
407 width = line - formatWidth - 2;
|
|
408 }
|
|
409 } else {
|
|
410 out.print(" ");
|
|
411 width -= 1;
|
|
412 }
|
|
413 }
|
|
414 if (needsPrintln) {
|
|
415 out.println();
|
|
416 }
|
|
417 }
|
|
418 }
|
|
419 },
|
|
420 new Command("findpc", "findpc address", false) {
|
|
421 public void doit(Tokens t) {
|
|
422 if (t.countTokens() != 1) {
|
|
423 usage();
|
|
424 } else {
|
|
425 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
|
|
426 PointerLocation loc = PointerFinder.find(a);
|
|
427 loc.printOn(out);
|
|
428 }
|
|
429 }
|
|
430 },
|
|
431 new Command("flags", "flags [ flag ]", false) {
|
|
432 public void doit(Tokens t) {
|
|
433 int tokens = t.countTokens();
|
|
434 if (tokens != 0 && tokens != 1) {
|
|
435 usage();
|
|
436 } else {
|
|
437 String name = tokens > 0 ? t.nextToken() : null;
|
|
438
|
|
439 VM.Flag[] flags = VM.getVM().getCommandLineFlags();
|
|
440 if (flags == null) {
|
|
441 out.println("Command Flag info not available (use 1.4.1_03 or later)!");
|
|
442 } else {
|
|
443 boolean printed = false;
|
|
444 for (int f = 0; f < flags.length; f++) {
|
|
445 VM.Flag flag = flags[f];
|
|
446 if (name == null || flag.getName().equals(name)) {
|
|
447 out.println(flag.getName() + " = " + flag.getValue());
|
|
448 printed = true;
|
|
449 }
|
|
450 }
|
|
451 if (name != null && !printed) {
|
|
452 out.println("Couldn't find flag: " + name);
|
|
453 }
|
|
454 }
|
|
455 }
|
|
456 }
|
|
457 },
|
|
458 new Command("help", "help [ command ]", true) {
|
|
459 public void doit(Tokens t) {
|
|
460 int tokens = t.countTokens();
|
|
461 Command cmd = null;
|
|
462 if (tokens == 1) {
|
|
463 cmd = findCommand(t.nextToken());
|
|
464 }
|
|
465
|
|
466 if (cmd != null) {
|
|
467 cmd.usage();
|
|
468 } else if (tokens == 0) {
|
|
469 out.println("Available commands:");
|
|
470 Object[] keys = commands.keySet().toArray();
|
|
471 Arrays.sort(keys, new Comparator() {
|
|
472 public int compare(Object o1, Object o2) {
|
|
473 return o1.toString().compareTo(o2.toString());
|
|
474 }
|
|
475 });
|
|
476 for (int i = 0; i < keys.length; i++) {
|
|
477 out.print(" ");
|
|
478 out.println(((Command)commands.get(keys[i])).usage);
|
|
479 }
|
|
480 }
|
|
481 }
|
|
482 },
|
|
483 new Command("history", "history", true) {
|
|
484 public void doit(Tokens t) {
|
|
485 int tokens = t.countTokens();
|
|
486 if (tokens != 0 && (tokens != 1 || !t.nextToken().equals("-h"))) {
|
|
487 usage();
|
|
488 return;
|
|
489 }
|
|
490 boolean printIndex = tokens == 0;
|
|
491 for (int i = 0; i < history.size(); i++) {
|
|
492 if (printIndex) out.print(i + " ");
|
|
493 out.println(history.get(i));
|
|
494 }
|
|
495 }
|
|
496 },
|
|
497 new Command("inspect", "inspect expression", false) {
|
|
498 public void doit(Tokens t) {
|
|
499 if (t.countTokens() != 1) {
|
|
500 usage();
|
|
501 } else {
|
|
502 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
|
|
503 SimpleTreeNode node = null;
|
|
504 if (VM.getVM().getUniverse().heap().isInReserved(a)) {
|
|
505 OopHandle handle = a.addOffsetToAsOopHandle(0);
|
|
506 Oop oop = VM.getVM().getObjectHeap().newOop(handle);
|
|
507 node = new OopTreeNodeAdapter(oop, null);
|
|
508
|
|
509 out.println("instance of " + node.getValue() + " @ " + a +
|
|
510 " (size = " + oop.getObjectSize() + ")");
|
|
511 } else if (VM.getVM().getCodeCache().contains(a)) {
|
|
512 CodeBlob blob = VM.getVM().getCodeCache().findBlobUnsafe(a);
|
|
513 a = blob.headerBegin();
|
|
514 }
|
|
515 if (node == null) {
|
|
516 Type type = VM.getVM().getTypeDataBase().guessTypeForAddress(a);
|
|
517 if (type != null) {
|
|
518 out.println("Type is " + type.getName() + " (size of " + type.getSize() + ")");
|
|
519 node = new CTypeTreeNodeAdapter(a, type, null);
|
|
520 }
|
|
521 }
|
|
522 if (node != null) {
|
|
523 printNode(node);
|
|
524 }
|
|
525 }
|
|
526 }
|
|
527 },
|
|
528 new Command("jhisto", "jhisto", false) {
|
|
529 public void doit(Tokens t) {
|
|
530 ObjectHistogram histo = new ObjectHistogram();
|
|
531 histo.run(out, err);
|
|
532 }
|
|
533 },
|
|
534 new Command("jstack", "jstack [-v]", false) {
|
|
535 public void doit(Tokens t) {
|
|
536 boolean verbose = false;
|
|
537 if (t.countTokens() > 0 && t.nextToken().equals("-v")) {
|
|
538 verbose = true;
|
|
539 }
|
|
540 StackTrace jstack = new StackTrace(verbose, true);
|
|
541 jstack.run(out);
|
|
542 }
|
|
543 },
|
|
544 new Command("print", "print expression", false) {
|
|
545 public void doit(Tokens t) {
|
|
546 if (t.countTokens() != 1) {
|
|
547 usage();
|
|
548 } else {
|
|
549 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
|
|
550 HTMLGenerator gen = new HTMLGenerator(false);
|
|
551 out.println(gen.genHTML(a));
|
|
552 }
|
|
553 }
|
|
554 },
|
|
555 new Command("printas", "printas type expression", false) {
|
|
556 public void doit(Tokens t) {
|
|
557 if (t.countTokens() != 2) {
|
|
558 usage();
|
|
559 } else {
|
|
560 Type type = agent.getTypeDataBase().lookupType(t.nextToken());
|
|
561 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
|
|
562 CTypeTreeNodeAdapter node = new CTypeTreeNodeAdapter(a, type, null);
|
|
563
|
|
564 out.println("pointer to " + type + " @ " + a +
|
|
565 " (size = " + type.getSize() + ")");
|
|
566 printNode(node);
|
|
567 }
|
|
568 }
|
|
569 },
|
|
570 new Command("symbol", "symbol name", false) {
|
|
571 public void doit(Tokens t) {
|
|
572 if (t.countTokens() != 1) {
|
|
573 usage();
|
|
574 } else {
|
|
575 String symbol = t.nextToken();
|
|
576 Address a = lookup(symbol);
|
|
577 out.println(symbol + " = " + a);
|
|
578 }
|
|
579 }
|
|
580 },
|
|
581 new Command("printstatics", "printstatics [ type ]", false) {
|
|
582 public void doit(Tokens t) {
|
|
583 if (t.countTokens() > 1) {
|
|
584 usage();
|
|
585 } else {
|
|
586 if (t.countTokens() == 0) {
|
|
587 out.println("All known static fields");
|
|
588 printNode(new CTypeTreeNodeAdapter(agent.getTypeDataBase().getTypes()));
|
|
589 } else {
|
|
590 Type type = agent.getTypeDataBase().lookupType(t.nextToken());
|
|
591 out.println("Static fields of " + type.getName());
|
|
592 printNode(new CTypeTreeNodeAdapter(type));
|
|
593 }
|
|
594 }
|
|
595 }
|
|
596 },
|
|
597 new Command("pmap", "pmap", false) {
|
|
598 public void doit(Tokens t) {
|
|
599 PMap pmap = new PMap();
|
|
600 pmap.run(out, debugger.getAgent().getDebugger());
|
|
601 }
|
|
602 },
|
|
603 new Command("pstack", "pstack [-v]", false) {
|
|
604 public void doit(Tokens t) {
|
|
605 boolean verbose = false;
|
|
606 if (t.countTokens() > 0 && t.nextToken().equals("-v")) {
|
|
607 verbose = true;
|
|
608 }
|
|
609 PStack pstack = new PStack(verbose, true);
|
|
610 pstack.run(out, debugger.getAgent().getDebugger());
|
|
611 }
|
|
612 },
|
|
613 new Command("quit", true) {
|
|
614 public void doit(Tokens t) {
|
|
615 if (t.countTokens() != 0) {
|
|
616 usage();
|
|
617 } else {
|
|
618 debugger.detach();
|
|
619 System.exit(0);
|
|
620 }
|
|
621 }
|
|
622 },
|
|
623 new Command("echo", "echo [ true | false ]", true) {
|
|
624 public void doit(Tokens t) {
|
|
625 if (t.countTokens() == 0) {
|
|
626 out.println("echo is " + doEcho);
|
|
627 } else if (t.countTokens() == 1) {
|
|
628 doEcho = Boolean.valueOf(t.nextToken()).booleanValue();
|
|
629 } else {
|
|
630 usage();
|
|
631 }
|
|
632 }
|
|
633 },
|
|
634 new Command("versioncheck", "versioncheck [ true | false ]", true) {
|
|
635 public void doit(Tokens t) {
|
|
636 if (t.countTokens() == 0) {
|
|
637 out.println("versioncheck is " +
|
|
638 (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null));
|
|
639 } else if (t.countTokens() == 1) {
|
|
640 if (Boolean.valueOf(t.nextToken()).booleanValue()) {
|
|
641 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", null);
|
|
642 } else {
|
|
643 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", "true");
|
|
644 }
|
|
645 } else {
|
|
646 usage();
|
|
647 }
|
|
648 }
|
|
649 },
|
|
650 new Command("scanoops", "scanoops start end [ type ]", false) {
|
|
651 public void doit(Tokens t) {
|
|
652 if (t.countTokens() != 2 && t.countTokens() != 3) {
|
|
653 usage();
|
|
654 } else {
|
|
655 long stride = VM.getVM().getAddressSize();
|
|
656 Address base = VM.getVM().getDebugger().parseAddress(t.nextToken());
|
|
657 Address end = VM.getVM().getDebugger().parseAddress(t.nextToken());
|
|
658 Klass klass = null;
|
|
659 if (t.countTokens() == 1) {
|
|
660 klass = SystemDictionaryHelper.findInstanceKlass(t.nextToken());
|
|
661 }
|
|
662 while (base != null && base.lessThan(end)) {
|
|
663 long step = stride;
|
|
664 OopHandle handle = base.addOffsetToAsOopHandle(0);
|
|
665 if (RobustOopDeterminator.oopLooksValid(handle)) {
|
|
666 try {
|
|
667 Oop oop = VM.getVM().getObjectHeap().newOop(handle);
|
|
668 if (klass == null || oop.getKlass().isSubtypeOf(klass))
|
|
669 out.println(handle.toString() + " " + oop.getKlass().getName().asString());
|
|
670 step = oop.getObjectSize();
|
|
671 } catch (UnknownOopException ex) {
|
|
672 // ok
|
|
673 } catch (RuntimeException ex) {
|
|
674 ex.printStackTrace();
|
|
675 }
|
|
676 }
|
|
677 base = base.addOffsetTo(step);
|
|
678 }
|
|
679 }
|
|
680 }
|
|
681 },
|
|
682 new Command("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) {
|
|
683 public void doit(Tokens t) {
|
|
684 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) {
|
|
685 usage();
|
|
686 return;
|
|
687 }
|
|
688 if (t.countTokens() == 1) {
|
|
689 Type type = agent.getTypeDataBase().lookupType(t.nextToken());
|
|
690 dumpFields(type);
|
|
691 } else if (t.countTokens() == 0) {
|
|
692 Iterator i = agent.getTypeDataBase().getTypes();
|
|
693 while (i.hasNext()) {
|
|
694 dumpFields((Type)i.next());
|
|
695 }
|
|
696 } else {
|
|
697 BasicType containingType = (BasicType)agent.getTypeDataBase().lookupType(t.nextToken());
|
|
698
|
|
699 String fieldName = t.nextToken();
|
|
700
|
|
701 // The field's Type must already be in the database -- no exceptions
|
|
702 Type fieldType = agent.getTypeDataBase().lookupType(t.nextToken());
|
|
703
|
|
704 boolean isStatic = Boolean.valueOf(t.nextToken()).booleanValue();
|
|
705 long offset = Long.parseLong(t.nextToken());
|
|
706 Address staticAddress = parseAddress(t.nextToken());
|
|
707 if (isStatic && staticAddress == null) {
|
|
708 staticAddress = lookup(containingType.getName() + "::" + fieldName);
|
|
709 }
|
|
710
|
|
711 // check to see if the field already exists
|
|
712 Iterator i = containingType.getFields();
|
|
713 while (i.hasNext()) {
|
|
714 Field f = (Field) i.next();
|
|
715 if (f.getName().equals(fieldName)) {
|
|
716 if (f.isStatic() != isStatic) {
|
|
717 throw new RuntimeException("static/nonstatic mismatch: " + t.input);
|
|
718 }
|
|
719 if (!isStatic) {
|
|
720 if (f.getOffset() != offset) {
|
|
721 throw new RuntimeException("bad redefinition of field offset: " + t.input);
|
|
722 }
|
|
723 } else {
|
|
724 if (!f.getStaticFieldAddress().equals(staticAddress)) {
|
|
725 throw new RuntimeException("bad redefinition of field location: " + t.input);
|
|
726 }
|
|
727 }
|
|
728 if (f.getType() != fieldType) {
|
|
729 throw new RuntimeException("bad redefinition of field type: " + t.input);
|
|
730 }
|
|
731 return;
|
|
732 }
|
|
733 }
|
|
734
|
|
735 // Create field by type
|
|
736 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
|
|
737 db.createField(containingType,
|
|
738 fieldName, fieldType,
|
|
739 isStatic,
|
|
740 offset,
|
|
741 staticAddress);
|
|
742
|
|
743 }
|
|
744 }
|
|
745
|
|
746 },
|
|
747 new Command("tokenize", "tokenize ...", true) {
|
|
748 public void doit(Tokens t) {
|
|
749 while (t.hasMoreTokens()) {
|
|
750 out.println("\"" + t.nextToken() + "\"");
|
|
751 }
|
|
752 }
|
|
753 },
|
|
754 new Command("type", "type [ type [ name super isOop isInteger isUnsigned size ] ]", true) {
|
|
755 public void doit(Tokens t) {
|
|
756 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) {
|
|
757 usage();
|
|
758 return;
|
|
759 }
|
|
760 if (t.countTokens() == 6) {
|
|
761 String typeName = t.nextToken();
|
|
762 String superclassName = t.nextToken();
|
|
763 if (superclassName.equals("null")) {
|
|
764 superclassName = null;
|
|
765 }
|
|
766 boolean isOop = Boolean.valueOf(t.nextToken()).booleanValue();
|
|
767 boolean isInteger = Boolean.valueOf(t.nextToken()).booleanValue();
|
|
768 boolean isUnsigned = Boolean.valueOf(t.nextToken()).booleanValue();
|
|
769 long size = Long.parseLong(t.nextToken());
|
|
770
|
|
771 BasicType type = null;
|
|
772 try {
|
|
773 type = (BasicType)agent.getTypeDataBase().lookupType(typeName);
|
|
774 } catch (RuntimeException e) {
|
|
775 }
|
|
776 if (type != null) {
|
|
777 if (type.isOopType() != isOop) {
|
|
778 throw new RuntimeException("oop mismatch in type definition: " + t.input);
|
|
779 }
|
|
780 if (type.isCIntegerType() != isInteger) {
|
|
781 throw new RuntimeException("integer type mismatch in type definition: " + t.input);
|
|
782 }
|
|
783 if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) {
|
|
784 throw new RuntimeException("unsigned mismatch in type definition: " + t.input);
|
|
785 }
|
|
786 if (type.getSuperclass() == null) {
|
|
787 if (superclassName != null) {
|
|
788 if (type.getSize() == -1) {
|
|
789 type.setSuperclass(agent.getTypeDataBase().lookupType(superclassName));
|
|
790 } else {
|
|
791 throw new RuntimeException("unexpected superclass in type definition: " + t.input);
|
|
792 }
|
|
793 }
|
|
794 } else {
|
|
795 if (superclassName == null) {
|
|
796 throw new RuntimeException("missing superclass in type definition: " + t.input);
|
|
797 }
|
|
798 if (!type.getSuperclass().getName().equals(superclassName)) {
|
|
799 throw new RuntimeException("incorrect superclass in type definition: " + t.input);
|
|
800 }
|
|
801 }
|
|
802 if (type.getSize() != size) {
|
|
803 if (type.getSize() == -1) {
|
|
804 type.setSize(size);
|
|
805 }
|
|
806 throw new RuntimeException("size mismatch in type definition: " + t.input);
|
|
807 }
|
|
808 return;
|
|
809 }
|
|
810
|
|
811 // Create type
|
|
812 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
|
|
813 db.createType(typeName, superclassName, isOop, isInteger, isUnsigned, size);
|
|
814 } else if (t.countTokens() == 1) {
|
|
815 Type type = agent.getTypeDataBase().lookupType(t.nextToken());
|
|
816 dumpType(type);
|
|
817 } else {
|
|
818 Iterator i = agent.getTypeDataBase().getTypes();
|
|
819 while (i.hasNext()) {
|
|
820 dumpType((Type)i.next());
|
|
821 }
|
|
822 }
|
|
823 }
|
|
824
|
|
825 },
|
|
826 new Command("source", "source filename", true) {
|
|
827 public void doit(Tokens t) {
|
|
828 if (t.countTokens() != 1) {
|
|
829 usage();
|
|
830 return;
|
|
831 }
|
|
832 String file = t.nextToken();
|
|
833 BufferedReader savedInput = in;
|
|
834 try {
|
|
835 BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
|
|
836 in = input;
|
|
837 run(false);
|
|
838 } catch (Exception e) {
|
|
839 out.println("Error: " + e);
|
|
840 if (verboseExceptions) {
|
|
841 e.printStackTrace(out);
|
|
842 }
|
|
843 } finally {
|
|
844 in = savedInput;
|
|
845 }
|
|
846
|
|
847 }
|
|
848 },
|
|
849 new Command("search", "search [ heap | codecache | threads ] value", false) {
|
|
850 public void doit(Tokens t) {
|
|
851 if (t.countTokens() != 2) {
|
|
852 usage();
|
|
853 } else {
|
|
854 String type = t.nextToken();
|
|
855 final Address value = VM.getVM().getDebugger().parseAddress(t.nextToken());
|
|
856 final long stride = VM.getVM().getAddressSize();
|
|
857 if (type.equals("threads")) {
|
|
858 Threads threads = VM.getVM().getThreads();
|
|
859 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
|
860 Address base = thread.getBaseOfStackPointer();
|
|
861 Address end = thread.getLastJavaSP();
|
|
862 if (end == null) continue;
|
|
863 if (end.lessThan(base)) {
|
|
864 Address tmp = base;
|
|
865 base = end;
|
|
866 end = tmp;
|
|
867 }
|
|
868 out.println("Searching " + base + " " + end);
|
|
869 while (base != null && base.lessThan(end)) {
|
|
870 Address val = base.getAddressAt(0);
|
|
871 if (AddressOps.equal(val, value)) {
|
|
872 out.println(base);
|
|
873 }
|
|
874 base = base.addOffsetTo(stride);
|
|
875 }
|
|
876 }
|
|
877 } else if (type.equals("heap")) {
|
|
878 RawHeapVisitor iterator = new RawHeapVisitor() {
|
|
879 public void prologue(long used) {
|
|
880 }
|
|
881
|
|
882 public void visitAddress(Address addr) {
|
|
883 Address val = addr.getAddressAt(0);
|
|
884 if (AddressOps.equal(val, value)) {
|
|
885 out.println("found at " + addr);
|
|
886 }
|
|
887 }
|
|
888
|
|
889 public void epilogue() {
|
|
890 }
|
|
891 };
|
|
892 VM.getVM().getObjectHeap().iterateRaw(iterator);
|
|
893 } else if (type.equals("codecache")) {
|
|
894 CodeCacheVisitor v = new CodeCacheVisitor() {
|
|
895 public void prologue(Address start, Address end) {
|
|
896 }
|
|
897 public void visit(CodeBlob blob) {
|
|
898 boolean printed = false;
|
|
899 Address base = blob.getAddress();
|
|
900 Address end = base.addOffsetTo(blob.getSize());
|
|
901 while (base != null && base.lessThan(end)) {
|
|
902 Address val = base.getAddressAt(0);
|
|
903 if (AddressOps.equal(val, value)) {
|
|
904 if (!printed) {
|
|
905 printed = true;
|
|
906 blob.printOn(out);
|
|
907 }
|
|
908 out.println("found at " + base + "\n");
|
|
909 }
|
|
910 base = base.addOffsetTo(stride);
|
|
911 }
|
|
912 }
|
|
913 public void epilogue() {
|
|
914 }
|
|
915
|
|
916
|
|
917 };
|
|
918 VM.getVM().getCodeCache().iterate(v);
|
|
919
|
|
920 }
|
|
921 }
|
|
922 }
|
|
923 },
|
|
924 new Command("where", "where { -a | id }", false) {
|
|
925 public void doit(Tokens t) {
|
|
926 if (t.countTokens() != 1) {
|
|
927 usage();
|
|
928 } else {
|
|
929 String name = t.nextToken();
|
|
930 Threads threads = VM.getVM().getThreads();
|
|
931 boolean all = name.equals("-a");
|
|
932 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
|
933 StringWriter sw = new StringWriter();
|
|
934 ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
935 thread.printThreadIDOn(new PrintStream(bos));
|
|
936 if (all || bos.toString().equals(name)) {
|
|
937 HTMLGenerator gen = new HTMLGenerator(false);
|
|
938 out.println(gen.genHTMLForJavaStackTrace(thread));
|
|
939 if (!all) return;
|
|
940 }
|
|
941 }
|
|
942 if (!all) out.println("Couldn't find thread " + name);
|
|
943 }
|
|
944 }
|
|
945 },
|
|
946
|
|
947 new Command("threads", false) {
|
|
948 public void doit(Tokens t) {
|
|
949 if (t.countTokens() != 0) {
|
|
950 usage();
|
|
951 } else {
|
|
952 Threads threads = VM.getVM().getThreads();
|
|
953 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
|
954 thread.printThreadIDOn(out);
|
|
955 out.println(" " + thread.getThreadName());
|
|
956 }
|
|
957 }
|
|
958 }
|
|
959 },
|
|
960
|
|
961 new Command("livenmethods", false) {
|
|
962 public void doit(Tokens t) {
|
|
963 if (t.countTokens() != 0) {
|
|
964 usage();
|
|
965 } else {
|
|
966 ArrayList nmethods = new ArrayList();
|
|
967 Threads threads = VM.getVM().getThreads();
|
|
968 HTMLGenerator gen = new HTMLGenerator(false);
|
|
969 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
|
970 try {
|
|
971 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
|
|
972 if (vf instanceof CompiledVFrame) {
|
|
973 NMethod c = ((CompiledVFrame)vf).getCode();
|
|
974 if (!nmethods.contains(c)) {
|
|
975 nmethods.add(c);
|
|
976 out.println(gen.genHTML(c));
|
|
977 }
|
|
978 }
|
|
979 }
|
|
980 } catch (Exception e) {
|
|
981 e.printStackTrace();
|
|
982 }
|
|
983 }
|
|
984 }
|
|
985 }
|
|
986 },
|
|
987 new Command("universe", false) {
|
|
988 public void doit(Tokens t) {
|
|
989 if (t.countTokens() != 0) {
|
|
990 usage();
|
|
991 } else {
|
|
992 Universe u = VM.getVM().getUniverse();
|
|
993 out.println("Heap Parameters:");
|
|
994 u.heap().printOn(out);
|
|
995 }
|
|
996 }
|
|
997 },
|
|
998 new Command("verbose", "verbose true | false", true) {
|
|
999 public void doit(Tokens t) {
|
|
1000 if (t.countTokens() != 1) {
|
|
1001 usage();
|
|
1002 } else {
|
|
1003 verboseExceptions = Boolean.valueOf(t.nextToken()).booleanValue();
|
|
1004 }
|
|
1005 }
|
|
1006 },
|
|
1007 new Command("assert", "assert true | false", true) {
|
|
1008 public void doit(Tokens t) {
|
|
1009 if (t.countTokens() != 1) {
|
|
1010 usage();
|
|
1011 } else {
|
|
1012 Assert.ASSERTS_ENABLED = Boolean.valueOf(t.nextToken()).booleanValue();
|
|
1013 }
|
|
1014 }
|
|
1015 },
|
|
1016 };
|
|
1017
|
|
1018 private boolean verboseExceptions = false;
|
|
1019 private ArrayList history = new ArrayList();
|
|
1020 private HashMap commands = new HashMap();
|
|
1021 private boolean doEcho = false;
|
|
1022
|
|
1023 private Command findCommand(String key) {
|
|
1024 return (Command)commands.get(key);
|
|
1025 }
|
|
1026
|
|
1027 public void printPrompt() {
|
|
1028 out.print("hsdb> ");
|
|
1029 }
|
|
1030
|
|
1031 private DebuggerInterface debugger;
|
|
1032 private HotSpotAgent agent;
|
|
1033 private JSJavaScriptEngine jsengine;
|
|
1034 private BufferedReader in;
|
|
1035 private PrintStream out;
|
|
1036 private PrintStream err;
|
|
1037
|
|
1038 // called before debuggee attach
|
|
1039 private void preAttach() {
|
|
1040 // nothing for now..
|
|
1041 }
|
|
1042
|
|
1043 // called after debuggee attach
|
|
1044 private void postAttach() {
|
|
1045 // create JavaScript engine and start it
|
|
1046 jsengine = new JSJavaScriptEngine() {
|
|
1047 private ObjectReader reader = new ObjectReader();
|
|
1048 private JSJavaFactory factory = new JSJavaFactoryImpl();
|
|
1049 public ObjectReader getObjectReader() {
|
|
1050 return reader;
|
|
1051 }
|
|
1052 public JSJavaFactory getJSJavaFactory() {
|
|
1053 return factory;
|
|
1054 }
|
|
1055 protected void quit() {
|
|
1056 debugger.detach();
|
|
1057 System.exit(0);
|
|
1058 }
|
|
1059 protected BufferedReader getInputReader() {
|
|
1060 return in;
|
|
1061 }
|
|
1062 protected PrintStream getOutputStream() {
|
|
1063 return out;
|
|
1064 }
|
|
1065 protected PrintStream getErrorStream() {
|
|
1066 return err;
|
|
1067 }
|
|
1068 };
|
|
1069 try {
|
|
1070 jsengine.defineFunction(this,
|
|
1071 this.getClass().getMethod("registerCommand",
|
|
1072 new Class[] {
|
|
1073 String.class, String.class, String.class
|
|
1074 }));
|
|
1075 } catch (NoSuchMethodException exp) {
|
|
1076 // should not happen, see below...!!
|
|
1077 exp.printStackTrace();
|
|
1078 }
|
|
1079 jsengine.start();
|
|
1080 }
|
|
1081
|
|
1082 public void registerCommand(String cmd, String usage, final String func) {
|
|
1083 commands.put(cmd, new Command(cmd, usage, false) {
|
|
1084 public void doit(Tokens t) {
|
|
1085 final int len = t.countTokens();
|
|
1086 Object[] args = new Object[len];
|
|
1087 for (int i = 0; i < len; i++) {
|
|
1088 args[i] = t.nextToken();
|
|
1089 }
|
|
1090 jsengine.call(func, args);
|
|
1091 }
|
|
1092 });
|
|
1093 }
|
|
1094
|
|
1095 public void setOutput(PrintStream o) {
|
|
1096 out = o;
|
|
1097 }
|
|
1098
|
|
1099 public void setErr(PrintStream e) {
|
|
1100 err = e;
|
|
1101 }
|
|
1102
|
|
1103 public CommandProcessor(DebuggerInterface debugger, BufferedReader in, PrintStream out, PrintStream err) {
|
|
1104 this.debugger = debugger;
|
|
1105 this.agent = debugger.getAgent();
|
|
1106 this.in = in;
|
|
1107 this.out = out;
|
|
1108 this.err = err;
|
|
1109 for (int i = 0; i < commandList.length; i++) {
|
|
1110 Command c = commandList[i];
|
|
1111 commands.put(c.name, c);
|
|
1112 }
|
|
1113 if (debugger.isAttached()) {
|
|
1114 postAttach();
|
|
1115 }
|
|
1116 }
|
|
1117
|
|
1118
|
|
1119 public void run(boolean prompt) {
|
|
1120 // Process interactive commands.
|
|
1121 while (true) {
|
|
1122 if (prompt) printPrompt();
|
|
1123 String ln = null;
|
|
1124 try {
|
|
1125 ln = in.readLine();
|
|
1126 } catch (IOException e) {
|
|
1127 }
|
|
1128 if (ln == null) {
|
|
1129 if (prompt) err.println("Input stream closed.");
|
|
1130 return;
|
|
1131 }
|
|
1132
|
|
1133 executeCommand(ln);
|
|
1134 }
|
|
1135 }
|
|
1136
|
|
1137 static Pattern historyPattern = Pattern.compile("((!\\*)|(!\\$)|(!!-?)|(!-?[0-9][0-9]*))");
|
|
1138
|
|
1139 public void executeCommand(String ln) {
|
|
1140 if (ln.indexOf('!') != -1) {
|
|
1141 int size = history.size();
|
|
1142 if (size == 0) {
|
|
1143 ln = "";
|
|
1144 err.println("History is empty");
|
|
1145 } else {
|
|
1146 StringBuffer result = new StringBuffer();
|
|
1147 Matcher m = historyPattern.matcher(ln);
|
|
1148 int start = 0;
|
|
1149 while (m.find()) {
|
|
1150 if (m.start() > start) {
|
|
1151 result.append(ln.substring(start, m.start() - start));
|
|
1152 }
|
|
1153 start = m.end();
|
|
1154
|
|
1155 String cmd = m.group();
|
|
1156 if (cmd.equals("!!")) {
|
|
1157 result.append((String)history.get(history.size() - 1));
|
|
1158 } else if (cmd.equals("!!-")) {
|
|
1159 Tokens item = new Tokens((String)history.get(history.size() - 1));
|
|
1160 item.trim(1);
|
|
1161 result.append(item.join(" "));
|
|
1162 } else if (cmd.equals("!*")) {
|
|
1163 Tokens item = new Tokens((String)history.get(history.size() - 1));
|
|
1164 item.nextToken();
|
|
1165 result.append(item.join(" "));
|
|
1166 } else if (cmd.equals("!$")) {
|
|
1167 Tokens item = new Tokens((String)history.get(history.size() - 1));
|
|
1168 result.append(item.at(item.countTokens() - 1));
|
|
1169 } else {
|
|
1170 String tail = cmd.substring(1);
|
|
1171 int index = Integer.parseInt(tail);
|
|
1172 if (index < 0) {
|
|
1173 index = history.size() + index;
|
|
1174 }
|
|
1175 if (index > size) {
|
|
1176 err.println("No such history item");
|
|
1177 } else {
|
|
1178 result.append((String)history.get(index));
|
|
1179 }
|
|
1180 }
|
|
1181 }
|
|
1182 if (result.length() == 0) {
|
|
1183 err.println("malformed history reference");
|
|
1184 ln = "";
|
|
1185 } else {
|
|
1186 if (start < ln.length()) {
|
|
1187 result.append(ln.substring(start));
|
|
1188 }
|
|
1189 ln = result.toString();
|
|
1190 if (!doEcho) {
|
|
1191 out.println(ln);
|
|
1192 }
|
|
1193 }
|
|
1194 }
|
|
1195 }
|
|
1196
|
|
1197 if (doEcho) {
|
|
1198 out.println("+ " + ln);
|
|
1199 }
|
|
1200
|
|
1201 PrintStream redirect = null;
|
|
1202 Tokens t = new Tokens(ln);
|
|
1203 if (t.hasMoreTokens()) {
|
|
1204 boolean error = false;
|
|
1205 history.add(ln);
|
|
1206 int len = t.countTokens();
|
|
1207 if (len > 2) {
|
|
1208 String r = t.at(len - 2);
|
|
1209 if (r.equals(">") || r.equals(">>")) {
|
|
1210 boolean append = r.length() == 2;
|
|
1211 String file = t.at(len - 1);
|
|
1212 try {
|
|
1213 redirect = new PrintStream(new BufferedOutputStream(new FileOutputStream(file, append)));
|
|
1214 t.trim(2);
|
|
1215 } catch (Exception e) {
|
|
1216 out.println("Error: " + e);
|
|
1217 if (verboseExceptions) {
|
|
1218 e.printStackTrace(out);
|
|
1219 }
|
|
1220 error = true;
|
|
1221 }
|
|
1222 }
|
|
1223 }
|
|
1224 if (!error) {
|
|
1225 PrintStream savedout = out;
|
|
1226 if (redirect != null) {
|
|
1227 out = redirect;
|
|
1228 }
|
|
1229 try {
|
|
1230 executeCommand(t);
|
|
1231 } catch (Exception e) {
|
|
1232 err.println("Error: " + e);
|
|
1233 if (verboseExceptions) {
|
|
1234 e.printStackTrace(err);
|
|
1235 }
|
|
1236 } finally {
|
|
1237 if (redirect != null) {
|
|
1238 out = savedout;
|
|
1239 redirect.close();
|
|
1240 }
|
|
1241 }
|
|
1242 }
|
|
1243 }
|
|
1244 }
|
|
1245
|
|
1246 void executeCommand(Tokens args) {
|
|
1247 String cmd = args.nextToken();
|
|
1248
|
|
1249 Command doit = findCommand(cmd);
|
|
1250
|
|
1251 /*
|
|
1252 * Check for an unknown command
|
|
1253 */
|
|
1254 if (doit == null) {
|
|
1255 out.println("Unrecognized command. Try help...");
|
|
1256 } else if (!debugger.isAttached() && !doit.okIfDisconnected) {
|
|
1257 out.println("Command not valid until the attached to a VM");
|
|
1258 } else {
|
|
1259 try {
|
|
1260 doit.doit(args);
|
|
1261 } catch (Exception e) {
|
|
1262 out.println("Error: " + e);
|
|
1263 if (verboseExceptions) {
|
|
1264 e.printStackTrace(out);
|
|
1265 }
|
|
1266 }
|
|
1267 }
|
|
1268 }
|
|
1269 }
|