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