Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java @ 2042:0a8e0d4345b3 hs20-b05 jdk7-b124
7010068: Update all 2010 Oracle-changed OpenJDK files to have the proper copyright dates - first pass
Summary: Update the copyright to be 2010 on all changed files in OpenJDK
Reviewed-by: jcoomes
author | trims |
---|---|
date | Mon, 03 Jan 2011 15:30:05 -0800 |
parents | 3e8fbc61cee8 |
children | 3582bf76420e |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1385
diff
changeset
|
2 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1385
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1385
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1385
diff
changeset
|
21 * questions. |
0 | 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 }, | |
1385 | 497 new Command("revptrs", "revptrs address", false) { |
498 public void doit(Tokens t) { | |
499 int tokens = t.countTokens(); | |
500 if (tokens != 1 && (tokens != 2 || !t.nextToken().equals("-c"))) { | |
501 usage(); | |
502 return; | |
503 } | |
504 boolean chase = tokens == 2; | |
505 ReversePtrs revptrs = VM.getVM().getRevPtrs(); | |
506 if (revptrs == null) { | |
507 out.println("Computing reverse pointers..."); | |
508 ReversePtrsAnalysis analysis = new ReversePtrsAnalysis(); | |
509 final boolean[] complete = new boolean[1]; | |
510 HeapProgressThunk thunk = new HeapProgressThunk() { | |
511 public void heapIterationFractionUpdate(double d) {} | |
512 public synchronized void heapIterationComplete() { | |
513 complete[0] = true; | |
514 notify(); | |
515 } | |
516 }; | |
517 analysis.setHeapProgressThunk(thunk); | |
518 analysis.run(); | |
519 while (!complete[0]) { | |
520 synchronized (thunk) { | |
521 try { | |
522 thunk.wait(); | |
523 } catch (Exception e) { | |
524 } | |
525 } | |
526 } | |
527 revptrs = VM.getVM().getRevPtrs(); | |
528 out.println("Done."); | |
529 } | |
530 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); | |
531 if (VM.getVM().getUniverse().heap().isInReserved(a)) { | |
532 OopHandle handle = a.addOffsetToAsOopHandle(0); | |
533 Oop oop = VM.getVM().getObjectHeap().newOop(handle); | |
534 ArrayList ptrs = revptrs.get(oop); | |
535 if (ptrs == null) { | |
536 out.println("no live references to " + a); | |
537 } else { | |
538 if (chase) { | |
539 while (ptrs.size() == 1) { | |
540 LivenessPathElement e = (LivenessPathElement)ptrs.get(0); | |
541 ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
542 Oop.printOopValueOn(e.getObj(), new PrintStream(bos)); | |
543 out.println(bos.toString()); | |
544 ptrs = revptrs.get(e.getObj()); | |
545 } | |
546 } else { | |
547 for (int i = 0; i < ptrs.size(); i++) { | |
548 LivenessPathElement e = (LivenessPathElement)ptrs.get(i); | |
549 ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
550 Oop.printOopValueOn(e.getObj(), new PrintStream(bos)); | |
551 out.println(bos.toString()); | |
552 oop = e.getObj(); | |
553 } | |
554 } | |
555 } | |
556 } | |
557 } | |
558 }, | |
0 | 559 new Command("inspect", "inspect expression", false) { |
560 public void doit(Tokens t) { | |
561 if (t.countTokens() != 1) { | |
562 usage(); | |
563 } else { | |
564 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); | |
565 SimpleTreeNode node = null; | |
566 if (VM.getVM().getUniverse().heap().isInReserved(a)) { | |
567 OopHandle handle = a.addOffsetToAsOopHandle(0); | |
568 Oop oop = VM.getVM().getObjectHeap().newOop(handle); | |
569 node = new OopTreeNodeAdapter(oop, null); | |
570 | |
571 out.println("instance of " + node.getValue() + " @ " + a + | |
572 " (size = " + oop.getObjectSize() + ")"); | |
573 } else if (VM.getVM().getCodeCache().contains(a)) { | |
574 CodeBlob blob = VM.getVM().getCodeCache().findBlobUnsafe(a); | |
575 a = blob.headerBegin(); | |
576 } | |
577 if (node == null) { | |
578 Type type = VM.getVM().getTypeDataBase().guessTypeForAddress(a); | |
579 if (type != null) { | |
580 out.println("Type is " + type.getName() + " (size of " + type.getSize() + ")"); | |
581 node = new CTypeTreeNodeAdapter(a, type, null); | |
582 } | |
583 } | |
584 if (node != null) { | |
585 printNode(node); | |
586 } | |
587 } | |
588 } | |
589 }, | |
590 new Command("jhisto", "jhisto", false) { | |
591 public void doit(Tokens t) { | |
592 ObjectHistogram histo = new ObjectHistogram(); | |
593 histo.run(out, err); | |
594 } | |
595 }, | |
596 new Command("jstack", "jstack [-v]", false) { | |
597 public void doit(Tokens t) { | |
598 boolean verbose = false; | |
599 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { | |
600 verbose = true; | |
601 } | |
602 StackTrace jstack = new StackTrace(verbose, true); | |
603 jstack.run(out); | |
604 } | |
605 }, | |
606 new Command("print", "print expression", false) { | |
607 public void doit(Tokens t) { | |
608 if (t.countTokens() != 1) { | |
609 usage(); | |
610 } else { | |
611 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); | |
612 HTMLGenerator gen = new HTMLGenerator(false); | |
613 out.println(gen.genHTML(a)); | |
614 } | |
615 } | |
616 }, | |
617 new Command("printas", "printas type expression", false) { | |
618 public void doit(Tokens t) { | |
619 if (t.countTokens() != 2) { | |
620 usage(); | |
621 } else { | |
622 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); | |
623 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken()); | |
624 CTypeTreeNodeAdapter node = new CTypeTreeNodeAdapter(a, type, null); | |
625 | |
626 out.println("pointer to " + type + " @ " + a + | |
627 " (size = " + type.getSize() + ")"); | |
628 printNode(node); | |
629 } | |
630 } | |
631 }, | |
632 new Command("symbol", "symbol name", false) { | |
633 public void doit(Tokens t) { | |
634 if (t.countTokens() != 1) { | |
635 usage(); | |
636 } else { | |
637 String symbol = t.nextToken(); | |
638 Address a = lookup(symbol); | |
639 out.println(symbol + " = " + a); | |
640 } | |
641 } | |
642 }, | |
643 new Command("printstatics", "printstatics [ type ]", false) { | |
644 public void doit(Tokens t) { | |
645 if (t.countTokens() > 1) { | |
646 usage(); | |
647 } else { | |
648 if (t.countTokens() == 0) { | |
649 out.println("All known static fields"); | |
650 printNode(new CTypeTreeNodeAdapter(agent.getTypeDataBase().getTypes())); | |
651 } else { | |
652 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); | |
653 out.println("Static fields of " + type.getName()); | |
654 printNode(new CTypeTreeNodeAdapter(type)); | |
655 } | |
656 } | |
657 } | |
658 }, | |
659 new Command("pmap", "pmap", false) { | |
660 public void doit(Tokens t) { | |
661 PMap pmap = new PMap(); | |
662 pmap.run(out, debugger.getAgent().getDebugger()); | |
663 } | |
664 }, | |
665 new Command("pstack", "pstack [-v]", false) { | |
666 public void doit(Tokens t) { | |
667 boolean verbose = false; | |
668 if (t.countTokens() > 0 && t.nextToken().equals("-v")) { | |
669 verbose = true; | |
670 } | |
671 PStack pstack = new PStack(verbose, true); | |
672 pstack.run(out, debugger.getAgent().getDebugger()); | |
673 } | |
674 }, | |
675 new Command("quit", true) { | |
676 public void doit(Tokens t) { | |
677 if (t.countTokens() != 0) { | |
678 usage(); | |
679 } else { | |
680 debugger.detach(); | |
681 System.exit(0); | |
682 } | |
683 } | |
684 }, | |
685 new Command("echo", "echo [ true | false ]", true) { | |
686 public void doit(Tokens t) { | |
687 if (t.countTokens() == 0) { | |
688 out.println("echo is " + doEcho); | |
689 } else if (t.countTokens() == 1) { | |
690 doEcho = Boolean.valueOf(t.nextToken()).booleanValue(); | |
691 } else { | |
692 usage(); | |
693 } | |
694 } | |
695 }, | |
696 new Command("versioncheck", "versioncheck [ true | false ]", true) { | |
697 public void doit(Tokens t) { | |
698 if (t.countTokens() == 0) { | |
699 out.println("versioncheck is " + | |
700 (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null)); | |
701 } else if (t.countTokens() == 1) { | |
702 if (Boolean.valueOf(t.nextToken()).booleanValue()) { | |
703 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", null); | |
704 } else { | |
705 System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", "true"); | |
706 } | |
707 } else { | |
708 usage(); | |
709 } | |
710 } | |
711 }, | |
712 new Command("scanoops", "scanoops start end [ type ]", false) { | |
713 public void doit(Tokens t) { | |
714 if (t.countTokens() != 2 && t.countTokens() != 3) { | |
715 usage(); | |
716 } else { | |
717 long stride = VM.getVM().getAddressSize(); | |
718 Address base = VM.getVM().getDebugger().parseAddress(t.nextToken()); | |
719 Address end = VM.getVM().getDebugger().parseAddress(t.nextToken()); | |
720 Klass klass = null; | |
721 if (t.countTokens() == 1) { | |
722 klass = SystemDictionaryHelper.findInstanceKlass(t.nextToken()); | |
723 } | |
724 while (base != null && base.lessThan(end)) { | |
725 long step = stride; | |
726 OopHandle handle = base.addOffsetToAsOopHandle(0); | |
727 if (RobustOopDeterminator.oopLooksValid(handle)) { | |
728 try { | |
729 Oop oop = VM.getVM().getObjectHeap().newOop(handle); | |
730 if (klass == null || oop.getKlass().isSubtypeOf(klass)) | |
731 out.println(handle.toString() + " " + oop.getKlass().getName().asString()); | |
732 step = oop.getObjectSize(); | |
733 } catch (UnknownOopException ex) { | |
734 // ok | |
735 } catch (RuntimeException ex) { | |
736 ex.printStackTrace(); | |
737 } | |
738 } | |
739 base = base.addOffsetTo(step); | |
740 } | |
741 } | |
742 } | |
743 }, | |
744 new Command("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) { | |
745 public void doit(Tokens t) { | |
746 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { | |
747 usage(); | |
748 return; | |
749 } | |
750 if (t.countTokens() == 1) { | |
751 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); | |
752 dumpFields(type); | |
753 } else if (t.countTokens() == 0) { | |
754 Iterator i = agent.getTypeDataBase().getTypes(); | |
755 while (i.hasNext()) { | |
756 dumpFields((Type)i.next()); | |
757 } | |
758 } else { | |
759 BasicType containingType = (BasicType)agent.getTypeDataBase().lookupType(t.nextToken()); | |
760 | |
761 String fieldName = t.nextToken(); | |
762 | |
763 // The field's Type must already be in the database -- no exceptions | |
764 Type fieldType = agent.getTypeDataBase().lookupType(t.nextToken()); | |
765 | |
766 boolean isStatic = Boolean.valueOf(t.nextToken()).booleanValue(); | |
767 long offset = Long.parseLong(t.nextToken()); | |
768 Address staticAddress = parseAddress(t.nextToken()); | |
769 if (isStatic && staticAddress == null) { | |
770 staticAddress = lookup(containingType.getName() + "::" + fieldName); | |
771 } | |
772 | |
773 // check to see if the field already exists | |
774 Iterator i = containingType.getFields(); | |
775 while (i.hasNext()) { | |
776 Field f = (Field) i.next(); | |
777 if (f.getName().equals(fieldName)) { | |
778 if (f.isStatic() != isStatic) { | |
779 throw new RuntimeException("static/nonstatic mismatch: " + t.input); | |
780 } | |
781 if (!isStatic) { | |
782 if (f.getOffset() != offset) { | |
783 throw new RuntimeException("bad redefinition of field offset: " + t.input); | |
784 } | |
785 } else { | |
786 if (!f.getStaticFieldAddress().equals(staticAddress)) { | |
787 throw new RuntimeException("bad redefinition of field location: " + t.input); | |
788 } | |
789 } | |
790 if (f.getType() != fieldType) { | |
791 throw new RuntimeException("bad redefinition of field type: " + t.input); | |
792 } | |
793 return; | |
794 } | |
795 } | |
796 | |
797 // Create field by type | |
798 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); | |
799 db.createField(containingType, | |
800 fieldName, fieldType, | |
801 isStatic, | |
802 offset, | |
803 staticAddress); | |
804 | |
805 } | |
806 } | |
807 | |
808 }, | |
809 new Command("tokenize", "tokenize ...", true) { | |
810 public void doit(Tokens t) { | |
811 while (t.hasMoreTokens()) { | |
812 out.println("\"" + t.nextToken() + "\""); | |
813 } | |
814 } | |
815 }, | |
816 new Command("type", "type [ type [ name super isOop isInteger isUnsigned size ] ]", true) { | |
817 public void doit(Tokens t) { | |
818 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { | |
819 usage(); | |
820 return; | |
821 } | |
822 if (t.countTokens() == 6) { | |
823 String typeName = t.nextToken(); | |
824 String superclassName = t.nextToken(); | |
825 if (superclassName.equals("null")) { | |
826 superclassName = null; | |
827 } | |
828 boolean isOop = Boolean.valueOf(t.nextToken()).booleanValue(); | |
829 boolean isInteger = Boolean.valueOf(t.nextToken()).booleanValue(); | |
830 boolean isUnsigned = Boolean.valueOf(t.nextToken()).booleanValue(); | |
831 long size = Long.parseLong(t.nextToken()); | |
832 | |
833 BasicType type = null; | |
834 try { | |
835 type = (BasicType)agent.getTypeDataBase().lookupType(typeName); | |
836 } catch (RuntimeException e) { | |
837 } | |
838 if (type != null) { | |
839 if (type.isOopType() != isOop) { | |
840 throw new RuntimeException("oop mismatch in type definition: " + t.input); | |
841 } | |
842 if (type.isCIntegerType() != isInteger) { | |
843 throw new RuntimeException("integer type mismatch in type definition: " + t.input); | |
844 } | |
845 if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) { | |
846 throw new RuntimeException("unsigned mismatch in type definition: " + t.input); | |
847 } | |
848 if (type.getSuperclass() == null) { | |
849 if (superclassName != null) { | |
850 if (type.getSize() == -1) { | |
851 type.setSuperclass(agent.getTypeDataBase().lookupType(superclassName)); | |
852 } else { | |
853 throw new RuntimeException("unexpected superclass in type definition: " + t.input); | |
854 } | |
855 } | |
856 } else { | |
857 if (superclassName == null) { | |
858 throw new RuntimeException("missing superclass in type definition: " + t.input); | |
859 } | |
860 if (!type.getSuperclass().getName().equals(superclassName)) { | |
861 throw new RuntimeException("incorrect superclass in type definition: " + t.input); | |
862 } | |
863 } | |
864 if (type.getSize() != size) { | |
865 if (type.getSize() == -1) { | |
866 type.setSize(size); | |
867 } | |
868 throw new RuntimeException("size mismatch in type definition: " + t.input); | |
869 } | |
870 return; | |
871 } | |
872 | |
873 // Create type | |
874 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase(); | |
875 db.createType(typeName, superclassName, isOop, isInteger, isUnsigned, size); | |
876 } else if (t.countTokens() == 1) { | |
877 Type type = agent.getTypeDataBase().lookupType(t.nextToken()); | |
878 dumpType(type); | |
879 } else { | |
880 Iterator i = agent.getTypeDataBase().getTypes(); | |
1385 | 881 // Make sure the types are emitted in an order than can be read back in |
882 HashSet emitted = new HashSet(); | |
883 Stack pending = new Stack(); | |
0 | 884 while (i.hasNext()) { |
1385 | 885 Type n = (Type)i.next(); |
886 if (emitted.contains(n.getName())) { | |
887 continue; | |
888 } | |
889 | |
890 while (n != null && !emitted.contains(n.getName())) { | |
891 pending.push(n); | |
892 n = n.getSuperclass(); | |
893 } | |
894 while (!pending.empty()) { | |
895 n = (Type)pending.pop(); | |
896 dumpType(n); | |
897 emitted.add(n.getName()); | |
898 } | |
0 | 899 } |
900 } | |
901 } | |
902 | |
903 }, | |
904 new Command("source", "source filename", true) { | |
905 public void doit(Tokens t) { | |
906 if (t.countTokens() != 1) { | |
907 usage(); | |
908 return; | |
909 } | |
910 String file = t.nextToken(); | |
911 BufferedReader savedInput = in; | |
912 try { | |
913 BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(file))); | |
914 in = input; | |
915 run(false); | |
916 } catch (Exception e) { | |
917 out.println("Error: " + e); | |
918 if (verboseExceptions) { | |
919 e.printStackTrace(out); | |
920 } | |
921 } finally { | |
922 in = savedInput; | |
923 } | |
924 | |
925 } | |
926 }, | |
1385 | 927 new Command("search", "search [ heap | perm | rawheap | codecache | threads ] value", false) { |
0 | 928 public void doit(Tokens t) { |
929 if (t.countTokens() != 2) { | |
930 usage(); | |
1385 | 931 return; |
932 } | |
933 String type = t.nextToken(); | |
934 final Address value = VM.getVM().getDebugger().parseAddress(t.nextToken()); | |
935 final long stride = VM.getVM().getAddressSize(); | |
936 if (type.equals("threads")) { | |
937 Threads threads = VM.getVM().getThreads(); | |
938 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { | |
939 Address base = thread.getBaseOfStackPointer(); | |
940 Address end = thread.getLastJavaSP(); | |
941 if (end == null) continue; | |
942 if (end.lessThan(base)) { | |
943 Address tmp = base; | |
944 base = end; | |
945 end = tmp; | |
946 } | |
947 out.println("Searching " + base + " " + end); | |
948 while (base != null && base.lessThan(end)) { | |
949 Address val = base.getAddressAt(0); | |
950 if (AddressOps.equal(val, value)) { | |
951 out.println(base); | |
952 } | |
953 base = base.addOffsetTo(stride); | |
954 } | |
955 } | |
956 } else if (type.equals("rawheap")) { | |
957 RawHeapVisitor iterator = new RawHeapVisitor() { | |
958 public void prologue(long used) { | |
0 | 959 } |
1385 | 960 |
961 public void visitAddress(Address addr) { | |
962 Address val = addr.getAddressAt(0); | |
0 | 963 if (AddressOps.equal(val, value)) { |
1385 | 964 out.println("found at " + addr); |
0 | 965 } |
1385 | 966 } |
967 public void visitCompOopAddress(Address addr) { | |
968 Address val = addr.getCompOopAddressAt(0); | |
969 if (AddressOps.equal(val, value)) { | |
970 out.println("found at " + addr); | |
971 } | |
0 | 972 } |
1385 | 973 public void epilogue() { |
974 } | |
975 }; | |
976 VM.getVM().getObjectHeap().iterateRaw(iterator); | |
977 } else if (type.equals("heap") || type.equals("perm")) { | |
978 HeapVisitor iterator = new DefaultHeapVisitor() { | |
979 public boolean doObj(Oop obj) { | |
980 int index = 0; | |
981 Address start = obj.getHandle(); | |
982 long end = obj.getObjectSize(); | |
983 while (index < end) { | |
984 Address val = start.getAddressAt(index); | |
0 | 985 if (AddressOps.equal(val, value)) { |
1385 | 986 out.println("found in " + obj.getHandle()); |
987 break; | |
0 | 988 } |
1385 | 989 index += 4; |
0 | 990 } |
1385 | 991 return false; |
992 } | |
993 }; | |
994 if (type.equals("heap")) { | |
995 VM.getVM().getObjectHeap().iterate(iterator); | |
996 } else { | |
997 VM.getVM().getObjectHeap().iteratePerm(iterator); | |
998 } | |
999 } else if (type.equals("codecache")) { | |
1000 CodeCacheVisitor v = new CodeCacheVisitor() { | |
1001 public void prologue(Address start, Address end) { | |
1002 } | |
1003 public void visit(CodeBlob blob) { | |
1004 boolean printed = false; | |
1005 Address base = blob.getAddress(); | |
1006 Address end = base.addOffsetTo(blob.getSize()); | |
1007 while (base != null && base.lessThan(end)) { | |
1008 Address val = base.getAddressAt(0); | |
1009 if (AddressOps.equal(val, value)) { | |
1010 if (!printed) { | |
1011 printed = true; | |
1012 blob.printOn(out); | |
0 | 1013 } |
1385 | 1014 out.println("found at " + base + "\n"); |
0 | 1015 } |
1385 | 1016 base = base.addOffsetTo(stride); |
0 | 1017 } |
1385 | 1018 } |
1019 public void epilogue() { | |
1020 } | |
0 | 1021 |
1022 | |
1385 | 1023 }; |
1024 VM.getVM().getCodeCache().iterate(v); | |
0 | 1025 |
1026 } | |
1027 } | |
1028 }, | |
1040
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1029 new Command("dumpcodecache", "dumpcodecache", false) { |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1030 public void doit(Tokens t) { |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1031 if (t.countTokens() != 0) { |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1032 usage(); |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1033 } else { |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1034 final PrintStream fout = out; |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1035 final HTMLGenerator gen = new HTMLGenerator(false); |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1036 CodeCacheVisitor v = new CodeCacheVisitor() { |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1037 public void prologue(Address start, Address end) { |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1038 } |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1039 public void visit(CodeBlob blob) { |
1748 | 1040 fout.println(gen.genHTML(blob.contentBegin())); |
1040
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1041 } |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1042 public void epilogue() { |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1043 } |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1044 |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1045 |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1046 }; |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1047 VM.getVM().getCodeCache().iterate(v); |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1048 } |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1049 } |
873ec3787992
6892186: SA does not dump debug info for scalar replaced objects
kvn
parents:
196
diff
changeset
|
1050 }, |
0 | 1051 new Command("where", "where { -a | id }", false) { |
1052 public void doit(Tokens t) { | |
1053 if (t.countTokens() != 1) { | |
1054 usage(); | |
1055 } else { | |
1056 String name = t.nextToken(); | |
1057 Threads threads = VM.getVM().getThreads(); | |
1058 boolean all = name.equals("-a"); | |
1059 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { | |
1060 ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
1061 thread.printThreadIDOn(new PrintStream(bos)); | |
1062 if (all || bos.toString().equals(name)) { | |
1385 | 1063 out.println(bos.toString() + " = " + thread.getAddress()); |
0 | 1064 HTMLGenerator gen = new HTMLGenerator(false); |
1385 | 1065 try { |
1066 out.println(gen.genHTMLForJavaStackTrace(thread)); | |
1067 } catch (Exception e) { | |
1068 err.println("Error: " + e); | |
1069 if (verboseExceptions) { | |
1070 e.printStackTrace(err); | |
1071 } | |
1072 } | |
0 | 1073 if (!all) return; |
1074 } | |
1075 } | |
1076 if (!all) out.println("Couldn't find thread " + name); | |
1077 } | |
1078 } | |
1079 }, | |
1385 | 1080 new Command("thread", "thread { -a | id }", false) { |
1081 public void doit(Tokens t) { | |
1082 if (t.countTokens() != 1) { | |
1083 usage(); | |
1084 } else { | |
1085 String name = t.nextToken(); | |
1086 Threads threads = VM.getVM().getThreads(); | |
1087 boolean all = name.equals("-a"); | |
1088 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { | |
1089 ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
1090 thread.printThreadIDOn(new PrintStream(bos)); | |
1091 if (all || bos.toString().equals(name)) { | |
1092 out.println(bos.toString() + " = " + thread.getAddress()); | |
1093 if (!all) return; | |
1094 } | |
1095 } | |
1096 out.println("Couldn't find thread " + name); | |
1097 } | |
1098 } | |
1099 }, | |
0 | 1100 |
1101 new Command("threads", false) { | |
1102 public void doit(Tokens t) { | |
1103 if (t.countTokens() != 0) { | |
1104 usage(); | |
1105 } else { | |
1106 Threads threads = VM.getVM().getThreads(); | |
1107 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { | |
1108 thread.printThreadIDOn(out); | |
1109 out.println(" " + thread.getThreadName()); | |
1110 } | |
1111 } | |
1112 } | |
1113 }, | |
1114 | |
1115 new Command("livenmethods", false) { | |
1116 public void doit(Tokens t) { | |
1117 if (t.countTokens() != 0) { | |
1118 usage(); | |
1119 } else { | |
1120 ArrayList nmethods = new ArrayList(); | |
1121 Threads threads = VM.getVM().getThreads(); | |
1122 HTMLGenerator gen = new HTMLGenerator(false); | |
1123 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { | |
1124 try { | |
1125 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { | |
1126 if (vf instanceof CompiledVFrame) { | |
1127 NMethod c = ((CompiledVFrame)vf).getCode(); | |
1128 if (!nmethods.contains(c)) { | |
1129 nmethods.add(c); | |
1130 out.println(gen.genHTML(c)); | |
1131 } | |
1132 } | |
1133 } | |
1134 } catch (Exception e) { | |
1135 e.printStackTrace(); | |
1136 } | |
1137 } | |
1138 } | |
1139 } | |
1140 }, | |
1141 new Command("universe", false) { | |
1142 public void doit(Tokens t) { | |
1143 if (t.countTokens() != 0) { | |
1144 usage(); | |
1145 } else { | |
1146 Universe u = VM.getVM().getUniverse(); | |
1147 out.println("Heap Parameters:"); | |
1148 u.heap().printOn(out); | |
1149 } | |
1150 } | |
1151 }, | |
1152 new Command("verbose", "verbose true | false", true) { | |
1153 public void doit(Tokens t) { | |
1154 if (t.countTokens() != 1) { | |
1155 usage(); | |
1156 } else { | |
1157 verboseExceptions = Boolean.valueOf(t.nextToken()).booleanValue(); | |
1158 } | |
1159 } | |
1160 }, | |
1161 new Command("assert", "assert true | false", true) { | |
1162 public void doit(Tokens t) { | |
1163 if (t.countTokens() != 1) { | |
1164 usage(); | |
1165 } else { | |
1166 Assert.ASSERTS_ENABLED = Boolean.valueOf(t.nextToken()).booleanValue(); | |
1167 } | |
1168 } | |
1169 }, | |
1170 }; | |
1171 | |
1172 private boolean verboseExceptions = false; | |
1173 private ArrayList history = new ArrayList(); | |
1174 private HashMap commands = new HashMap(); | |
1175 private boolean doEcho = false; | |
1176 | |
1177 private Command findCommand(String key) { | |
1178 return (Command)commands.get(key); | |
1179 } | |
1180 | |
1181 public void printPrompt() { | |
1182 out.print("hsdb> "); | |
1183 } | |
1184 | |
1185 private DebuggerInterface debugger; | |
1186 private HotSpotAgent agent; | |
1187 private JSJavaScriptEngine jsengine; | |
1188 private BufferedReader in; | |
1189 private PrintStream out; | |
1190 private PrintStream err; | |
1191 | |
1192 // called before debuggee attach | |
1193 private void preAttach() { | |
1194 // nothing for now.. | |
1195 } | |
1196 | |
1197 // called after debuggee attach | |
1198 private void postAttach() { | |
1199 // create JavaScript engine and start it | |
1200 jsengine = new JSJavaScriptEngine() { | |
1201 private ObjectReader reader = new ObjectReader(); | |
1202 private JSJavaFactory factory = new JSJavaFactoryImpl(); | |
1203 public ObjectReader getObjectReader() { | |
1204 return reader; | |
1205 } | |
1206 public JSJavaFactory getJSJavaFactory() { | |
1207 return factory; | |
1208 } | |
1209 protected void quit() { | |
1210 debugger.detach(); | |
1211 System.exit(0); | |
1212 } | |
1213 protected BufferedReader getInputReader() { | |
1214 return in; | |
1215 } | |
1216 protected PrintStream getOutputStream() { | |
1217 return out; | |
1218 } | |
1219 protected PrintStream getErrorStream() { | |
1220 return err; | |
1221 } | |
1222 }; | |
1223 try { | |
1224 jsengine.defineFunction(this, | |
1225 this.getClass().getMethod("registerCommand", | |
1226 new Class[] { | |
1227 String.class, String.class, String.class | |
1228 })); | |
1229 } catch (NoSuchMethodException exp) { | |
1230 // should not happen, see below...!! | |
1231 exp.printStackTrace(); | |
1232 } | |
1233 jsengine.start(); | |
1234 } | |
1235 | |
1236 public void registerCommand(String cmd, String usage, final String func) { | |
1237 commands.put(cmd, new Command(cmd, usage, false) { | |
1238 public void doit(Tokens t) { | |
1239 final int len = t.countTokens(); | |
1240 Object[] args = new Object[len]; | |
1241 for (int i = 0; i < len; i++) { | |
1242 args[i] = t.nextToken(); | |
1243 } | |
1244 jsengine.call(func, args); | |
1245 } | |
1246 }); | |
1247 } | |
1248 | |
1249 public void setOutput(PrintStream o) { | |
1250 out = o; | |
1251 } | |
1252 | |
1253 public void setErr(PrintStream e) { | |
1254 err = e; | |
1255 } | |
1256 | |
1257 public CommandProcessor(DebuggerInterface debugger, BufferedReader in, PrintStream out, PrintStream err) { | |
1258 this.debugger = debugger; | |
1259 this.agent = debugger.getAgent(); | |
1260 this.in = in; | |
1261 this.out = out; | |
1262 this.err = err; | |
1263 for (int i = 0; i < commandList.length; i++) { | |
1264 Command c = commandList[i]; | |
1265 commands.put(c.name, c); | |
1266 } | |
1267 if (debugger.isAttached()) { | |
1268 postAttach(); | |
1269 } | |
1270 } | |
1271 | |
1272 | |
1273 public void run(boolean prompt) { | |
1274 // Process interactive commands. | |
1275 while (true) { | |
1276 if (prompt) printPrompt(); | |
1277 String ln = null; | |
1278 try { | |
1279 ln = in.readLine(); | |
1280 } catch (IOException e) { | |
1281 } | |
1282 if (ln == null) { | |
1283 if (prompt) err.println("Input stream closed."); | |
1284 return; | |
1285 } | |
1286 | |
1287 executeCommand(ln); | |
1288 } | |
1289 } | |
1290 | |
1385 | 1291 static Pattern historyPattern = Pattern.compile("((!\\*)|(!\\$)|(!!-?)|(!-?[0-9][0-9]*)|(![a-zA-Z][^ ]*))"); |
0 | 1292 |
1293 public void executeCommand(String ln) { | |
1294 if (ln.indexOf('!') != -1) { | |
1295 int size = history.size(); | |
1296 if (size == 0) { | |
1297 ln = ""; | |
1298 err.println("History is empty"); | |
1299 } else { | |
1300 StringBuffer result = new StringBuffer(); | |
1301 Matcher m = historyPattern.matcher(ln); | |
1302 int start = 0; | |
1303 while (m.find()) { | |
1304 if (m.start() > start) { | |
1305 result.append(ln.substring(start, m.start() - start)); | |
1306 } | |
1307 start = m.end(); | |
1308 | |
1309 String cmd = m.group(); | |
1310 if (cmd.equals("!!")) { | |
1311 result.append((String)history.get(history.size() - 1)); | |
1312 } else if (cmd.equals("!!-")) { | |
1313 Tokens item = new Tokens((String)history.get(history.size() - 1)); | |
1314 item.trim(1); | |
1315 result.append(item.join(" ")); | |
1316 } else if (cmd.equals("!*")) { | |
1317 Tokens item = new Tokens((String)history.get(history.size() - 1)); | |
1318 item.nextToken(); | |
1319 result.append(item.join(" ")); | |
1320 } else if (cmd.equals("!$")) { | |
1321 Tokens item = new Tokens((String)history.get(history.size() - 1)); | |
1322 result.append(item.at(item.countTokens() - 1)); | |
1323 } else { | |
1324 String tail = cmd.substring(1); | |
1385 | 1325 switch (tail.charAt(0)) { |
1326 case '0': | |
1327 case '1': | |
1328 case '2': | |
1329 case '3': | |
1330 case '4': | |
1331 case '5': | |
1332 case '6': | |
1333 case '7': | |
1334 case '8': | |
1335 case '9': | |
1336 case '-': { | |
1337 int index = Integer.parseInt(tail); | |
1338 if (index < 0) { | |
1339 index = history.size() + index; | |
1340 } | |
1341 if (index > size) { | |
1342 err.println("No such history item"); | |
1343 } else { | |
1344 result.append((String)history.get(index)); | |
1345 } | |
1346 break; | |
0 | 1347 } |
1385 | 1348 default: { |
1349 for (int i = history.size() - 1; i >= 0; i--) { | |
1350 String s = (String)history.get(i); | |
1351 if (s.startsWith(tail)) { | |
1352 result.append(s); | |
1353 } | |
1354 } | |
1355 } | |
0 | 1356 } |
1357 } | |
1358 } | |
1359 if (result.length() == 0) { | |
1360 err.println("malformed history reference"); | |
1361 ln = ""; | |
1362 } else { | |
1363 if (start < ln.length()) { | |
1364 result.append(ln.substring(start)); | |
1365 } | |
1366 ln = result.toString(); | |
1367 if (!doEcho) { | |
1368 out.println(ln); | |
1369 } | |
1370 } | |
1371 } | |
1372 } | |
1373 | |
1374 if (doEcho) { | |
1375 out.println("+ " + ln); | |
1376 } | |
1377 | |
1378 PrintStream redirect = null; | |
1379 Tokens t = new Tokens(ln); | |
1380 if (t.hasMoreTokens()) { | |
1381 boolean error = false; | |
1382 history.add(ln); | |
1383 int len = t.countTokens(); | |
1384 if (len > 2) { | |
1385 String r = t.at(len - 2); | |
1386 if (r.equals(">") || r.equals(">>")) { | |
1387 boolean append = r.length() == 2; | |
1388 String file = t.at(len - 1); | |
1389 try { | |
1390 redirect = new PrintStream(new BufferedOutputStream(new FileOutputStream(file, append))); | |
1391 t.trim(2); | |
1392 } catch (Exception e) { | |
1393 out.println("Error: " + e); | |
1394 if (verboseExceptions) { | |
1395 e.printStackTrace(out); | |
1396 } | |
1397 error = true; | |
1398 } | |
1399 } | |
1400 } | |
1401 if (!error) { | |
1402 PrintStream savedout = out; | |
1403 if (redirect != null) { | |
1404 out = redirect; | |
1405 } | |
1406 try { | |
1407 executeCommand(t); | |
1408 } catch (Exception e) { | |
1409 err.println("Error: " + e); | |
1410 if (verboseExceptions) { | |
1411 e.printStackTrace(err); | |
1412 } | |
1413 } finally { | |
1414 if (redirect != null) { | |
1415 out = savedout; | |
1416 redirect.close(); | |
1417 } | |
1418 } | |
1419 } | |
1420 } | |
1421 } | |
1422 | |
1423 void executeCommand(Tokens args) { | |
1424 String cmd = args.nextToken(); | |
1425 | |
1426 Command doit = findCommand(cmd); | |
1427 | |
1428 /* | |
1429 * Check for an unknown command | |
1430 */ | |
1431 if (doit == null) { | |
1432 out.println("Unrecognized command. Try help..."); | |
1433 } else if (!debugger.isAttached() && !doit.okIfDisconnected) { | |
1434 out.println("Command not valid until the attached to a VM"); | |
1435 } else { | |
1436 try { | |
1437 doit.doit(args); | |
1438 } catch (Exception e) { | |
1439 out.println("Error: " + e); | |
1440 if (verboseExceptions) { | |
1441 e.printStackTrace(out); | |
1442 } | |
1443 } | |
1444 } | |
1445 } | |
1446 } |