View Javadoc
1   /*
2    * Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20   * or visit www.oracle.com if you need additional information or have any
21   * questions.
22   *
23   */
24  
25  package sun.jvm.hotspot;
26  
27  import java.io.BufferedOutputStream;
28  import java.io.BufferedReader;
29  import java.io.ByteArrayOutputStream;
30  import java.io.FileInputStream;
31  import java.io.FileOutputStream;
32  import java.io.IOException;
33  import java.io.InputStreamReader;
34  import java.io.PrintStream;
35  import java.util.ArrayList;
36  import java.util.Arrays;
37  import java.util.Comparator;
38  import java.util.HashMap;
39  import java.util.HashSet;
40  import java.util.Iterator;
41  import java.util.Stack;
42  import java.util.regex.Matcher;
43  import java.util.regex.Pattern;
44  
45  import sun.jvm.hotspot.ci.ciEnv;
46  import sun.jvm.hotspot.code.CodeBlob;
47  import sun.jvm.hotspot.code.CodeCacheVisitor;
48  import sun.jvm.hotspot.code.NMethod;
49  import sun.jvm.hotspot.debugger.Address;
50  import sun.jvm.hotspot.debugger.OopHandle;
51  import sun.jvm.hotspot.memory.SymbolTable;
52  import sun.jvm.hotspot.memory.SystemDictionary;
53  import sun.jvm.hotspot.memory.Universe;
54  import sun.jvm.hotspot.oops.DefaultHeapVisitor;
55  import sun.jvm.hotspot.oops.HeapVisitor;
56  import sun.jvm.hotspot.oops.InstanceKlass;
57  import sun.jvm.hotspot.oops.Klass;
58  import sun.jvm.hotspot.oops.Metadata;
59  import sun.jvm.hotspot.oops.Method;
60  import sun.jvm.hotspot.oops.MethodData;
61  import sun.jvm.hotspot.oops.Oop;
62  import sun.jvm.hotspot.oops.RawHeapVisitor;
63  import sun.jvm.hotspot.oops.Symbol;
64  import sun.jvm.hotspot.oops.UnknownOopException;
65  import sun.jvm.hotspot.opto.Compile;
66  import sun.jvm.hotspot.opto.InlineTree;
67  import sun.jvm.hotspot.runtime.CompiledVFrame;
68  import sun.jvm.hotspot.runtime.CompilerThread;
69  import sun.jvm.hotspot.runtime.JavaThread;
70  import sun.jvm.hotspot.runtime.JavaVFrame;
71  import sun.jvm.hotspot.runtime.Threads;
72  import sun.jvm.hotspot.runtime.VM;
73  import sun.jvm.hotspot.tools.ObjectHistogram;
74  import sun.jvm.hotspot.tools.PMap;
75  import sun.jvm.hotspot.tools.PStack;
76  import sun.jvm.hotspot.tools.StackTrace;
77  import sun.jvm.hotspot.tools.jcore.ClassDump;
78  import sun.jvm.hotspot.tools.jcore.ClassFilter;
79  import sun.jvm.hotspot.types.CIntegerType;
80  import sun.jvm.hotspot.types.Field;
81  import sun.jvm.hotspot.types.Type;
82  import sun.jvm.hotspot.types.basic.BasicType;
83  import sun.jvm.hotspot.ui.classbrowser.HTMLGenerator;
84  import sun.jvm.hotspot.ui.tree.CTypeTreeNodeAdapter;
85  import sun.jvm.hotspot.ui.tree.OopTreeNodeAdapter;
86  import sun.jvm.hotspot.ui.tree.SimpleTreeNode;
87  import sun.jvm.hotspot.utilities.AddressOps;
88  import sun.jvm.hotspot.utilities.Assert;
89  import sun.jvm.hotspot.utilities.HeapProgressThunk;
90  import sun.jvm.hotspot.utilities.LivenessPathElement;
91  import sun.jvm.hotspot.utilities.MethodArray;
92  import sun.jvm.hotspot.utilities.ObjectReader;
93  import sun.jvm.hotspot.utilities.PointerFinder;
94  import sun.jvm.hotspot.utilities.PointerLocation;
95  import sun.jvm.hotspot.utilities.ReversePtrs;
96  import sun.jvm.hotspot.utilities.ReversePtrsAnalysis;
97  import sun.jvm.hotspot.utilities.RobustOopDeterminator;
98  import sun.jvm.hotspot.utilities.SystemDictionaryHelper;
99  import sun.jvm.hotspot.utilities.soql.JSJavaFactory;
100 import sun.jvm.hotspot.utilities.soql.JSJavaFactoryImpl;
101 import sun.jvm.hotspot.utilities.soql.JSJavaScriptEngine;
102 
103 public class CommandProcessor {
104 
105     volatile boolean quit;
106 
107     public abstract static class DebuggerInterface {
108         public abstract HotSpotAgent getAgent();
109         public abstract boolean isAttached();
110         public abstract void attach(String pid);
111         public abstract void attach(String java, String core);
112         public abstract void detach();
113         public abstract void reattach();
114     }
115 
116     public static class BootFilter implements ClassFilter {
117         public boolean canInclude(InstanceKlass kls) {
118             return kls.getClassLoader() == null;
119         }
120     }
121 
122     public static class NonBootFilter implements ClassFilter {
123         private HashMap emitted = new HashMap();
124         public boolean canInclude(InstanceKlass kls) {
125             if (kls.getClassLoader() == null) return false;
126             if (emitted.get(kls.getName()) != null) {
127                 // Since multiple class loaders are being shoved
128                 // together duplicate classes are a possibilty.  For
129                 // now just ignore them.
130                 return false;
131             }
132             emitted.put(kls.getName(), kls);
133             return true;
134         }
135     }
136 
137     static class Tokens {
138         final String input;
139         int i;
140         String[] tokens;
141         int length;
142 
143         String[] splitWhitespace(String cmd) {
144             String[] t = cmd.split("\\s");
145             if (t.length == 1 && t[0].length() == 0) {
146                 return new String[0];
147             }
148             return t;
149         }
150 
151         void add(String s, ArrayList t) {
152             if (s.length() > 0) {
153                 t.add(s);
154             }
155         }
156 
157         Tokens(String cmd) {
158             input = cmd;
159 
160             // check for quoting
161             int quote = cmd.indexOf('"');
162             ArrayList t = new ArrayList();
163             if (quote != -1) {
164                 while (cmd.length() > 0) {
165                     if (quote != -1) {
166                         int endquote = cmd.indexOf('"', quote + 1);
167                         if (endquote == -1) {
168                             throw new RuntimeException("mismatched quotes: " + input);
169                         }
170 
171                         String before = cmd.substring(0, quote).trim();
172                         String quoted = cmd.substring(quote + 1, endquote);
173                         cmd = cmd.substring(endquote + 1).trim();
174                         if (before.length() > 0) {
175                             String[] w = splitWhitespace(before);
176                             for (int i = 0; i < w.length; i++) {
177                                 add(w[i], t);
178                             }
179                         }
180                         add(quoted, t);
181                         quote = cmd.indexOf('"');
182                     } else {
183                         String[] w = splitWhitespace(cmd);
184                         for (int i = 0; i < w.length; i++) {
185                             add(w[i], t);
186                         }
187                         cmd = "";
188 
189                     }
190                 }
191             } else {
192                 String[] w = splitWhitespace(cmd);
193                 for (int i = 0; i < w.length; i++) {
194                     add(w[i], t);
195                 }
196             }
197             tokens = (String[])t.toArray(new String[0]);
198             i = 0;
199             length = tokens.length;
200 
201             //for (int i = 0; i < tokens.length; i++) {
202             //    System.out.println("\"" + tokens[i] + "\"");
203             //}
204         }
205 
206         String nextToken() {
207             return tokens[i++];
208         }
209         boolean hasMoreTokens() {
210             return i < length;
211         }
212         int countTokens() {
213             return length - i;
214         }
215         void trim(int n) {
216             if (length >= n) {
217                 length -= n;
218             } else {
219                 throw new IndexOutOfBoundsException(String.valueOf(n));
220             }
221         }
222         String join(String sep) {
223             StringBuffer result = new StringBuffer();
224             for (int w = i; w < length; w++) {
225                 result.append(tokens[w]);
226                 if (w + 1 < length) {
227                     result.append(sep);
228                 }
229             }
230             return result.toString();
231         }
232 
233         String at(int i) {
234             if (i < 0 || i >= length) {
235                 throw new IndexOutOfBoundsException(String.valueOf(i));
236             }
237             return tokens[i];
238         }
239     }
240 
241 
242     abstract class Command {
243         Command(String n, String u, boolean ok) {
244             name = n;
245             usage = u;
246             okIfDisconnected = ok;
247         }
248 
249         Command(String n, boolean ok) {
250             name = n;
251             usage = n;
252             okIfDisconnected = ok;
253         }
254 
255         final String name;
256         final String usage;
257         final boolean okIfDisconnected;
258         abstract void doit(Tokens t);
259         void usage() {
260             out.println("Usage: " + usage);
261         }
262 
263         void printOopValue(Oop oop) {
264             if (oop != null) {
265                 Klass k = oop.getKlass();
266                 Symbol s = k.getName();
267                 if (s != null) {
268                     out.print("Oop for " + s.asString() + " @ ");
269                 } else {
270                     out.print("Oop @ ");
271                 }
272                 Oop.printOopAddressOn(oop, out);
273             } else {
274                 out.print("null");
275             }
276         }
277 
278         void printNode(SimpleTreeNode node) {
279             int count = node.getChildCount();
280             for (int i = 0; i < count; i++) {
281                 try {
282                     SimpleTreeNode field = node.getChild(i);
283                     if (field instanceof OopTreeNodeAdapter) {
284                         out.print(field);
285                         out.print(" ");
286                         printOopValue(((OopTreeNodeAdapter)field).getOop());
287                         out.println();
288                     } else {
289                         out.println(field);
290                     }
291                 } catch (Exception e) {
292                     out.println();
293                     out.println("Error: " + e);
294                     if (verboseExceptions) {
295                         e.printStackTrace(out);
296                     }
297                 }
298             }
299         }
300     }
301 
302     void quote(String s) {
303         if (s.indexOf(" ") == -1) {
304             out.print(s);
305         } else {
306             out.print("\"");
307             out.print(s);
308             out.print("\"");
309         }
310     }
311 
312     void dumpType(Type type) {
313         out.print("type ");
314         quote(type.getName());
315         out.print(" ");
316         if (type.getSuperclass() != null) {
317             quote(type.getSuperclass().getName());
318             out.print(" ");
319         } else {
320             out.print("null ");
321         }
322         out.print(type.isOopType());
323         out.print(" ");
324         if (type.isCIntegerType()) {
325             out.print("true ");
326             out.print(((CIntegerType)type).isUnsigned());
327             out.print(" ");
328         } else {
329             out.print("false false ");
330         }
331         out.print(type.getSize());
332         out.println();
333     }
334 
335     void dumpFields(Type type) {
336         dumpFields(type, true);
337     }
338 
339     void dumpFields(Type type, boolean allowStatic) {
340         Iterator i = type.getFields();
341         while (i.hasNext()) {
342             Field f = (Field) i.next();
343             if (!allowStatic && f.isStatic()) continue;
344             out.print("field ");
345             quote(type.getName());
346             out.print(" ");
347             out.print(f.getName());
348             out.print(" ");
349             quote(f.getType().getName());
350             out.print(" ");
351             out.print(f.isStatic());
352             out.print(" ");
353             if (f.isStatic()) {
354                 out.print("0 ");
355                 out.print(f.getStaticFieldAddress());
356             } else {
357                 out.print(f.getOffset());
358                 out.print(" 0x0");
359             }
360             out.println();
361         }
362     }
363 
364 
365     Address lookup(String symbol) {
366         if (symbol.indexOf("::") != -1) {
367             String[] parts = symbol.split("::");
368             StringBuffer mangled = new StringBuffer("__1c");
369             for (int i = 0; i < parts.length; i++) {
370                 int len = parts[i].length();
371                 if (len >= 26) {
372                     mangled.append((char)('a' + (len / 26)));
373                     len = len % 26;
374                 }
375                 mangled.append((char)('A' + len));
376                 mangled.append(parts[i]);
377             }
378             mangled.append("_");
379             symbol = mangled.toString();
380         }
381         return VM.getVM().getDebugger().lookup(null, symbol);
382     }
383 
384     Address parseAddress(String addr) {
385         return VM.getVM().getDebugger().parseAddress(addr);
386     }
387 
388     private final Command[] commandList = {
389         new Command("reattach", true) {
390             public void doit(Tokens t) {
391                 int tokens = t.countTokens();
392                 if (tokens != 0) {
393                     usage();
394                     return;
395                 }
396                 preAttach();
397                 debugger.reattach();
398                 postAttach();
399             }
400         },
401         new Command("attach", "attach pid | exec core", true) {
402             public void doit(Tokens t) {
403                 int tokens = t.countTokens();
404                 if (tokens == 1) {
405                     preAttach();
406                     debugger.attach(t.nextToken());
407                     postAttach();
408                 } else if (tokens == 2) {
409                     preAttach();
410                     debugger.attach(t.nextToken(), t.nextToken());
411                     postAttach();
412                 } else {
413                     usage();
414                 }
415             }
416         },
417         new Command("detach", false) {
418             public void doit(Tokens t) {
419                 if (t.countTokens() != 0) {
420                     usage();
421                 } else {
422                     debugger.detach();
423                 }
424             }
425         },
426         new Command("examine", "examine [ address/count ] | [ address,address]", false) {
427             Pattern args1 = Pattern.compile("^(0x[0-9a-f]+)(/([0-9]*)([a-z]*))?$");
428             Pattern args2 = Pattern.compile("^(0x[0-9a-f]+),(0x[0-9a-f]+)(/[a-z]*)?$");
429 
430             String fill(Address a, int width) {
431                 String s = "0x0";
432                 if (a != null) {
433                     s = a.toString();
434                 }
435                 if (s.length() != width) {
436                     return s.substring(0, 2) + "000000000000000000000".substring(0, width - s.length()) + s.substring(2);
437                 }
438                 return s;
439             }
440 
441             public void doit(Tokens t) {
442                 if (t.countTokens() != 1) {
443                     usage();
444                 } else {
445                     String arg = t.nextToken();
446                     Matcher m1 = args1.matcher(arg);
447                     Matcher m2 = args2.matcher(arg);
448                     Address start = null;
449                     Address end   = null;
450                     String format = "";
451                     int formatSize = (int)VM.getVM().getAddressSize();
452 
453                     if (m1.matches()) {
454                         start = VM.getVM().getDebugger().parseAddress(m1.group(1));
455                         int count = 1;
456                         if (m1.group(2) != null) {
457                             count = Integer.parseInt(m1.group(3));
458                         }
459                         end = start.addOffsetTo(count * formatSize);
460                     } else if (m2.matches()) {
461                         start = VM.getVM().getDebugger().parseAddress(m2.group(1));
462                         end   = VM.getVM().getDebugger().parseAddress(m2.group(2));
463                     } else {
464                         usage();
465                         return;
466                     }
467                     int line = 80;
468                     int formatWidth = formatSize * 8 / 4 + 2;
469 
470                     out.print(fill(start, formatWidth));
471                     out.print(": ");
472                     int width = line - formatWidth - 2;
473 
474                     boolean needsPrintln = true;
475                     while (start != null && start.lessThan(end)) {
476                         Address val = start.getAddressAt(0);
477                         out.print(fill(val, formatWidth));
478                         needsPrintln = true;
479                         width -= formatWidth;
480                         start = start.addOffsetTo(formatSize);
481                         if (width <= formatWidth) {
482                             out.println();
483                             needsPrintln = false;
484                             if (start.lessThan(end)) {
485                                 out.print(fill(start, formatWidth));
486                                 out.print(": ");
487                                 width = line - formatWidth - 2;
488                             }
489                         } else {
490                             out.print(" ");
491                             width -= 1;
492                         }
493                     }
494                     if (needsPrintln) {
495                         out.println();
496                     }
497                 }
498             }
499         },
500         new Command("dumpreplaydata", "dumpreplaydata { <address > | -a | <thread_id> }", false) {
501             // This is used to dump replay data from ciInstanceKlass, ciMethodData etc
502             // default file name is replay.txt, also if java crashes in compiler
503             // thread, this file will be dumped in error processing.
504             public void doit(Tokens t) {
505                 if (t.countTokens() != 1) {
506                     usage();
507                     return;
508                 }
509                 String name = t.nextToken();
510                 Address a = null;
511                 try {
512                     a = VM.getVM().getDebugger().parseAddress(name);
513                 } catch (NumberFormatException e) { }
514                 if (a != null) {
515                     // only nmethod, Method, MethodData and InstanceKlass needed to
516                     // dump replay data
517 
518                     CodeBlob cb = VM.getVM().getCodeCache().findBlob(a);
519                     if (cb != null && (cb instanceof NMethod)) {
520                         ((NMethod)cb).dumpReplayData(out);
521                         return;
522                     }
523                     // assume it is Metadata
524                     Metadata meta = Metadata.instantiateWrapperFor(a);
525                     if (meta != null) {
526                         meta.dumpReplayData(out);
527                     } else {
528                         usage();
529                         return;
530                     }
531                 }
532                 // Not an address
533                 boolean all = name.equals("-a");
534                 Threads threads = VM.getVM().getThreads();
535                 for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
536                     ByteArrayOutputStream bos = new ByteArrayOutputStream();
537                     thread.printThreadIDOn(new PrintStream(bos));
538                     if (all || bos.toString().equals(name)) {
539                         if (thread instanceof CompilerThread) {
540                             CompilerThread ct = (CompilerThread)thread;
541                             ciEnv env = ct.env();
542                             if (env != null) {
543                                env.dumpReplayData(out);
544                             }
545                         }
546                     }
547                 }
548             }
549         },
550         new Command("buildreplayjars", "buildreplayjars [ all | app | boot ]  | [ prefix ]", false) {
551             // This is used to dump jar files of all the classes
552             // loaded in the core.  Everything on the bootclasspath
553             // will go in boot.jar and everything else will go in
554             // app.jar.  Then the classes can be loaded by the replay
555             // jvm using -Xbootclasspath/p:boot.jar -cp app.jar. boot.jar usually
556             // not needed, unless changed by jvmti.
557             public void doit(Tokens t) {
558                 int tcount = t.countTokens();
559                 if (tcount > 2) {
560                     usage();
561                     return;
562                 }
563                 try {
564                    String prefix = "";
565                    String option = "all"; // default
566                    switch(tcount) {
567                        case 0:
568                            break;
569                        case 1:
570                            option = t.nextToken();
571                            if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") &&
572                                !option.equalsIgnoreCase("root")) {
573                               prefix = option;
574                               option = "all";
575                            }
576                            break;
577                        case 2:
578                            option = t.nextToken();
579                            prefix = t.nextToken();
580                            break;
581                        default:
582                            usage();
583                            return;
584                    }
585                    if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") &&
586                                !option.equalsIgnoreCase("boot")) {
587                        usage();
588                        return;
589                    }
590                    ClassDump cd = new ClassDump();
591                    if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("boot")) {
592                      cd.setClassFilter(new BootFilter());
593                      cd.setJarOutput(prefix + "boot.jar");
594                      cd.run();
595                    }
596                    if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("app")) {
597                      cd.setClassFilter(new NonBootFilter());
598                      cd.setJarOutput(prefix + "app.jar");
599                      cd.run();
600                    }
601                 } catch (IOException ioe) {
602                    ioe.printStackTrace();
603                 }
604             }
605         },
606         new Command("findpc", "findpc address", 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                     PointerLocation loc = PointerFinder.find(a);
613                     loc.printOn(out);
614                 }
615             }
616         },
617         new Command("symbol", "symbol address", false) {
618             public void doit(Tokens t) {
619                 if (t.countTokens() != 1) {
620                     usage();
621                 } else {
622                     Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
623                     Symbol.create(a).printValueOn(out);
624                     out.println();
625                 }
626             }
627         },
628         new Command("symboltable", "symboltable name", false) {
629             public void doit(Tokens t) {
630                 if (t.countTokens() != 1) {
631                     usage();
632                 } else {
633                     out.println(SymbolTable.getTheTable().probe(t.nextToken()));
634                 }
635             }
636         },
637         new Command("symboldump", "symboldump", false) {
638             public void doit(Tokens t) {
639                 SymbolTable.getTheTable().symbolsDo(new SymbolTable.SymbolVisitor() {
640                         public void visit(Symbol sym) {
641                             sym.printValueOn(out);
642                             out.println();
643                         }
644                     });
645             }
646         },
647         new Command("flags", "flags [ flag | -nd ]", false) {
648             public void doit(Tokens t) {
649                 int tokens = t.countTokens();
650                 if (tokens != 0 && tokens != 1) {
651                     usage();
652                 } else {
653                     String name = tokens > 0 ? t.nextToken() : null;
654                     boolean nonDefault = false;
655                     if (name != null && name.equals("-nd")) {
656                         name = null;
657                         nonDefault = true;
658                     }
659 
660                     VM.Flag[] flags = VM.getVM().getCommandLineFlags();
661                     if (flags == null) {
662                         out.println("Command Flag info not available (use 1.4.1_03 or later)!");
663                     } else {
664                         boolean printed = false;
665                         for (int f = 0; f < flags.length; f++) {
666                             VM.Flag flag = flags[f];
667                             if (name == null || flag.getName().equals(name)) {
668 
669                                 if (nonDefault && flag.getOrigin() == 0) {
670                                     // only print flags which aren't their defaults
671                                     continue;
672                                 }
673                                 out.println(flag.getName() + " = " + flag.getValue() + " " + flag.getOrigin());
674                                 printed = true;
675                             }
676                         }
677                         if (name != null && !printed) {
678                             out.println("Couldn't find flag: " + name);
679                         }
680                     }
681                 }
682             }
683         },
684         new Command("help", "help [ command ]", true) {
685             public void doit(Tokens t) {
686                 int tokens = t.countTokens();
687                 Command cmd = null;
688                 if (tokens == 1) {
689                     cmd = findCommand(t.nextToken());
690                 }
691 
692                 if (cmd != null) {
693                     cmd.usage();
694                 } else if (tokens == 0) {
695                     out.println("Available commands:");
696                     Object[] keys = commands.keySet().toArray();
697                     Arrays.sort(keys, new Comparator() {
698                              public int compare(Object o1, Object o2) {
699                                  return o1.toString().compareTo(o2.toString());
700                              }
701                           });
702                     for (int i = 0; i < keys.length; i++) {
703                         out.print("  ");
704                         out.println(((Command)commands.get(keys[i])).usage);
705                     }
706                 }
707             }
708         },
709         new Command("history", "history", true) {
710             public void doit(Tokens t) {
711                 int tokens = t.countTokens();
712                 if (tokens != 0 && (tokens != 1 || !t.nextToken().equals("-h"))) {
713                     usage();
714                     return;
715                 }
716                 boolean printIndex = tokens == 0;
717                 for (int i = 0; i < history.size(); i++) {
718                     if (printIndex) out.print(i + " ");
719                     out.println(history.get(i));
720                 }
721             }
722         },
723         // decode raw address
724         new Command("dis", "dis address [length]", false) {
725             public void doit(Tokens t) {
726                 int tokens = t.countTokens();
727                 if (tokens != 1 && tokens != 2) {
728                     usage();
729                     return;
730                 }
731                 String name = t.nextToken();
732                 Address addr = null;
733                 int len = 0x10; // default length
734                 try {
735                     addr = VM.getVM().getDebugger().parseAddress(name);
736                 } catch (NumberFormatException e) {
737                    out.println(e);
738                    return;
739                 }
740                 if (tokens == 2) {
741                     try {
742                         len = Integer.parseInt(t.nextToken());
743                     } catch (NumberFormatException e) {
744                         out.println(e);
745                         return;
746                     }
747                 }
748                 HTMLGenerator generator = new HTMLGenerator(false);
749                 out.println(generator.genHTMLForRawDisassembly(addr, len));
750             }
751 
752         },
753         // decode codeblob or nmethod
754         new Command("disassemble", "disassemble address", false) {
755             public void doit(Tokens t) {
756                 int tokens = t.countTokens();
757                 if (tokens != 1) {
758                     usage();
759                     return;
760                 }
761                 String name = t.nextToken();
762                 Address addr = null;
763                 try {
764                     addr = VM.getVM().getDebugger().parseAddress(name);
765                 } catch (NumberFormatException e) {
766                    out.println(e);
767                    return;
768                 }
769 
770                 HTMLGenerator generator = new HTMLGenerator(false);
771                 out.println(generator.genHTML(addr));
772             }
773         },
774         // print Java bytecode disassembly
775         new Command("jdis", "jdis address", false) {
776             public void doit(Tokens t) {
777                 int tokens = t.countTokens();
778                 if (tokens != 1) {
779                     usage();
780                     return;
781                 }
782                 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
783                 Method m = (Method)Metadata.instantiateWrapperFor(a);
784                 HTMLGenerator html = new HTMLGenerator(false);
785                 out.println(html.genHTML(m));
786             }
787         },
788         new Command("revptrs", "revptrs address", false) {
789             public void doit(Tokens t) {
790                 int tokens = t.countTokens();
791                 if (tokens != 1 && (tokens != 2 || !t.nextToken().equals("-c"))) {
792                     usage();
793                     return;
794                 }
795                 boolean chase = tokens == 2;
796                 ReversePtrs revptrs = VM.getVM().getRevPtrs();
797                 if (revptrs == null) {
798                     out.println("Computing reverse pointers...");
799                     ReversePtrsAnalysis analysis = new ReversePtrsAnalysis();
800                     final boolean[] complete = new boolean[1];
801                     HeapProgressThunk thunk = new HeapProgressThunk() {
802                             public void heapIterationFractionUpdate(double d) {}
803                             public synchronized void heapIterationComplete() {
804                                 complete[0] = true;
805                                 notify();
806                             }
807                         };
808                     analysis.setHeapProgressThunk(thunk);
809                     analysis.run();
810                     while (!complete[0]) {
811                         synchronized (thunk) {
812                             try {
813                                 thunk.wait();
814                             } catch (Exception e) {
815                             }
816                         }
817                     }
818                     revptrs = VM.getVM().getRevPtrs();
819                     out.println("Done.");
820                 }
821                 Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
822                 if (VM.getVM().getUniverse().heap().isInReserved(a)) {
823                     OopHandle handle = a.addOffsetToAsOopHandle(0);
824                     Oop oop = VM.getVM().getObjectHeap().newOop(handle);
825                     ArrayList ptrs = revptrs.get(oop);
826                     if (ptrs == null) {
827                         out.println("no live references to " + a);
828                     } else {
829                         if (chase) {
830                             while (ptrs.size() == 1) {
831                                 LivenessPathElement e = (LivenessPathElement)ptrs.get(0);
832                                 ByteArrayOutputStream bos = new ByteArrayOutputStream();
833                                 Oop.printOopValueOn(e.getObj(), new PrintStream(bos));
834                                 out.println(bos.toString());
835                                 ptrs = revptrs.get(e.getObj());
836                             }
837                         } else {
838                             for (int i = 0; i < ptrs.size(); i++) {
839                                 LivenessPathElement e = (LivenessPathElement)ptrs.get(i);
840                                 ByteArrayOutputStream bos = new ByteArrayOutputStream();
841                                 Oop.printOopValueOn(e.getObj(), new PrintStream(bos));
842                                 out.println(bos.toString());
843                                 oop = e.getObj();
844                             }
845                         }
846                     }
847                 }
848             }
849         },
850         new Command("printmdo", "printmdo [ -a | expression ]", false) {
851             // Print every MDO in the heap or the one referenced by expression.
852             public void doit(Tokens t) {
853                 if (t.countTokens() != 1) {
854                     usage();
855                 } else {
856                     String s = t.nextToken();
857                     if (s.equals("-a")) {
858                         SystemDictionary sysDict = VM.getVM().getSystemDictionary();
859                         sysDict.allClassesDo(new SystemDictionary.ClassVisitor() {
860                                 public void visit(Klass k) {
861                                     if (k instanceof InstanceKlass) {
862                                         MethodArray methods = ((InstanceKlass)k).getMethods();
863                                         for (int i = 0; i < methods.length(); i++) {
864                                             Method m = methods.at(i);
865                                             MethodData mdo = m.getMethodData();
866                                             if (mdo != null) {
867                                                 out.println("MethodData " + mdo.getAddress() + " for " +
868                                                     "method " + m.getMethodHolder().getName().asString() + "." +
869                                                     m.getName().asString() +
870                                                             m.getSignature().asString() + "@" + m.getAddress());
871                                                 mdo.printDataOn(out);
872                                     }
873                                 }
874                                     }
875                                 }
876                             }
877                             );
878                     } else {
879                         Address a = VM.getVM().getDebugger().parseAddress(s);
880                         MethodData mdo = (MethodData) Metadata.instantiateWrapperFor(a);
881                         mdo.printDataOn(out);
882                     }
883                 }
884             }
885         },
886         new Command("printall", "printall", false) {
887             // Print every MDO in the heap or the one referenced by expression.
888             public void doit(Tokens t) {
889                 if (t.countTokens() != 0) {
890                     usage();
891                 } else {
892                     SystemDictionary sysDict = VM.getVM().getSystemDictionary();
893                     sysDict.allClassesDo(new SystemDictionary.ClassVisitor() {
894                             public void visit(Klass k) {
895                                 if (k instanceof InstanceKlass && ((InstanceKlass)k).getConstants().getCache() != null) {
896                                     MethodArray methods = ((InstanceKlass)k).getMethods();
897                                     for (int i = 0; i < methods.length(); i++) {
898                                         Method m = methods.at(i);
899                                         HTMLGenerator gen = new HTMLGenerator(false);
900                                         out.println(gen.genHTML(m));
901                                     }
902                                 }
903                             }
904                         }
905                         );
906                 }
907             }
908         },
909         new Command("dumpideal", "dumpideal { -a | id }", false) {
910             // Do a full dump of the nodes reachabile from root in each compiler thread.
911             public void doit(Tokens t) {
912                 if (t.countTokens() != 1) {
913                     usage();
914                 } else {
915                     String name = t.nextToken();
916                     boolean all = name.equals("-a");
917                     Threads threads = VM.getVM().getThreads();
918                     for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
919                         ByteArrayOutputStream bos = new ByteArrayOutputStream();
920                         thread.printThreadIDOn(new PrintStream(bos));
921                         if (all || bos.toString().equals(name)) {
922                           if (thread instanceof CompilerThread) {
923                             CompilerThread ct = (CompilerThread)thread;
924                             out.println(ct);
925                             ciEnv env = ct.env();
926                             if (env != null) {
927                               Compile c = env.compilerData();
928                               c.root().dump(9999, out);
929                             } else {
930                               out.println("  not compiling");
931                             }
932                           }
933                         }
934                     }
935                 }
936             }
937         },
938         new Command("dumpcfg", "dumpcfg { -a | id }", false) {
939             // Dump the PhaseCFG for every compiler thread that has one live.
940             public void doit(Tokens t) {
941                 if (t.countTokens() != 1) {
942                     usage();
943                 } else {
944                     String name = t.nextToken();
945                     boolean all = name.equals("-a");
946                     Threads threads = VM.getVM().getThreads();
947                     for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
948                         ByteArrayOutputStream bos = new ByteArrayOutputStream();
949                         thread.printThreadIDOn(new PrintStream(bos));
950                         if (all || bos.toString().equals(name)) {
951                           if (thread instanceof CompilerThread) {
952                             CompilerThread ct = (CompilerThread)thread;
953                             out.println(ct);
954                             ciEnv env = ct.env();
955                             if (env != null) {
956                               Compile c = env.compilerData();
957                               c.cfg().dump(out);
958                             }
959                           }
960                         }
961                     }
962                 }
963             }
964         },
965         new Command("dumpilt", "dumpilt { -a | id }", false) {
966             // dumps the InlineTree of a C2 compile
967             public void doit(Tokens t) {
968                 if (t.countTokens() != 1) {
969                     usage();
970                 } else {
971                     String name = t.nextToken();
972                     boolean all = name.equals("-a");
973                     Threads threads = VM.getVM().getThreads();
974                     for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
975                         ByteArrayOutputStream bos = new ByteArrayOutputStream();
976                         thread.printThreadIDOn(new PrintStream(bos));
977                         if (all || bos.toString().equals(name)) {
978                             if (thread instanceof CompilerThread) {
979                                 CompilerThread ct = (CompilerThread)thread;
980                                 ciEnv env = ct.env();
981                                 if (env != null) {
982                                     Compile c = env.compilerData();
983                                     InlineTree ilt = c.ilt();
984                                     if (ilt != null) {
985                                         ilt.print(out);
986                                     }
987                                 }
988                             }
989                         }
990                     }
991                 }
992             }
993         },
994         new Command("vmstructsdump", "vmstructsdump", false) {
995             public void doit(Tokens t) {
996                 if (t.countTokens() != 0) {
997                     usage();
998                     return;
999                 }
1000 
1001                 // Dump a copy of the type database in a form that can
1002                 // be read back.
1003                 Iterator i = agent.getTypeDataBase().getTypes();
1004                 // Make sure the types are emitted in an order than can be read back in
1005                 HashSet emitted = new HashSet();
1006                 Stack pending = new Stack();
1007                 while (i.hasNext()) {
1008                     Type n = (Type)i.next();
1009                     if (emitted.contains(n.getName())) {
1010                         continue;
1011                     }
1012 
1013                     while (n != null && !emitted.contains(n.getName())) {
1014                         pending.push(n);
1015                         n = n.getSuperclass();
1016                     }
1017                     while (!pending.empty()) {
1018                         n = (Type)pending.pop();
1019                         dumpType(n);
1020                         emitted.add(n.getName());
1021                     }
1022                 }
1023                 i = agent.getTypeDataBase().getTypes();
1024                 while (i.hasNext()) {
1025                     dumpFields((Type)i.next(), false);
1026                 }
1027             }
1028         },
1029 
1030         new Command("inspect", "inspect expression", false) {
1031             public void doit(Tokens t) {
1032                 if (t.countTokens() != 1) {
1033                     usage();
1034                 } else {
1035                     Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
1036                     SimpleTreeNode node = null;
1037                     if (VM.getVM().getUniverse().heap().isInReserved(a)) {
1038                         OopHandle handle = a.addOffsetToAsOopHandle(0);
1039                         Oop oop = VM.getVM().getObjectHeap().newOop(handle);
1040                         node = new OopTreeNodeAdapter(oop, null);
1041 
1042                         out.println("instance of " + node.getValue() + " @ " + a +
1043                                     " (size = " + oop.getObjectSize() + ")");
1044                     } else if (VM.getVM().getCodeCache().contains(a)) {
1045                         CodeBlob blob = VM.getVM().getCodeCache().findBlobUnsafe(a);
1046                         a = blob.headerBegin();
1047                     }
1048                     if (node == null) {
1049                         Type type = VM.getVM().getTypeDataBase().guessTypeForAddress(a);
1050                         if (type != null) {
1051                             out.println("Type is " + type.getName() + " (size of " + type.getSize() + ")");
1052                             node = new CTypeTreeNodeAdapter(a, type, null);
1053                         }
1054                     }
1055                     if (node != null) {
1056                         printNode(node);
1057                     }
1058                 }
1059             }
1060         },
1061         new Command("jhisto", "jhisto", false) {
1062             public void doit(Tokens t) {
1063                  ObjectHistogram histo = new ObjectHistogram();
1064                  histo.run(out, err);
1065             }
1066         },
1067         new Command("jstack", "jstack [-v]", false) {
1068             public void doit(Tokens t) {
1069                 boolean verbose = false;
1070                 if (t.countTokens() > 0 && t.nextToken().equals("-v")) {
1071                     verbose = true;
1072                 }
1073                 StackTrace jstack = new StackTrace(verbose, true);
1074                 jstack.run(out);
1075             }
1076         },
1077         new Command("print", "print expression", false) {
1078             public void doit(Tokens t) {
1079                 if (t.countTokens() != 1) {
1080                     usage();
1081                 } else {
1082                     Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
1083                     HTMLGenerator gen = new HTMLGenerator(false);
1084                     out.println(gen.genHTML(a));
1085                 }
1086             }
1087         },
1088         new Command("printas", "printas type expression", false) {
1089             public void doit(Tokens t) {
1090                 if (t.countTokens() != 2) {
1091                     usage();
1092                 } else {
1093                     Type type = agent.getTypeDataBase().lookupType(t.nextToken());
1094                     Address a = VM.getVM().getDebugger().parseAddress(t.nextToken());
1095                     CTypeTreeNodeAdapter node = new CTypeTreeNodeAdapter(a, type, null);
1096 
1097                     out.println("pointer to " + type + " @ " + a +
1098                                 " (size = " + type.getSize() + ")");
1099                     printNode(node);
1100                 }
1101             }
1102         },
1103         new Command("printstatics", "printstatics [ type ]", false) {
1104             public void doit(Tokens t) {
1105                 if (t.countTokens() > 1) {
1106                     usage();
1107                 } else {
1108                     if (t.countTokens() == 0) {
1109                         out.println("All known static fields");
1110                         printNode(new CTypeTreeNodeAdapter(agent.getTypeDataBase().getTypes()));
1111                     } else {
1112                         Type type = agent.getTypeDataBase().lookupType(t.nextToken());
1113                         out.println("Static fields of " + type.getName());
1114                         printNode(new CTypeTreeNodeAdapter(type));
1115                     }
1116                 }
1117             }
1118         },
1119         new Command("pmap", "pmap", false) {
1120             public void doit(Tokens t) {
1121                 PMap pmap = new PMap();
1122                 pmap.run(out, debugger.getAgent().getDebugger());
1123             }
1124         },
1125         new Command("pstack", "pstack [-v]", false) {
1126             public void doit(Tokens t) {
1127                 boolean verbose = false;
1128                 if (t.countTokens() > 0 && t.nextToken().equals("-v")) {
1129                     verbose = true;
1130                 }
1131                 PStack pstack = new PStack(verbose, true);
1132                 pstack.run(out, debugger.getAgent().getDebugger());
1133             }
1134         },
1135         new Command("quit", true) {
1136             public void doit(Tokens t) {
1137                 if (t.countTokens() != 0) {
1138                     usage();
1139                 } else {
1140                     debugger.detach();
1141                     quit = true;
1142                 }
1143             }
1144         },
1145         new Command("echo", "echo [ true | false ]", true) {
1146             public void doit(Tokens t) {
1147                 if (t.countTokens() == 0) {
1148                     out.println("echo is " + doEcho);
1149                 } else if (t.countTokens() == 1) {
1150                     doEcho = Boolean.valueOf(t.nextToken()).booleanValue();
1151                 } else {
1152                     usage();
1153                 }
1154             }
1155         },
1156         new Command("versioncheck", "versioncheck [ true | false ]", true) {
1157             public void doit(Tokens t) {
1158                 if (t.countTokens() == 0) {
1159                     out.println("versioncheck is " +
1160                                 (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null));
1161                 } else if (t.countTokens() == 1) {
1162                     if (Boolean.valueOf(t.nextToken()).booleanValue()) {
1163                         System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", null);
1164                     } else {
1165                         System.setProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck", "true");
1166                     }
1167                 } else {
1168                     usage();
1169                 }
1170             }
1171         },
1172         new Command("scanoops", "scanoops start end [ type ]", false) {
1173             public void doit(Tokens t) {
1174                 if (t.countTokens() != 2 && t.countTokens() != 3) {
1175                     usage();
1176                 } else {
1177                     long stride = VM.getVM().getAddressSize();
1178                     Address base = VM.getVM().getDebugger().parseAddress(t.nextToken());
1179                     Address end  = VM.getVM().getDebugger().parseAddress(t.nextToken());
1180                     Klass klass = null;
1181                     if (t.countTokens() == 1) {
1182                         klass = SystemDictionaryHelper.findInstanceKlass(t.nextToken());
1183                         if (klass == null) {
1184                             out.println("No such type.");
1185                             return;
1186                         }
1187                     }
1188                     while (base != null && base.lessThan(end)) {
1189                         long step = stride;
1190                         OopHandle handle = base.addOffsetToAsOopHandle(0);
1191                         if (RobustOopDeterminator.oopLooksValid(handle)) {
1192                             try {
1193                                 Oop oop = VM.getVM().getObjectHeap().newOop(handle);
1194                                 if (klass == null || oop.getKlass().isSubtypeOf(klass))
1195                                     out.println(handle.toString() + " " + oop.getKlass().getName().asString());
1196                                 step = oop.getObjectSize();
1197                             } catch (UnknownOopException ex) {
1198                                 // ok
1199                             } catch (RuntimeException ex) {
1200                                 ex.printStackTrace();
1201                             }
1202                         }
1203                         base = base.addOffsetTo(step);
1204                     }
1205                 }
1206             }
1207         },
1208         new Command("intConstant", "intConstant [ name [ value ] ]", true) {
1209             public void doit(Tokens t) {
1210                 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) {
1211                     usage();
1212                     return;
1213                 }
1214                 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
1215                 if (t.countTokens() == 1) {
1216                     String name = t.nextToken();
1217                     out.println("intConstant " + name + " " + db.lookupIntConstant(name));
1218                 } else if (t.countTokens() == 0) {
1219                     Iterator i = db.getIntConstants();
1220                     while (i.hasNext()) {
1221                         String name = (String)i.next();
1222                         out.println("intConstant " + name + " " + db.lookupIntConstant(name));
1223                     }
1224                 } else if (t.countTokens() == 2) {
1225                     String name = t.nextToken();
1226                     Integer value = Integer.valueOf(t.nextToken());
1227                     db.addIntConstant(name, value);
1228                 }
1229             }
1230         },
1231         new Command("longConstant", "longConstant [ name [ value ] ]", true) {
1232             public void doit(Tokens t) {
1233                 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) {
1234                     usage();
1235                     return;
1236                 }
1237                 HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
1238                 if (t.countTokens() == 1) {
1239                     String name = t.nextToken();
1240                     out.println("longConstant " + name + " " + db.lookupLongConstant(name));
1241                 } else if (t.countTokens() == 0) {
1242                     Iterator i = db.getLongConstants();
1243                     while (i.hasNext()) {
1244                         String name = (String)i.next();
1245                         out.println("longConstant " + name + " " + db.lookupLongConstant(name));
1246                     }
1247                 } else if (t.countTokens() == 2) {
1248                     String name = t.nextToken();
1249                     Long value = Long.valueOf(t.nextToken());
1250                     db.addLongConstant(name, value);
1251                 }
1252             }
1253         },
1254         new Command("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) {
1255             public void doit(Tokens t) {
1256                 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) {
1257                     usage();
1258                     return;
1259                 }
1260                 if (t.countTokens() == 1) {
1261                     Type type = agent.getTypeDataBase().lookupType(t.nextToken());
1262                     dumpFields(type);
1263                 } else if (t.countTokens() == 0) {
1264                     Iterator i = agent.getTypeDataBase().getTypes();
1265                     while (i.hasNext()) {
1266                         dumpFields((Type)i.next());
1267                     }
1268                 } else {
1269                     BasicType containingType = (BasicType)agent.getTypeDataBase().lookupType(t.nextToken());
1270 
1271                     String fieldName = t.nextToken();
1272 
1273                     // The field's Type must already be in the database -- no exceptions
1274                     Type fieldType = agent.getTypeDataBase().lookupType(t.nextToken());
1275 
1276                     boolean isStatic = Boolean.valueOf(t.nextToken()).booleanValue();
1277                     long offset = Long.parseLong(t.nextToken());
1278                     Address staticAddress = parseAddress(t.nextToken());
1279                     if (isStatic && staticAddress == null) {
1280                         staticAddress = lookup(containingType.getName() + "::" + fieldName);
1281                     }
1282 
1283                     // check to see if the field already exists
1284                     Iterator i = containingType.getFields();
1285                     while (i.hasNext()) {
1286                         Field f = (Field) i.next();
1287                         if (f.getName().equals(fieldName)) {
1288                             if (f.isStatic() != isStatic) {
1289                                 throw new RuntimeException("static/nonstatic mismatch: " + t.input);
1290                             }
1291                             if (!isStatic) {
1292                                 if (f.getOffset() != offset) {
1293                                     throw new RuntimeException("bad redefinition of field offset: " + t.input);
1294                                 }
1295                             } else {
1296                                 if (!f.getStaticFieldAddress().equals(staticAddress)) {
1297                                     throw new RuntimeException("bad redefinition of field location: " + t.input);
1298                                 }
1299                             }
1300                             if (f.getType() != fieldType) {
1301                                 throw new RuntimeException("bad redefinition of field type: " + t.input);
1302                             }
1303                             return;
1304                         }
1305                     }
1306 
1307                     // Create field by type
1308                     HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
1309                     db.createField(containingType,
1310                                    fieldName, fieldType,
1311                                    isStatic,
1312                                    offset,
1313                                    staticAddress);
1314 
1315                 }
1316             }
1317 
1318         },
1319         new Command("tokenize", "tokenize ...", true) {
1320             public void doit(Tokens t) {
1321                 while (t.hasMoreTokens()) {
1322                     out.println("\"" + t.nextToken() + "\"");
1323                 }
1324             }
1325         },
1326         new Command("type", "type [ type [ name super isOop isInteger isUnsigned size ] ]", true) {
1327             public void doit(Tokens t) {
1328                 if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) {
1329                     usage();
1330                     return;
1331                 }
1332                 if (t.countTokens() == 6) {
1333                     String typeName = t.nextToken();
1334                     String superclassName = t.nextToken();
1335                     if (superclassName.equals("null")) {
1336                         superclassName = null;
1337                     }
1338                     boolean isOop = Boolean.valueOf(t.nextToken()).booleanValue();
1339                     boolean isInteger = Boolean.valueOf(t.nextToken()).booleanValue();
1340                     boolean isUnsigned = Boolean.valueOf(t.nextToken()).booleanValue();
1341                     long size = Long.parseLong(t.nextToken());
1342 
1343                     BasicType type = null;
1344                     try {
1345                         type = (BasicType)agent.getTypeDataBase().lookupType(typeName);
1346                     } catch (RuntimeException e) {
1347                     }
1348                     if (type != null) {
1349                         if (type.isOopType() != isOop) {
1350                             throw new RuntimeException("oop mismatch in type definition: " + t.input);
1351                         }
1352                         if (type.isCIntegerType() != isInteger) {
1353                             throw new RuntimeException("integer type mismatch in type definition: " + t.input);
1354                         }
1355                         if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) {
1356                             throw new RuntimeException("unsigned mismatch in type definition: " + t.input);
1357                         }
1358                         if (type.getSuperclass() == null) {
1359                             if (superclassName != null) {
1360                                 if (type.getSize() == -1) {
1361                                     type.setSuperclass(agent.getTypeDataBase().lookupType(superclassName));
1362                                 } else {
1363                                     throw new RuntimeException("unexpected superclass in type definition: " + t.input);
1364                                 }
1365                             }
1366                         } else {
1367                             if (superclassName == null) {
1368                                 throw new RuntimeException("missing superclass in type definition: " + t.input);
1369                             }
1370                             if (!type.getSuperclass().getName().equals(superclassName)) {
1371                                 throw new RuntimeException("incorrect superclass in type definition: " + t.input);
1372                             }
1373                         }
1374                         if (type.getSize() != size) {
1375                             if (type.getSize() == -1) {
1376                                 type.setSize(size);
1377                             }
1378                             throw new RuntimeException("size mismatch in type definition: " + t.input);
1379                         }
1380                         return;
1381                     }
1382 
1383                     // Create type
1384                     HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
1385                     db.createType(typeName, superclassName, isOop, isInteger, isUnsigned, size);
1386                 } else if (t.countTokens() == 1) {
1387                     Type type = agent.getTypeDataBase().lookupType(t.nextToken());
1388                     dumpType(type);
1389                 } else {
1390                     Iterator i = agent.getTypeDataBase().getTypes();
1391                     // Make sure the types are emitted in an order than can be read back in
1392                     HashSet emitted = new HashSet();
1393                     Stack pending = new Stack();
1394                     while (i.hasNext()) {
1395                         Type n = (Type)i.next();
1396                         if (emitted.contains(n.getName())) {
1397                             continue;
1398                         }
1399 
1400                         while (n != null && !emitted.contains(n.getName())) {
1401                             pending.push(n);
1402                             n = n.getSuperclass();
1403                         }
1404                         while (!pending.empty()) {
1405                             n = (Type)pending.pop();
1406                             dumpType(n);
1407                             emitted.add(n.getName());
1408                         }
1409                     }
1410                 }
1411             }
1412 
1413         },
1414         new Command("source", "source filename", true) {
1415             public void doit(Tokens t) {
1416                 if (t.countTokens() != 1) {
1417                     usage();
1418                     return;
1419                 }
1420                 String file = t.nextToken();
1421                 BufferedReader savedInput = in;
1422                 try {
1423                     BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
1424                     in = input;
1425                     run(false);
1426                 } catch (Exception e) {
1427                     out.println("Error: " + e);
1428                     if (verboseExceptions) {
1429                         e.printStackTrace(out);
1430                     }
1431                 } finally {
1432                     in = savedInput;
1433                 }
1434 
1435             }
1436         },
1437         new Command("search", "search [ heap | perm | rawheap | codecache | threads ] value", false) {
1438             public void doit(Tokens t) {
1439                 if (t.countTokens() != 2) {
1440                     usage();
1441                     return;
1442                 }
1443                 String type = t.nextToken();
1444                 final Address value = VM.getVM().getDebugger().parseAddress(t.nextToken());
1445                 final long stride = VM.getVM().getAddressSize();
1446                 if (type.equals("threads")) {
1447                     Threads threads = VM.getVM().getThreads();
1448                     for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
1449                         Address base = thread.getBaseOfStackPointer();
1450                         Address end = thread.getLastJavaSP();
1451                         if (end == null) continue;
1452                         if (end.lessThan(base)) {
1453                             Address tmp = base;
1454                             base = end;
1455                             end = tmp;
1456                         }
1457                         out.println("Searching " + base + " " + end);
1458                         while (base != null && base.lessThan(end)) {
1459                             Address val = base.getAddressAt(0);
1460                             if (AddressOps.equal(val, value)) {
1461                                 out.println(base);
1462                             }
1463                             base = base.addOffsetTo(stride);
1464                         }
1465                     }
1466                 } else if (type.equals("rawheap")) {
1467                     RawHeapVisitor iterator = new RawHeapVisitor() {
1468                             public void prologue(long used) {
1469                             }
1470 
1471                             public void visitAddress(Address addr) {
1472                                 Address val = addr.getAddressAt(0);
1473                                 if (AddressOps.equal(val, value)) {
1474                                         out.println("found at " + addr);
1475                                 }
1476                             }
1477                             public void visitCompOopAddress(Address addr) {
1478                                 Address val = addr.getCompOopAddressAt(0);
1479                                 if (AddressOps.equal(val, value)) {
1480                                     out.println("found at " + addr);
1481                                 }
1482                             }
1483                             public void epilogue() {
1484                             }
1485                         };
1486                     VM.getVM().getObjectHeap().iterateRaw(iterator);
1487                 } else if (type.equals("heap")) {
1488                     HeapVisitor iterator = new DefaultHeapVisitor() {
1489                             public boolean doObj(Oop obj) {
1490                                 int index = 0;
1491                                 Address start = obj.getHandle();
1492                                 long end = obj.getObjectSize();
1493                                 while (index < end) {
1494                                     Address val = start.getAddressAt(index);
1495                                     if (AddressOps.equal(val, value)) {
1496                                         out.println("found in " + obj.getHandle());
1497                                         break;
1498                                     }
1499                                     index += 4;
1500                                 }
1501                                 return false;
1502                             }
1503                         };
1504                         VM.getVM().getObjectHeap().iterate(iterator);
1505                 } else if (type.equals("codecache")) {
1506                     CodeCacheVisitor v = new CodeCacheVisitor() {
1507                             public void prologue(Address start, Address end) {
1508                             }
1509                             public void visit(CodeBlob blob) {
1510                                 boolean printed = false;
1511                                 Address base = blob.getAddress();
1512                                 Address end = base.addOffsetTo(blob.getSize());
1513                                 while (base != null && base.lessThan(end)) {
1514                                     Address val = base.getAddressAt(0);
1515                                     if (AddressOps.equal(val, value)) {
1516                                         if (!printed) {
1517                                             printed = true;
1518                                             try {
1519                                                 blob.printOn(out);
1520                                             } catch (Exception e) {
1521                                                 out.println("Exception printing blob at " + base);
1522                                                 e.printStackTrace();
1523                                             }
1524                                         }
1525                                         out.println("found at " + base + "\n");
1526                                     }
1527                                     base = base.addOffsetTo(stride);
1528                                 }
1529                             }
1530                             public void epilogue() {
1531                             }
1532 
1533 
1534                         };
1535                     VM.getVM().getCodeCache().iterate(v);
1536 
1537                 }
1538             }
1539         },
1540         new Command("dumpcodecache", "dumpcodecache", false) {
1541             public void doit(Tokens t) {
1542                 if (t.countTokens() != 0) {
1543                     usage();
1544                 } else {
1545                     final PrintStream fout = out;
1546                     final HTMLGenerator gen = new HTMLGenerator(false);
1547                     CodeCacheVisitor v = new CodeCacheVisitor() {
1548                             public void prologue(Address start, Address end) {
1549                             }
1550                             public void visit(CodeBlob blob) {
1551                                 fout.println(gen.genHTML(blob.contentBegin()));
1552                             }
1553                             public void epilogue() {
1554                             }
1555 
1556 
1557                         };
1558                     VM.getVM().getCodeCache().iterate(v);
1559                 }
1560             }
1561         },
1562         new Command("where", "where { -a | id }", false) {
1563             public void doit(Tokens t) {
1564                 if (t.countTokens() != 1) {
1565                     usage();
1566                 } else {
1567                     String name = t.nextToken();
1568                     Threads threads = VM.getVM().getThreads();
1569                     boolean all = name.equals("-a");
1570                     for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
1571                         ByteArrayOutputStream bos = new ByteArrayOutputStream();
1572                         thread.printThreadIDOn(new PrintStream(bos));
1573                         if (all || bos.toString().equals(name)) {
1574                             out.println("Thread " + bos.toString() + " Address: " + thread.getAddress());
1575                             HTMLGenerator gen = new HTMLGenerator(false);
1576                             try {
1577                                 out.println(gen.genHTMLForJavaStackTrace(thread));
1578                             } catch (Exception e) {
1579                                 err.println("Error: " + e);
1580                                 if (verboseExceptions) {
1581                                     e.printStackTrace(err);
1582                                 }
1583                             }
1584                             if (!all) return;
1585                         }
1586                     }
1587                     if (!all) out.println("Couldn't find thread " + name);
1588                 }
1589             }
1590         },
1591         new Command("thread", "thread { -a | id }", false) {
1592             public void doit(Tokens t) {
1593                 if (t.countTokens() != 1) {
1594                     usage();
1595                 } else {
1596                     String name = t.nextToken();
1597                     Threads threads = VM.getVM().getThreads();
1598                     boolean all = name.equals("-a");
1599                     for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
1600                         ByteArrayOutputStream bos = new ByteArrayOutputStream();
1601                         thread.printThreadIDOn(new PrintStream(bos));
1602                         if (all || bos.toString().equals(name)) {
1603                             out.println("Thread " + bos.toString() + " Address " + thread.getAddress());
1604                             if (!all) return;
1605                         }
1606                     }
1607                     out.println("Couldn't find thread " + name);
1608                 }
1609             }
1610         },
1611 
1612         new Command("threads", false) {
1613             public void doit(Tokens t) {
1614                 if (t.countTokens() != 0) {
1615                     usage();
1616                 } else {
1617                     Threads threads = VM.getVM().getThreads();
1618                     for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
1619                         thread.printThreadIDOn(out);
1620                         out.println(" " + thread.getThreadName());
1621                     }
1622                 }
1623             }
1624         },
1625 
1626         new Command("livenmethods", false) {
1627             public void doit(Tokens t) {
1628                 if (t.countTokens() != 0) {
1629                     usage();
1630                 } else {
1631                     ArrayList nmethods = new ArrayList();
1632                     Threads threads = VM.getVM().getThreads();
1633                     HTMLGenerator gen = new HTMLGenerator(false);
1634                     for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
1635                         try {
1636                             for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
1637                                 if (vf instanceof CompiledVFrame) {
1638                                     NMethod c = ((CompiledVFrame)vf).getCode();
1639                                     if (!nmethods.contains(c)) {
1640                                         nmethods.add(c);
1641                                         out.println(gen.genHTML(c));
1642                                     }
1643                                 }
1644                             }
1645                         } catch (Exception e) {
1646                             e.printStackTrace();
1647                         }
1648                     }
1649                 }
1650             }
1651         },
1652         new Command("universe", false) {
1653             public void doit(Tokens t) {
1654                 if (t.countTokens() != 0) {
1655                     usage();
1656                 } else {
1657                     Universe u = VM.getVM().getUniverse();
1658                     out.println("Heap Parameters:");
1659                     u.heap().printOn(out);
1660                 }
1661             }
1662         },
1663         new Command("verbose", "verbose true | false", true) {
1664             public void doit(Tokens t) {
1665                 if (t.countTokens() != 1) {
1666                     usage();
1667                 } else {
1668                     verboseExceptions = Boolean.valueOf(t.nextToken()).booleanValue();
1669                 }
1670             }
1671         },
1672         new Command("assert", "assert true | false", true) {
1673             public void doit(Tokens t) {
1674                 if (t.countTokens() != 1) {
1675                     usage();
1676                 } else {
1677                     Assert.ASSERTS_ENABLED = Boolean.valueOf(t.nextToken()).booleanValue();
1678                 }
1679             }
1680         },
1681     };
1682 
1683     private boolean verboseExceptions = false;
1684     private ArrayList history = new ArrayList();
1685     private HashMap commands = new HashMap();
1686     private boolean doEcho = false;
1687 
1688     private Command findCommand(String key) {
1689         return (Command)commands.get(key);
1690     }
1691 
1692     public void printPrompt() {
1693         out.print("hsdb> ");
1694     }
1695 
1696     private DebuggerInterface debugger;
1697     private HotSpotAgent agent;
1698     private JSJavaScriptEngine jsengine;
1699     private BufferedReader in;
1700     private PrintStream out;
1701     private PrintStream err;
1702 
1703     // called before debuggee attach
1704     private void preAttach() {
1705         // nothing for now..
1706     }
1707 
1708     // called after debuggee attach
1709     private void postAttach() {
1710         // create JavaScript engine and start it
1711         jsengine = new JSJavaScriptEngine() {
1712                         private ObjectReader reader = new ObjectReader();
1713                         private JSJavaFactory factory = new JSJavaFactoryImpl();
1714                         public ObjectReader getObjectReader() {
1715                             return reader;
1716                         }
1717                         public JSJavaFactory getJSJavaFactory() {
1718                             return factory;
1719                         }
1720                         protected void quit() {
1721                             debugger.detach();
1722                             quit = true;
1723                         }
1724                         protected BufferedReader getInputReader() {
1725                             return in;
1726                         }
1727                         protected PrintStream getOutputStream() {
1728                             return out;
1729                         }
1730                         protected PrintStream getErrorStream() {
1731                             return err;
1732                         }
1733                    };
1734         try {
1735             jsengine.defineFunction(this,
1736                      this.getClass().getMethod("registerCommand",
1737                                 new Class[] {
1738                                      String.class, String.class, String.class
1739                                 }));
1740         } catch (NoSuchMethodException exp) {
1741             // should not happen, see below...!!
1742             exp.printStackTrace();
1743         }
1744         jsengine.start();
1745     }
1746 
1747     public void registerCommand(String cmd, String usage, final String func) {
1748         commands.put(cmd, new Command(cmd, usage, false) {
1749                               public void doit(Tokens t) {
1750                                   final int len = t.countTokens();
1751                                   Object[] args = new Object[len];
1752                                   for (int i = 0; i < len; i++) {
1753                                       args[i] = t.nextToken();
1754                                   }
1755                                   jsengine.call(func, args);
1756                               }
1757                           });
1758     }
1759 
1760     public void setOutput(PrintStream o) {
1761         out = o;
1762     }
1763 
1764     public void setErr(PrintStream e) {
1765         err = e;
1766     }
1767 
1768     public CommandProcessor(DebuggerInterface debugger, BufferedReader in, PrintStream out, PrintStream err) {
1769         this.debugger = debugger;
1770         this.agent = debugger.getAgent();
1771         this.in = in;
1772         this.out = out;
1773         this.err = err;
1774         for (int i = 0; i < commandList.length; i++) {
1775             Command c = commandList[i];
1776             if (commands.get(c.name) != null) {
1777                 throw new InternalError(c.name + " has multiple definitions");
1778             }
1779             commands.put(c.name, c);
1780         }
1781         if (debugger.isAttached()) {
1782             postAttach();
1783         }
1784     }
1785 
1786 
1787     public void run(boolean prompt) {
1788         // Process interactive commands.
1789         while (!quit) {
1790             if (prompt) printPrompt();
1791             String ln = null;
1792             try {
1793                 ln = in.readLine();
1794             } catch (IOException e) {
1795             }
1796             if (ln == null) {
1797                 if (prompt) err.println("Input stream closed.");
1798                 return;
1799             }
1800 
1801             executeCommand(ln, prompt);
1802         }
1803     }
1804 
1805     static Pattern historyPattern = Pattern.compile("((!\\*)|(!\\$)|(!!-?)|(!-?[0-9][0-9]*)|(![a-zA-Z][^ ]*))");
1806 
1807     public void executeCommand(String ln, boolean putInHistory) {
1808         if (ln.indexOf('!') != -1) {
1809             int size = history.size();
1810             if (size == 0) {
1811                 ln = "";
1812                 err.println("History is empty");
1813             } else {
1814                 StringBuffer result = new StringBuffer();
1815                 Matcher m = historyPattern.matcher(ln);
1816                 int start = 0;
1817                 while (m.find()) {
1818                     if (m.start() > start) {
1819                         result.append(ln.substring(start, m.start() - start));
1820                     }
1821                     start = m.end();
1822 
1823                     String cmd = m.group();
1824                     if (cmd.equals("!!")) {
1825                         result.append((String)history.get(history.size() - 1));
1826                     } else if (cmd.equals("!!-")) {
1827                         Tokens item = new Tokens((String)history.get(history.size() - 1));
1828                         item.trim(1);
1829                         result.append(item.join(" "));
1830                     } else if (cmd.equals("!*")) {
1831                         Tokens item = new Tokens((String)history.get(history.size() - 1));
1832                         item.nextToken();
1833                         result.append(item.join(" "));
1834                     } else if (cmd.equals("!$")) {
1835                         Tokens item = new Tokens((String)history.get(history.size() - 1));
1836                         result.append(item.at(item.countTokens() - 1));
1837                     } else {
1838                         String tail = cmd.substring(1);
1839                         switch (tail.charAt(0)) {
1840                         case '0':
1841                         case '1':
1842                         case '2':
1843                         case '3':
1844                         case '4':
1845                         case '5':
1846                         case '6':
1847                         case '7':
1848                         case '8':
1849                         case '9':
1850                         case '-': {
1851                             int index = Integer.parseInt(tail);
1852                             if (index < 0) {
1853                                 index = history.size() + index;
1854                             }
1855                             if (index > size) {
1856                                 err.println("No such history item");
1857                             } else {
1858                                 result.append((String)history.get(index));
1859                             }
1860                             break;
1861                         }
1862                         default: {
1863                             for (int i = history.size() - 1; i >= 0; i--) {
1864                                 String s = (String)history.get(i);
1865                                 if (s.startsWith(tail)) {
1866                                     result.append(s);
1867                                 }
1868                             }
1869                         }
1870                         }
1871                     }
1872                 }
1873                 if (result.length() == 0) {
1874                     err.println("malformed history reference");
1875                     ln = "";
1876                 } else {
1877                     if (start < ln.length()) {
1878                         result.append(ln.substring(start));
1879                     }
1880                     ln = result.toString();
1881                     if (!doEcho) {
1882                         out.println(ln);
1883                     }
1884                 }
1885             }
1886         }
1887 
1888         if (doEcho) {
1889             out.println("+ " + ln);
1890         }
1891 
1892         PrintStream redirect = null;
1893         Tokens t = new Tokens(ln);
1894         if (t.hasMoreTokens()) {
1895             boolean error = false;
1896             if (putInHistory) history.add(ln);
1897             int len = t.countTokens();
1898             if (len > 2) {
1899                 String r = t.at(len - 2);
1900                 if (r.equals(">") || r.equals(">>")) {
1901                     boolean append = r.length() == 2;
1902                     String file = t.at(len - 1);
1903                     try {
1904                         redirect = new PrintStream(new BufferedOutputStream(new FileOutputStream(file, append)));
1905                         t.trim(2);
1906                     } catch (Exception e) {
1907                         out.println("Error: " + e);
1908                         if (verboseExceptions) {
1909                             e.printStackTrace(out);
1910                         }
1911                         error = true;
1912                     }
1913                 }
1914             }
1915             if (!error) {
1916                 PrintStream savedout = out;
1917                 if (redirect != null) {
1918                     out = redirect;
1919                 }
1920                 try {
1921                     executeCommand(t);
1922                 } catch (Exception e) {
1923                     err.println("Error: " + e);
1924                     if (verboseExceptions) {
1925                         e.printStackTrace(err);
1926                     }
1927                 } finally {
1928                     if (redirect != null) {
1929                         out = savedout;
1930                         redirect.close();
1931                     }
1932                 }
1933             }
1934         }
1935     }
1936 
1937     void executeCommand(Tokens args) {
1938         String cmd = args.nextToken();
1939 
1940         Command doit = findCommand(cmd);
1941 
1942         /*
1943          * Check for an unknown command
1944          */
1945         if (doit == null) {
1946             out.println("Unrecognized command.  Try help...");
1947         } else if (!debugger.isAttached() && !doit.okIfDisconnected) {
1948             out.println("Command not valid until the attached to a VM");
1949         } else {
1950             try {
1951                 doit.doit(args);
1952             } catch (Exception e) {
1953                 out.println("Error: " + e);
1954                 if (verboseExceptions) {
1955                     e.printStackTrace(out);
1956                 }
1957             }
1958         }
1959     }
1960 }