Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java @ 210:05712c37c828
6676016: ParallelOldGC leaks memory
Summary: ensure that GCTask threads release resource and handle memory
Reviewed-by: jmasa, chrisphi
author | jcoomes |
---|---|
date | Wed, 18 Jun 2008 18:36:47 -0700 |
parents | ba764ed4b6f2 |
children | d1605aabd0a1 |
rev | line source |
---|---|
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 } | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
888 public void visitCompOopAddress(Address addr) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
889 Address val = addr.getCompOopAddressAt(0); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
890 if (AddressOps.equal(val, value)) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
891 out.println("found at " + addr); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
892 } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
893 } |
0 | 894 public void epilogue() { |
895 } | |
896 }; | |
897 VM.getVM().getObjectHeap().iterateRaw(iterator); | |
898 } else if (type.equals("codecache")) { | |
899 CodeCacheVisitor v = new CodeCacheVisitor() { | |
900 public void prologue(Address start, Address end) { | |
901 } | |
902 public void visit(CodeBlob blob) { | |
903 boolean printed = false; | |
904 Address base = blob.getAddress(); | |
905 Address end = base.addOffsetTo(blob.getSize()); | |
906 while (base != null && base.lessThan(end)) { | |
907 Address val = base.getAddressAt(0); | |
908 if (AddressOps.equal(val, value)) { | |
909 if (!printed) { | |
910 printed = true; | |
911 blob.printOn(out); | |
912 } | |
913 out.println("found at " + base + "\n"); | |
914 } | |
915 base = base.addOffsetTo(stride); | |
916 } | |
917 } | |
918 public void epilogue() { | |
919 } | |
920 | |
921 | |
922 }; | |
923 VM.getVM().getCodeCache().iterate(v); | |
924 | |
925 } | |
926 } | |
927 } | |
928 }, | |
929 new Command("where", "where { -a | id }", false) { | |
930 public void doit(Tokens t) { | |
931 if (t.countTokens() != 1) { | |
932 usage(); | |
933 } else { | |
934 String name = t.nextToken(); | |
935 Threads threads = VM.getVM().getThreads(); | |
936 boolean all = name.equals("-a"); | |
937 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { | |
938 StringWriter sw = new StringWriter(); | |
939 ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
940 thread.printThreadIDOn(new PrintStream(bos)); | |
941 if (all || bos.toString().equals(name)) { | |
942 HTMLGenerator gen = new HTMLGenerator(false); | |
943 out.println(gen.genHTMLForJavaStackTrace(thread)); | |
944 if (!all) return; | |
945 } | |
946 } | |
947 if (!all) out.println("Couldn't find thread " + name); | |
948 } | |
949 } | |
950 }, | |
951 | |
952 new Command("threads", false) { | |
953 public void doit(Tokens t) { | |
954 if (t.countTokens() != 0) { | |
955 usage(); | |
956 } else { | |
957 Threads threads = VM.getVM().getThreads(); | |
958 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { | |
959 thread.printThreadIDOn(out); | |
960 out.println(" " + thread.getThreadName()); | |
961 } | |
962 } | |
963 } | |
964 }, | |
965 | |
966 new Command("livenmethods", false) { | |
967 public void doit(Tokens t) { | |
968 if (t.countTokens() != 0) { | |
969 usage(); | |
970 } else { | |
971 ArrayList nmethods = new ArrayList(); | |
972 Threads threads = VM.getVM().getThreads(); | |
973 HTMLGenerator gen = new HTMLGenerator(false); | |
974 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) { | |
975 try { | |
976 for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { | |
977 if (vf instanceof CompiledVFrame) { | |
978 NMethod c = ((CompiledVFrame)vf).getCode(); | |
979 if (!nmethods.contains(c)) { | |
980 nmethods.add(c); | |
981 out.println(gen.genHTML(c)); | |
982 } | |
983 } | |
984 } | |
985 } catch (Exception e) { | |
986 e.printStackTrace(); | |
987 } | |
988 } | |
989 } | |
990 } | |
991 }, | |
992 new Command("universe", false) { | |
993 public void doit(Tokens t) { | |
994 if (t.countTokens() != 0) { | |
995 usage(); | |
996 } else { | |
997 Universe u = VM.getVM().getUniverse(); | |
998 out.println("Heap Parameters:"); | |
999 u.heap().printOn(out); | |
1000 } | |
1001 } | |
1002 }, | |
1003 new Command("verbose", "verbose true | false", true) { | |
1004 public void doit(Tokens t) { | |
1005 if (t.countTokens() != 1) { | |
1006 usage(); | |
1007 } else { | |
1008 verboseExceptions = Boolean.valueOf(t.nextToken()).booleanValue(); | |
1009 } | |
1010 } | |
1011 }, | |
1012 new Command("assert", "assert true | false", true) { | |
1013 public void doit(Tokens t) { | |
1014 if (t.countTokens() != 1) { | |
1015 usage(); | |
1016 } else { | |
1017 Assert.ASSERTS_ENABLED = Boolean.valueOf(t.nextToken()).booleanValue(); | |
1018 } | |
1019 } | |
1020 }, | |
1021 }; | |
1022 | |
1023 private boolean verboseExceptions = false; | |
1024 private ArrayList history = new ArrayList(); | |
1025 private HashMap commands = new HashMap(); | |
1026 private boolean doEcho = false; | |
1027 | |
1028 private Command findCommand(String key) { | |
1029 return (Command)commands.get(key); | |
1030 } | |
1031 | |
1032 public void printPrompt() { | |
1033 out.print("hsdb> "); | |
1034 } | |
1035 | |
1036 private DebuggerInterface debugger; | |
1037 private HotSpotAgent agent; | |
1038 private JSJavaScriptEngine jsengine; | |
1039 private BufferedReader in; | |
1040 private PrintStream out; | |
1041 private PrintStream err; | |
1042 | |
1043 // called before debuggee attach | |
1044 private void preAttach() { | |
1045 // nothing for now.. | |
1046 } | |
1047 | |
1048 // called after debuggee attach | |
1049 private void postAttach() { | |
1050 // create JavaScript engine and start it | |
1051 jsengine = new JSJavaScriptEngine() { | |
1052 private ObjectReader reader = new ObjectReader(); | |
1053 private JSJavaFactory factory = new JSJavaFactoryImpl(); | |
1054 public ObjectReader getObjectReader() { | |
1055 return reader; | |
1056 } | |
1057 public JSJavaFactory getJSJavaFactory() { | |
1058 return factory; | |
1059 } | |
1060 protected void quit() { | |
1061 debugger.detach(); | |
1062 System.exit(0); | |
1063 } | |
1064 protected BufferedReader getInputReader() { | |
1065 return in; | |
1066 } | |
1067 protected PrintStream getOutputStream() { | |
1068 return out; | |
1069 } | |
1070 protected PrintStream getErrorStream() { | |
1071 return err; | |
1072 } | |
1073 }; | |
1074 try { | |
1075 jsengine.defineFunction(this, | |
1076 this.getClass().getMethod("registerCommand", | |
1077 new Class[] { | |
1078 String.class, String.class, String.class | |
1079 })); | |
1080 } catch (NoSuchMethodException exp) { | |
1081 // should not happen, see below...!! | |
1082 exp.printStackTrace(); | |
1083 } | |
1084 jsengine.start(); | |
1085 } | |
1086 | |
1087 public void registerCommand(String cmd, String usage, final String func) { | |
1088 commands.put(cmd, new Command(cmd, usage, false) { | |
1089 public void doit(Tokens t) { | |
1090 final int len = t.countTokens(); | |
1091 Object[] args = new Object[len]; | |
1092 for (int i = 0; i < len; i++) { | |
1093 args[i] = t.nextToken(); | |
1094 } | |
1095 jsengine.call(func, args); | |
1096 } | |
1097 }); | |
1098 } | |
1099 | |
1100 public void setOutput(PrintStream o) { | |
1101 out = o; | |
1102 } | |
1103 | |
1104 public void setErr(PrintStream e) { | |
1105 err = e; | |
1106 } | |
1107 | |
1108 public CommandProcessor(DebuggerInterface debugger, BufferedReader in, PrintStream out, PrintStream err) { | |
1109 this.debugger = debugger; | |
1110 this.agent = debugger.getAgent(); | |
1111 this.in = in; | |
1112 this.out = out; | |
1113 this.err = err; | |
1114 for (int i = 0; i < commandList.length; i++) { | |
1115 Command c = commandList[i]; | |
1116 commands.put(c.name, c); | |
1117 } | |
1118 if (debugger.isAttached()) { | |
1119 postAttach(); | |
1120 } | |
1121 } | |
1122 | |
1123 | |
1124 public void run(boolean prompt) { | |
1125 // Process interactive commands. | |
1126 while (true) { | |
1127 if (prompt) printPrompt(); | |
1128 String ln = null; | |
1129 try { | |
1130 ln = in.readLine(); | |
1131 } catch (IOException e) { | |
1132 } | |
1133 if (ln == null) { | |
1134 if (prompt) err.println("Input stream closed."); | |
1135 return; | |
1136 } | |
1137 | |
1138 executeCommand(ln); | |
1139 } | |
1140 } | |
1141 | |
1142 static Pattern historyPattern = Pattern.compile("((!\\*)|(!\\$)|(!!-?)|(!-?[0-9][0-9]*))"); | |
1143 | |
1144 public void executeCommand(String ln) { | |
1145 if (ln.indexOf('!') != -1) { | |
1146 int size = history.size(); | |
1147 if (size == 0) { | |
1148 ln = ""; | |
1149 err.println("History is empty"); | |
1150 } else { | |
1151 StringBuffer result = new StringBuffer(); | |
1152 Matcher m = historyPattern.matcher(ln); | |
1153 int start = 0; | |
1154 while (m.find()) { | |
1155 if (m.start() > start) { | |
1156 result.append(ln.substring(start, m.start() - start)); | |
1157 } | |
1158 start = m.end(); | |
1159 | |
1160 String cmd = m.group(); | |
1161 if (cmd.equals("!!")) { | |
1162 result.append((String)history.get(history.size() - 1)); | |
1163 } else if (cmd.equals("!!-")) { | |
1164 Tokens item = new Tokens((String)history.get(history.size() - 1)); | |
1165 item.trim(1); | |
1166 result.append(item.join(" ")); | |
1167 } else if (cmd.equals("!*")) { | |
1168 Tokens item = new Tokens((String)history.get(history.size() - 1)); | |
1169 item.nextToken(); | |
1170 result.append(item.join(" ")); | |
1171 } else if (cmd.equals("!$")) { | |
1172 Tokens item = new Tokens((String)history.get(history.size() - 1)); | |
1173 result.append(item.at(item.countTokens() - 1)); | |
1174 } else { | |
1175 String tail = cmd.substring(1); | |
1176 int index = Integer.parseInt(tail); | |
1177 if (index < 0) { | |
1178 index = history.size() + index; | |
1179 } | |
1180 if (index > size) { | |
1181 err.println("No such history item"); | |
1182 } else { | |
1183 result.append((String)history.get(index)); | |
1184 } | |
1185 } | |
1186 } | |
1187 if (result.length() == 0) { | |
1188 err.println("malformed history reference"); | |
1189 ln = ""; | |
1190 } else { | |
1191 if (start < ln.length()) { | |
1192 result.append(ln.substring(start)); | |
1193 } | |
1194 ln = result.toString(); | |
1195 if (!doEcho) { | |
1196 out.println(ln); | |
1197 } | |
1198 } | |
1199 } | |
1200 } | |
1201 | |
1202 if (doEcho) { | |
1203 out.println("+ " + ln); | |
1204 } | |
1205 | |
1206 PrintStream redirect = null; | |
1207 Tokens t = new Tokens(ln); | |
1208 if (t.hasMoreTokens()) { | |
1209 boolean error = false; | |
1210 history.add(ln); | |
1211 int len = t.countTokens(); | |
1212 if (len > 2) { | |
1213 String r = t.at(len - 2); | |
1214 if (r.equals(">") || r.equals(">>")) { | |
1215 boolean append = r.length() == 2; | |
1216 String file = t.at(len - 1); | |
1217 try { | |
1218 redirect = new PrintStream(new BufferedOutputStream(new FileOutputStream(file, append))); | |
1219 t.trim(2); | |
1220 } catch (Exception e) { | |
1221 out.println("Error: " + e); | |
1222 if (verboseExceptions) { | |
1223 e.printStackTrace(out); | |
1224 } | |
1225 error = true; | |
1226 } | |
1227 } | |
1228 } | |
1229 if (!error) { | |
1230 PrintStream savedout = out; | |
1231 if (redirect != null) { | |
1232 out = redirect; | |
1233 } | |
1234 try { | |
1235 executeCommand(t); | |
1236 } catch (Exception e) { | |
1237 err.println("Error: " + e); | |
1238 if (verboseExceptions) { | |
1239 e.printStackTrace(err); | |
1240 } | |
1241 } finally { | |
1242 if (redirect != null) { | |
1243 out = savedout; | |
1244 redirect.close(); | |
1245 } | |
1246 } | |
1247 } | |
1248 } | |
1249 } | |
1250 | |
1251 void executeCommand(Tokens args) { | |
1252 String cmd = args.nextToken(); | |
1253 | |
1254 Command doit = findCommand(cmd); | |
1255 | |
1256 /* | |
1257 * Check for an unknown command | |
1258 */ | |
1259 if (doit == null) { | |
1260 out.println("Unrecognized command. Try help..."); | |
1261 } else if (!debugger.isAttached() && !doit.okIfDisconnected) { | |
1262 out.println("Command not valid until the attached to a VM"); | |
1263 } else { | |
1264 try { | |
1265 doit.doit(args); | |
1266 } catch (Exception e) { | |
1267 out.println("Error: " + e); | |
1268 if (verboseExceptions) { | |
1269 e.printStackTrace(out); | |
1270 } | |
1271 } | |
1272 } | |
1273 } | |
1274 } |