History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/tools/example/debug/tty/Commands.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/example/debug/tty/Commands.java+2098−0
@@ -0,0 +1,2098 @@
1/*
2 * Copyright (c) 1998, 2008, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.example.debug.tty;
27
28import com.sun.jdi.*;
29import com.sun.jdi.connect.Connector;
30import com.sun.jdi.request.*;
31import com.sun.tools.example.debug.expr.ExpressionParser;
32import com.sun.tools.example.debug.expr.ParseException;
33
34import java.text.*;
35import java.util.*;
36import java.io.*;
37
38class Commands {
39
40 abstract class AsyncExecution {
41 abstract void action();
42
43 AsyncExecution() {
44 execute();
45 }
46
47 void execute() {
48 /*
49 * Save current thread and stack frame. (BugId 4296031)
50 */
51 final ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
52 final int stackFrame = threadInfo == null? 0 : threadInfo.getCurrentFrameIndex();
53 Thread thread = new Thread("asynchronous jdb command") {
54 @Override
55 public void run() {
56 try {
57 action();
58 } catch (UnsupportedOperationException uoe) {
59 //(BugId 4453329)
60 MessageOutput.println("Operation is not supported on the target VM");
61 } catch (Exception e) {
62 MessageOutput.println("Internal exception during operation:",
63 e.getMessage());
64 } finally {
65 /*
66 * This was an asynchronous command. Events may have been
67 * processed while it was running. Restore the thread and
68 * stack frame the user was looking at. (BugId 4296031)
69 */
70 if (threadInfo != null) {
71 ThreadInfo.setCurrentThreadInfo(threadInfo);
72 try {
73 threadInfo.setCurrentFrameIndex(stackFrame);
74 } catch (IncompatibleThreadStateException e) {
75 MessageOutput.println("Current thread isnt suspended.");
76 } catch (ArrayIndexOutOfBoundsException e) {
77 MessageOutput.println("Requested stack frame is no longer active:",
78 new Object []{new Integer(stackFrame)});
79 }
80 }
81 MessageOutput.printPrompt();
82 }
83 }
84 };
85 thread.start();
86 }
87 }
88
89 Commands() {
90 }
91
92 private Value evaluate(String expr) {
93 Value result = null;
94 ExpressionParser.GetFrame frameGetter = null;
95 try {
96 final ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
97 if ((threadInfo != null) && (threadInfo.getCurrentFrame() != null)) {
98 frameGetter = new ExpressionParser.GetFrame() {
99 @Override
100 public StackFrame get() throws IncompatibleThreadStateException {
101 return threadInfo.getCurrentFrame();
102 }
103 };
104 }
105 result = ExpressionParser.evaluate(expr, Env.vm(), frameGetter);
106 } catch (InvocationException ie) {
107 MessageOutput.println("Exception in expression:",
108 ie.exception().referenceType().name());
109 } catch (Exception ex) {
110 String exMessage = ex.getMessage();
111 if (exMessage == null) {
112 MessageOutput.printException(exMessage, ex);
113 } else {
114 String s;
115 try {
116 s = MessageOutput.format(exMessage);
117 } catch (MissingResourceException mex) {
118 s = ex.toString();
119 }
120 MessageOutput.printDirectln(s);// Special case: use printDirectln()
121 }
122 }
123 return result;
124 }
125
126 private String getStringValue() {
127 Value val = null;
128 String valStr = null;
129 try {
130 val = ExpressionParser.getMassagedValue();
131 valStr = val.toString();
132 } catch (ParseException e) {
133 String msg = e.getMessage();
134 if (msg == null) {
135 MessageOutput.printException(msg, e);
136 } else {
137 String s;
138 try {
139 s = MessageOutput.format(msg);
140 } catch (MissingResourceException mex) {
141 s = e.toString();
142 }
143 MessageOutput.printDirectln(s);
144 }
145 }
146 return valStr;
147 }
148
149 private ThreadInfo doGetThread(String idToken) {
150 ThreadInfo threadInfo = ThreadInfo.getThreadInfo(idToken);
151 if (threadInfo == null) {
152 MessageOutput.println("is not a valid thread id", idToken);
153 }
154 return threadInfo;
155 }
156
157 String typedName(Method method) {
158 StringBuffer buf = new StringBuffer();
159 buf.append(method.name());
160 buf.append("(");
161
162 List<String> args = method.argumentTypeNames();
163 int lastParam = args.size() - 1;
164 // output param types except for the last
165 for (int ii = 0; ii < lastParam; ii++) {
166 buf.append(args.get(ii));
167 buf.append(", ");
168 }
169 if (lastParam >= 0) {
170 // output the last param
171 String lastStr = args.get(lastParam);
172 if (method.isVarArgs()) {
173 // lastParam is an array. Replace the [] with ...
174 buf.append(lastStr.substring(0, lastStr.length() - 2));
175 buf.append("...");
176 } else {
177 buf.append(lastStr);
178 }
179 }
180 buf.append(")");
181 return buf.toString();
182 }
183
184 void commandConnectors(VirtualMachineManager vmm) {
185 Collection<Connector> ccs = vmm.allConnectors();
186 if (ccs.isEmpty()) {
187 MessageOutput.println("Connectors available");
188 }
189 for (Connector cc : ccs) {
190 String transportName =
191 cc.transport() == null ? "null" : cc.transport().name();
192 MessageOutput.println();
193 MessageOutput.println("Connector and Transport name",
194 new Object [] {cc.name(), transportName});
195 MessageOutput.println("Connector description", cc.description());
196
197 for (Connector.Argument aa : cc.defaultArguments().values()) {
198 MessageOutput.println();
199
200 boolean requiredArgument = aa.mustSpecify();
201 if (aa.value() == null || aa.value() == "") {
202 //no current value and no default.
203 MessageOutput.println(requiredArgument ?
204 "Connector required argument nodefault" :
205 "Connector argument nodefault", aa.name());
206 } else {
207 MessageOutput.println(requiredArgument ?
208 "Connector required argument default" :
209 "Connector argument default",
210 new Object [] {aa.name(), aa.value()});
211 }
212 MessageOutput.println("Connector description", aa.description());
213
214 }
215 }
216
217 }
218
219 void commandClasses() {
220 StringBuffer classList = new StringBuffer();
221 for (ReferenceType refType : Env.vm().allClasses()) {
222 classList.append(refType.name());
223 classList.append("\n");
224 }
225 MessageOutput.print("** classes list **", classList.toString());
226 }
227
228 void commandClass(StringTokenizer t) {
229
230 if (!t.hasMoreTokens()) {
231 MessageOutput.println("No class specified.");
232 return;
233 }
234
235 String idClass = t.nextToken();
236 boolean showAll = false;
237
238 if (t.hasMoreTokens()) {
239 if (t.nextToken().toLowerCase().equals("all")) {
240 showAll = true;
241 } else {
242 MessageOutput.println("Invalid option on class command");
243 return;
244 }
245 }
246 ReferenceType type = Env.getReferenceTypeFromToken(idClass);
247 if (type == null) {
248 MessageOutput.println("is not a valid id or class name", idClass);
249 return;
250 }
251 if (type instanceof ClassType) {
252 ClassType clazz = (ClassType)type;
253 MessageOutput.println("Class:", clazz.name());
254
255 ClassType superclass = clazz.superclass();
256 while (superclass != null) {
257 MessageOutput.println("extends:", superclass.name());
258 superclass = showAll ? superclass.superclass() : null;
259 }
260
261 List<InterfaceType> interfaces =
262 showAll ? clazz.allInterfaces() : clazz.interfaces();
263 for (InterfaceType interfaze : interfaces) {
264 MessageOutput.println("implements:", interfaze.name());
265 }
266
267 for (ClassType sub : clazz.subclasses()) {
268 MessageOutput.println("subclass:", sub.name());
269 }
270 for (ReferenceType nest : clazz.nestedTypes()) {
271 MessageOutput.println("nested:", nest.name());
272 }
273 } else if (type instanceof InterfaceType) {
274 InterfaceType interfaze = (InterfaceType)type;
275 MessageOutput.println("Interface:", interfaze.name());
276 for (InterfaceType superinterface : interfaze.superinterfaces()) {
277 MessageOutput.println("extends:", superinterface.name());
278 }
279 for (InterfaceType sub : interfaze.subinterfaces()) {
280 MessageOutput.println("subinterface:", sub.name());
281 }
282 for (ClassType implementor : interfaze.implementors()) {
283 MessageOutput.println("implementor:", implementor.name());
284 }
285 for (ReferenceType nest : interfaze.nestedTypes()) {
286 MessageOutput.println("nested:", nest.name());
287 }
288 } else { // array type
289 ArrayType array = (ArrayType)type;
290 MessageOutput.println("Array:", array.name());
291 }
292 }
293
294 void commandMethods(StringTokenizer t) {
295 if (!t.hasMoreTokens()) {
296 MessageOutput.println("No class specified.");
297 return;
298 }
299
300 String idClass = t.nextToken();
301 ReferenceType cls = Env.getReferenceTypeFromToken(idClass);
302 if (cls != null) {
303 StringBuffer methodsList = new StringBuffer();
304 for (Method method : cls.allMethods()) {
305 methodsList.append(method.declaringType().name());
306 methodsList.append(" ");
307 methodsList.append(typedName(method));
308 methodsList.append('\n');
309 }
310 MessageOutput.print("** methods list **", methodsList.toString());
311 } else {
312 MessageOutput.println("is not a valid id or class name", idClass);
313 }
314 }
315
316 void commandFields(StringTokenizer t) {
317 if (!t.hasMoreTokens()) {
318 MessageOutput.println("No class specified.");
319 return;
320 }
321
322 String idClass = t.nextToken();
323 ReferenceType cls = Env.getReferenceTypeFromToken(idClass);
324 if (cls != null) {
325 List<Field> fields = cls.allFields();
326 List<Field> visible = cls.visibleFields();
327 StringBuffer fieldsList = new StringBuffer();
328 for (Field field : fields) {
329 String s;
330 if (!visible.contains(field)) {
331 s = MessageOutput.format("list field typename and name hidden",
332 new Object [] {field.typeName(),
333 field.name()});
334 } else if (!field.declaringType().equals(cls)) {
335 s = MessageOutput.format("list field typename and name inherited",
336 new Object [] {field.typeName(),
337 field.name(),
338 field.declaringType().name()});
339 } else {
340 s = MessageOutput.format("list field typename and name",
341 new Object [] {field.typeName(),
342 field.name()});
343 }
344 fieldsList.append(s);
345 }
346 MessageOutput.print("** fields list **", fieldsList.toString());
347 } else {
348 MessageOutput.println("is not a valid id or class name", idClass);
349 }
350 }
351
352 private void printThreadGroup(ThreadGroupReference tg) {
353 ThreadIterator threadIter = new ThreadIterator(tg);
354
355 MessageOutput.println("Thread Group:", tg.name());
356 int maxIdLength = 0;
357 int maxNameLength = 0;
358 while (threadIter.hasNext()) {
359 ThreadReference thr = threadIter.next();
360 maxIdLength = Math.max(maxIdLength,
361 Env.description(thr).length());
362 maxNameLength = Math.max(maxNameLength,
363 thr.name().length());
364 }
365
366 threadIter = new ThreadIterator(tg);
367 while (threadIter.hasNext()) {
368 ThreadReference thr = threadIter.next();
369 if (thr.threadGroup() == null) {
370 continue;
371 }
372 // Note any thread group changes
373 if (!thr.threadGroup().equals(tg)) {
374 tg = thr.threadGroup();
375 MessageOutput.println("Thread Group:", tg.name());
376 }
377
378 /*
379 * Do a bit of filling with whitespace to get thread ID
380 * and thread names to line up in the listing, and also
381 * allow for proper localization. This also works for
382 * very long thread names, at the possible cost of lines
383 * being wrapped by the display device.
384 */
385 StringBuffer idBuffer = new StringBuffer(Env.description(thr));
386 for (int i = idBuffer.length(); i < maxIdLength; i++) {
387 idBuffer.append(" ");
388 }
389 StringBuffer nameBuffer = new StringBuffer(thr.name());
390 for (int i = nameBuffer.length(); i < maxNameLength; i++) {
391 nameBuffer.append(" ");
392 }
393
394 /*
395 * Select the output format to use based on thread status
396 * and breakpoint.
397 */
398 String statusFormat;
399 switch (thr.status()) {
400 case ThreadReference.THREAD_STATUS_UNKNOWN:
401 if (thr.isAtBreakpoint()) {
402 statusFormat = "Thread description name unknownStatus BP";
403 } else {
404 statusFormat = "Thread description name unknownStatus";
405 }
406 break;
407 case ThreadReference.THREAD_STATUS_ZOMBIE:
408 if (thr.isAtBreakpoint()) {
409 statusFormat = "Thread description name zombieStatus BP";
410 } else {
411 statusFormat = "Thread description name zombieStatus";
412 }
413 break;
414 case ThreadReference.THREAD_STATUS_RUNNING:
415 if (thr.isAtBreakpoint()) {
416 statusFormat = "Thread description name runningStatus BP";
417 } else {
418 statusFormat = "Thread description name runningStatus";
419 }
420 break;
421 case ThreadReference.THREAD_STATUS_SLEEPING:
422 if (thr.isAtBreakpoint()) {
423 statusFormat = "Thread description name sleepingStatus BP";
424 } else {
425 statusFormat = "Thread description name sleepingStatus";
426 }
427 break;
428 case ThreadReference.THREAD_STATUS_MONITOR:
429 if (thr.isAtBreakpoint()) {
430 statusFormat = "Thread description name waitingStatus BP";
431 } else {
432 statusFormat = "Thread description name waitingStatus";
433 }
434 break;
435 case ThreadReference.THREAD_STATUS_WAIT:
436 if (thr.isAtBreakpoint()) {
437 statusFormat = "Thread description name condWaitstatus BP";
438 } else {
439 statusFormat = "Thread description name condWaitstatus";
440 }
441 break;
442 default:
443 throw new InternalError(MessageOutput.format("Invalid thread status."));
444 }
445 MessageOutput.println(statusFormat,
446 new Object [] {idBuffer.toString(),
447 nameBuffer.toString()});
448 }
449 }
450
451 void commandThreads(StringTokenizer t) {
452 if (!t.hasMoreTokens()) {
453 printThreadGroup(ThreadInfo.group());
454 return;
455 }
456 String name = t.nextToken();
457 ThreadGroupReference tg = ThreadGroupIterator.find(name);
458 if (tg == null) {
459 MessageOutput.println("is not a valid threadgroup name", name);
460 } else {
461 printThreadGroup(tg);
462 }
463 }
464
465 void commandThreadGroups() {
466 ThreadGroupIterator it = new ThreadGroupIterator();
467 int cnt = 0;
468 while (it.hasNext()) {
469 ThreadGroupReference tg = it.nextThreadGroup();
470 ++cnt;
471 MessageOutput.println("thread group number description name",
472 new Object [] { new Integer (cnt),
473 Env.description(tg),
474 tg.name()});
475 }
476 }
477
478 void commandThread(StringTokenizer t) {
479 if (!t.hasMoreTokens()) {
480 MessageOutput.println("Thread number not specified.");
481 return;
482 }
483 ThreadInfo threadInfo = doGetThread(t.nextToken());
484 if (threadInfo != null) {
485 ThreadInfo.setCurrentThreadInfo(threadInfo);
486 }
487 }
488
489 void commandThreadGroup(StringTokenizer t) {
490 if (!t.hasMoreTokens()) {
491 MessageOutput.println("Threadgroup name not specified.");
492 return;
493 }
494 String name = t.nextToken();
495 ThreadGroupReference tg = ThreadGroupIterator.find(name);
496 if (tg == null) {
497 MessageOutput.println("is not a valid threadgroup name", name);
498 } else {
499 ThreadInfo.setThreadGroup(tg);
500 }
501 }
502
503 void commandRun(StringTokenizer t) {
504 /*
505 * The 'run' command makes little sense in a
506 * that doesn't support restarts or multiple VMs. However,
507 * this is an attempt to emulate the behavior of the old
508 * JDB as much as possible. For new users and implementations
509 * it is much more straightforward to launch immedidately
510 * with the -launch option.
511 */
512 VMConnection connection = Env.connection();
513 if (!connection.isLaunch()) {
514 if (!t.hasMoreTokens()) {
515 commandCont();
516 } else {
517 MessageOutput.println("run <args> command is valid only with launched VMs");
518 }
519 return;
520 }
521 if (connection.isOpen()) {
522 MessageOutput.println("VM already running. use cont to continue after events.");
523 return;
524 }
525
526 /*
527 * Set the main class and any arguments. Note that this will work
528 * only with the standard launcher, "com.sun.jdi.CommandLineLauncher"
529 */
530 String args;
531 if (t.hasMoreTokens()) {
532 args = t.nextToken("");
533 boolean argsSet = connection.setConnectorArg("main", args);
534 if (!argsSet) {
535 MessageOutput.println("Unable to set main class and arguments");
536 return;
537 }
538 } else {
539 args = connection.connectorArg("main");
540 if (args.length() == 0) {
541 MessageOutput.println("Main class and arguments must be specified");
542 return;
543 }
544 }
545 MessageOutput.println("run", args);
546
547 /*
548 * Launch the VM.
549 */
550 connection.open();
551
552 }
553
554 void commandLoad(StringTokenizer t) {
555 MessageOutput.println("The load command is no longer supported.");
556 }
557
558 private List<ThreadReference> allThreads(ThreadGroupReference group) {
559 List<ThreadReference> list = new ArrayList<ThreadReference>();
560 list.addAll(group.threads());
561 for (ThreadGroupReference child : group.threadGroups()) {
562 list.addAll(allThreads(child));
563 }
564 return list;
565 }
566
567 void commandSuspend(StringTokenizer t) {
568 if (!t.hasMoreTokens()) {
569 Env.vm().suspend();
570 MessageOutput.println("All threads suspended.");
571 } else {
572 while (t.hasMoreTokens()) {
573 ThreadInfo threadInfo = doGetThread(t.nextToken());
574 if (threadInfo != null) {
575 threadInfo.getThread().suspend();
576 }
577 }
578 }
579 }
580
581 void commandResume(StringTokenizer t) {
582 if (!t.hasMoreTokens()) {
583 ThreadInfo.invalidateAll();
584 Env.vm().resume();
585 MessageOutput.println("All threads resumed.");
586 } else {
587 while (t.hasMoreTokens()) {
588 ThreadInfo threadInfo = doGetThread(t.nextToken());
589 if (threadInfo != null) {
590 threadInfo.invalidate();
591 threadInfo.getThread().resume();
592 }
593 }
594 }
595 }
596
597 void commandCont() {
598 if (ThreadInfo.getCurrentThreadInfo() == null) {
599 MessageOutput.println("Nothing suspended.");
600 return;
601 }
602 ThreadInfo.invalidateAll();
603 Env.vm().resume();
604 }
605
606 void clearPreviousStep(ThreadReference thread) {
607 /*
608 * A previous step may not have completed on this thread;
609 * if so, it gets removed here.
610 */
611 EventRequestManager mgr = Env.vm().eventRequestManager();
612 for (StepRequest request : mgr.stepRequests()) {
613 if (request.thread().equals(thread)) {
614 mgr.deleteEventRequest(request);
615 break;
616 }
617 }
618 }
619 /* step
620 *
621 */
622 void commandStep(StringTokenizer t) {
623 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
624 if (threadInfo == null) {
625 MessageOutput.println("Nothing suspended.");
626 return;
627 }
628 int depth;
629 if (t.hasMoreTokens() &&
630 t.nextToken().toLowerCase().equals("up")) {
631 depth = StepRequest.STEP_OUT;
632 } else {
633 depth = StepRequest.STEP_INTO;
634 }
635
636 clearPreviousStep(threadInfo.getThread());
637 EventRequestManager reqMgr = Env.vm().eventRequestManager();
638 StepRequest request = reqMgr.createStepRequest(threadInfo.getThread(),
639 StepRequest.STEP_LINE, depth);
640 if (depth == StepRequest.STEP_INTO) {
641 Env.addExcludes(request);
642 }
643 // We want just the next step event and no others
644 request.addCountFilter(1);
645 request.enable();
646 ThreadInfo.invalidateAll();
647 Env.vm().resume();
648 }
649
650 /* stepi
651 * step instruction.
652 */
653 void commandStepi() {
654 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
655 if (threadInfo == null) {
656 MessageOutput.println("Nothing suspended.");
657 return;
658 }
659 clearPreviousStep(threadInfo.getThread());
660 EventRequestManager reqMgr = Env.vm().eventRequestManager();
661 StepRequest request = reqMgr.createStepRequest(threadInfo.getThread(),
662 StepRequest.STEP_MIN,
663 StepRequest.STEP_INTO);
664 Env.addExcludes(request);
665 // We want just the next step event and no others
666 request.addCountFilter(1);
667 request.enable();
668 ThreadInfo.invalidateAll();
669 Env.vm().resume();
670 }
671
672 void commandNext() {
673 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
674 if (threadInfo == null) {
675 MessageOutput.println("Nothing suspended.");
676 return;
677 }
678 clearPreviousStep(threadInfo.getThread());
679 EventRequestManager reqMgr = Env.vm().eventRequestManager();
680 StepRequest request = reqMgr.createStepRequest(threadInfo.getThread(),
681 StepRequest.STEP_LINE,
682 StepRequest.STEP_OVER);
683 Env.addExcludes(request);
684 // We want just the next step event and no others
685 request.addCountFilter(1);
686 request.enable();
687 ThreadInfo.invalidateAll();
688 Env.vm().resume();
689 }
690
691 void doKill(ThreadReference thread, StringTokenizer t) {
692 if (!t.hasMoreTokens()) {
693 MessageOutput.println("No exception object specified.");
694 return;
695 }
696 String expr = t.nextToken("");
697 Value val = evaluate(expr);
698 if ((val != null) && (val instanceof ObjectReference)) {
699 try {
700 thread.stop((ObjectReference)val);
701 MessageOutput.println("killed", thread.toString());
702 } catch (InvalidTypeException e) {
703 MessageOutput.println("Invalid exception object");
704 }
705 } else {
706 MessageOutput.println("Expression must evaluate to an object");
707 }
708 }
709
710 void doKillThread(final ThreadReference threadToKill,
711 final StringTokenizer tokenizer) {
712 new AsyncExecution() {
713 @Override
714 void action() {
715 doKill(threadToKill, tokenizer);
716 }
717 };
718 }
719
720 void commandKill(StringTokenizer t) {
721 if (!t.hasMoreTokens()) {
722 MessageOutput.println("Usage: kill <thread id> <throwable>");
723 return;
724 }
725 ThreadInfo threadInfo = doGetThread(t.nextToken());
726 if (threadInfo != null) {
727 MessageOutput.println("killing thread:", threadInfo.getThread().name());
728 doKillThread(threadInfo.getThread(), t);
729 return;
730 }
731 }
732
733 void listCaughtExceptions() {
734 boolean noExceptions = true;
735
736 // Print a listing of the catch patterns currently in place
737 for (EventRequestSpec spec : Env.specList.eventRequestSpecs()) {
738 if (spec instanceof ExceptionSpec) {
739 if (noExceptions) {
740 noExceptions = false;
741 MessageOutput.println("Exceptions caught:");
742 }
743 MessageOutput.println("tab", spec.toString());
744 }
745 }
746 if (noExceptions) {
747 MessageOutput.println("No exceptions caught.");
748 }
749 }
750
751 private EventRequestSpec parseExceptionSpec(StringTokenizer t) {
752 String notification = t.nextToken();
753 boolean notifyCaught = false;
754 boolean notifyUncaught = false;
755 EventRequestSpec spec = null;
756 String classPattern = null;
757
758 if (notification.equals("uncaught")) {
759 notifyCaught = false;
760 notifyUncaught = true;
761 } else if (notification.equals("caught")) {
762 notifyCaught = true;
763 notifyUncaught = false;
764 } else if (notification.equals("all")) {
765 notifyCaught = true;
766 notifyUncaught = true;
767 } else {
768 /*
769 * Handle the same as "all" for backward
770 * compatibility with existing .jdbrc files.
771 *
772 * Insert an "all" and take the current token as the
773 * intended classPattern
774 *
775 */
776 notifyCaught = true;
777 notifyUncaught = true;
778 classPattern = notification;
779 }
780 if (classPattern == null && t.hasMoreTokens()) {
781 classPattern = t.nextToken();
782 }
783 if ((classPattern != null) && (notifyCaught || notifyUncaught)) {
784 try {
785 spec = Env.specList.createExceptionCatch(classPattern,
786 notifyCaught,
787 notifyUncaught);
788 } catch (ClassNotFoundException exc) {
789 MessageOutput.println("is not a valid class name", classPattern);
790 }
791 }
792 return spec;
793 }
794
795 void commandCatchException(StringTokenizer t) {
796 if (!t.hasMoreTokens()) {
797 listCaughtExceptions();
798 } else {
799 EventRequestSpec spec = parseExceptionSpec(t);
800 if (spec != null) {
801 resolveNow(spec);
802 } else {
803 MessageOutput.println("Usage: catch exception");
804 }
805 }
806 }
807
808 void commandIgnoreException(StringTokenizer t) {
809 if (!t.hasMoreTokens()) {
810 listCaughtExceptions();
811 } else {
812 EventRequestSpec spec = parseExceptionSpec(t);
813 if (Env.specList.delete(spec)) {
814 MessageOutput.println("Removed:", spec.toString());
815 } else {
816 if (spec != null) {
817 MessageOutput.println("Not found:", spec.toString());
818 }
819 MessageOutput.println("Usage: ignore exception");
820 }
821 }
822 }
823
824 void commandUp(StringTokenizer t) {
825 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
826 if (threadInfo == null) {
827 MessageOutput.println("Current thread not set.");
828 return;
829 }
830
831 int nLevels = 1;
832 if (t.hasMoreTokens()) {
833 String idToken = t.nextToken();
834 int i;
835 try {
836 NumberFormat nf = NumberFormat.getNumberInstance();
837 nf.setParseIntegerOnly(true);
838 Number n = nf.parse(idToken);
839 i = n.intValue();
840 } catch (java.text.ParseException jtpe) {
841 i = 0;
842 }
843 if (i <= 0) {
844 MessageOutput.println("Usage: up [n frames]");
845 return;
846 }
847 nLevels = i;
848 }
849
850 try {
851 threadInfo.up(nLevels);
852 } catch (IncompatibleThreadStateException e) {
853 MessageOutput.println("Current thread isnt suspended.");
854 } catch (ArrayIndexOutOfBoundsException e) {
855 MessageOutput.println("End of stack.");
856 }
857 }
858
859 void commandDown(StringTokenizer t) {
860 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
861 if (threadInfo == null) {
862 MessageOutput.println("Current thread not set.");
863 return;
864 }
865
866 int nLevels = 1;
867 if (t.hasMoreTokens()) {
868 String idToken = t.nextToken();
869 int i;
870 try {
871 NumberFormat nf = NumberFormat.getNumberInstance();
872 nf.setParseIntegerOnly(true);
873 Number n = nf.parse(idToken);
874 i = n.intValue();
875 } catch (java.text.ParseException jtpe) {
876 i = 0;
877 }
878 if (i <= 0) {
879 MessageOutput.println("Usage: down [n frames]");
880 return;
881 }
882 nLevels = i;
883 }
884
885 try {
886 threadInfo.down(nLevels);
887 } catch (IncompatibleThreadStateException e) {
888 MessageOutput.println("Current thread isnt suspended.");
889 } catch (ArrayIndexOutOfBoundsException e) {
890 MessageOutput.println("End of stack.");
891 }
892 }
893
894 private void dumpStack(ThreadInfo threadInfo, boolean showPC) {
895 List<StackFrame> stack = null;
896 try {
897 stack = threadInfo.getStack();
898 } catch (IncompatibleThreadStateException e) {
899 MessageOutput.println("Current thread isnt suspended.");
900 return;
901 }
902 if (stack == null) {
903 MessageOutput.println("Thread is not running (no stack).");
904 } else {
905 int nFrames = stack.size();
906 for (int i = threadInfo.getCurrentFrameIndex(); i < nFrames; i++) {
907 StackFrame frame = stack.get(i);
908 dumpFrame (i, showPC, frame);
909 }
910 }
911 }
912
913 private void dumpFrame (int frameNumber, boolean showPC, StackFrame frame) {
914 Location loc = frame.location();
915 long pc = -1;
916 if (showPC) {
917 pc = loc.codeIndex();
918 }
919 Method meth = loc.method();
920
921 long lineNumber = loc.lineNumber();
922 String methodInfo = null;
923 if (meth.isNative()) {
924 methodInfo = MessageOutput.format("native method");
925 } else if (lineNumber != -1) {
926 try {
927 methodInfo = loc.sourceName() +
928 MessageOutput.format("line number",
929 new Object [] {new Long(lineNumber)});
930 } catch (AbsentInformationException e) {
931 methodInfo = MessageOutput.format("unknown");
932 }
933 }
934 if (pc != -1) {
935 MessageOutput.println("stack frame dump with pc",
936 new Object [] {new Integer(frameNumber + 1),
937 meth.declaringType().name(),
938 meth.name(),
939 methodInfo,
940 new Long(pc)});
941 } else {
942 MessageOutput.println("stack frame dump",
943 new Object [] {new Integer(frameNumber + 1),
944 meth.declaringType().name(),
945 meth.name(),
946 methodInfo});
947 }
948 }
949
950 void commandWhere(StringTokenizer t, boolean showPC) {
951 if (!t.hasMoreTokens()) {
952 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
953 if (threadInfo == null) {
954 MessageOutput.println("No thread specified.");
955 return;
956 }
957 dumpStack(threadInfo, showPC);
958 } else {
959 String token = t.nextToken();
960 if (token.toLowerCase().equals("all")) {
961 for (ThreadInfo threadInfo : ThreadInfo.threads()) {
962 MessageOutput.println("Thread:",
963 threadInfo.getThread().name());
964 dumpStack(threadInfo, showPC);
965 }
966 } else {
967 ThreadInfo threadInfo = doGetThread(token);
968 if (threadInfo != null) {
969 ThreadInfo.setCurrentThreadInfo(threadInfo);
970 dumpStack(threadInfo, showPC);
971 }
972 }
973 }
974 }
975
976 void commandInterrupt(StringTokenizer t) {
977 if (!t.hasMoreTokens()) {
978 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
979 if (threadInfo == null) {
980 MessageOutput.println("No thread specified.");
981 return;
982 }
983 threadInfo.getThread().interrupt();
984 } else {
985 ThreadInfo threadInfo = doGetThread(t.nextToken());
986 if (threadInfo != null) {
987 threadInfo.getThread().interrupt();
988 }
989 }
990 }
991
992 void commandMemory() {
993 MessageOutput.println("The memory command is no longer supported.");
994 }
995
996 void commandGC() {
997 MessageOutput.println("The gc command is no longer necessary.");
998 }
999
1000 /*
1001 * The next two methods are used by this class and by EventHandler
1002 * to print consistent locations and error messages.
1003 */
1004 static String locationString(Location loc) {
1005 return MessageOutput.format("locationString",
1006 new Object [] {loc.declaringType().name(),
1007 loc.method().name(),
1008 new Integer (loc.lineNumber()),
1009 new Long (loc.codeIndex())});
1010 }
1011
1012 void listBreakpoints() {
1013 boolean noBreakpoints = true;
1014
1015 // Print set breakpoints
1016 for (EventRequestSpec spec : Env.specList.eventRequestSpecs()) {
1017 if (spec instanceof BreakpointSpec) {
1018 if (noBreakpoints) {
1019 noBreakpoints = false;
1020 MessageOutput.println("Breakpoints set:");
1021 }
1022 MessageOutput.println("tab", spec.toString());
1023 }
1024 }
1025 if (noBreakpoints) {
1026 MessageOutput.println("No breakpoints set.");
1027 }
1028 }
1029
1030
1031 private void printBreakpointCommandUsage(String atForm, String inForm) {
1032 MessageOutput.println("printbreakpointcommandusage",
1033 new Object [] {atForm, inForm});
1034 }
1035
1036 protected BreakpointSpec parseBreakpointSpec(StringTokenizer t,
1037 String atForm, String inForm) {
1038 BreakpointSpec breakpoint = null;
1039 try {
1040 String token = t.nextToken(":( \t\n\r");
1041
1042 // We can't use hasMoreTokens here because it will cause any leading
1043 // paren to be lost.
1044 String rest;
1045 try {
1046 rest = t.nextToken("").trim();
1047 } catch (NoSuchElementException e) {
1048 rest = null;
1049 }
1050
1051 if ((rest != null) && rest.startsWith(":")) {
1052 t = new StringTokenizer(rest.substring(1));
1053 String classId = token;
1054 String lineToken = t.nextToken();
1055
1056 NumberFormat nf = NumberFormat.getNumberInstance();
1057 nf.setParseIntegerOnly(true);
1058 Number n = nf.parse(lineToken);
1059 int lineNumber = n.intValue();
1060
1061 if (t.hasMoreTokens()) {
1062 printBreakpointCommandUsage(atForm, inForm);
1063 return null;
1064 }
1065 try {
1066 breakpoint = Env.specList.createBreakpoint(classId,
1067 lineNumber);
1068 } catch (ClassNotFoundException exc) {
1069 MessageOutput.println("is not a valid class name", classId);
1070 }
1071 } else {
1072 // Try stripping method from class.method token.
1073 int idot = token.lastIndexOf(".");
1074 if ( (idot <= 0) || /* No dot or dot in first char */
1075 (idot >= token.length() - 1) ) { /* dot in last char */
1076 printBreakpointCommandUsage(atForm, inForm);
1077 return null;
1078 }
1079 String methodName = token.substring(idot + 1);
1080 String classId = token.substring(0, idot);
1081 List<String> argumentList = null;
1082 if (rest != null) {
1083 if (!rest.startsWith("(") || !rest.endsWith(")")) {
1084 MessageOutput.println("Invalid method specification:",
1085 methodName + rest);
1086 printBreakpointCommandUsage(atForm, inForm);
1087 return null;
1088 }
1089 // Trim the parens
1090 rest = rest.substring(1, rest.length() - 1);
1091
1092 argumentList = new ArrayList<String>();
1093 t = new StringTokenizer(rest, ",");
1094 while (t.hasMoreTokens()) {
1095 argumentList.add(t.nextToken());
1096 }
1097 }
1098 try {
1099 breakpoint = Env.specList.createBreakpoint(classId,
1100 methodName,
1101 argumentList);
1102 } catch (MalformedMemberNameException exc) {
1103 MessageOutput.println("is not a valid method name", methodName);
1104 } catch (ClassNotFoundException exc) {
1105 MessageOutput.println("is not a valid class name", classId);
1106 }
1107 }
1108 } catch (Exception e) {
1109 printBreakpointCommandUsage(atForm, inForm);
1110 return null;
1111 }
1112 return breakpoint;
1113 }
1114
1115 private void resolveNow(EventRequestSpec spec) {
1116 boolean success = Env.specList.addEagerlyResolve(spec);
1117 if (success && !spec.isResolved()) {
1118 MessageOutput.println("Deferring.", spec.toString());
1119 }
1120 }
1121
1122 void commandStop(StringTokenizer t) {
1123 String atIn;
1124 byte suspendPolicy = EventRequest.SUSPEND_ALL;
1125
1126 if (t.hasMoreTokens()) {
1127 atIn = t.nextToken();
1128 if (atIn.equals("go") && t.hasMoreTokens()) {
1129 suspendPolicy = EventRequest.SUSPEND_NONE;
1130 atIn = t.nextToken();
1131 } else if (atIn.equals("thread") && t.hasMoreTokens()) {
1132 suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD;
1133 atIn = t.nextToken();
1134 }
1135 } else {
1136 listBreakpoints();
1137 return;
1138 }
1139
1140 BreakpointSpec spec = parseBreakpointSpec(t, "stop at", "stop in");
1141 if (spec != null) {
1142 // Enforcement of "at" vs. "in". The distinction is really
1143 // unnecessary and we should consider not checking for this
1144 // (and making "at" and "in" optional).
1145 if (atIn.equals("at") && spec.isMethodBreakpoint()) {
1146 MessageOutput.println("Use stop at to set a breakpoint at a line number");
1147 printBreakpointCommandUsage("stop at", "stop in");
1148 return;
1149 }
1150 spec.suspendPolicy = suspendPolicy;
1151 resolveNow(spec);
1152 }
1153 }
1154
1155 void commandClear(StringTokenizer t) {
1156 if (!t.hasMoreTokens()) {
1157 listBreakpoints();
1158 return;
1159 }
1160
1161 BreakpointSpec spec = parseBreakpointSpec(t, "clear", "clear");
1162 if (spec != null) {
1163 if (Env.specList.delete(spec)) {
1164 MessageOutput.println("Removed:", spec.toString());
1165 } else {
1166 MessageOutput.println("Not found:", spec.toString());
1167 }
1168 }
1169 }
1170
1171 private List<WatchpointSpec> parseWatchpointSpec(StringTokenizer t) {
1172 List<WatchpointSpec> list = new ArrayList<WatchpointSpec>();
1173 boolean access = false;
1174 boolean modification = false;
1175 int suspendPolicy = EventRequest.SUSPEND_ALL;
1176
1177 String fieldName = t.nextToken();
1178 if (fieldName.equals("go")) {
1179 suspendPolicy = EventRequest.SUSPEND_NONE;
1180 fieldName = t.nextToken();
1181 } else if (fieldName.equals("thread")) {
1182 suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD;
1183 fieldName = t.nextToken();
1184 }
1185 if (fieldName.equals("access")) {
1186 access = true;
1187 fieldName = t.nextToken();
1188 } else if (fieldName.equals("all")) {
1189 access = true;
1190 modification = true;
1191 fieldName = t.nextToken();
1192 } else {
1193 modification = true;
1194 }
1195 int dot = fieldName.lastIndexOf('.');
1196 if (dot < 0) {
1197 MessageOutput.println("Class containing field must be specified.");
1198 return list;
1199 }
1200 String className = fieldName.substring(0, dot);
1201 fieldName = fieldName.substring(dot+1);
1202
1203 try {
1204 WatchpointSpec spec;
1205 if (access) {
1206 spec = Env.specList.createAccessWatchpoint(className,
1207 fieldName);
1208 spec.suspendPolicy = suspendPolicy;
1209 list.add(spec);
1210 }
1211 if (modification) {
1212 spec = Env.specList.createModificationWatchpoint(className,
1213 fieldName);
1214 spec.suspendPolicy = suspendPolicy;
1215 list.add(spec);
1216 }
1217 } catch (MalformedMemberNameException exc) {
1218 MessageOutput.println("is not a valid field name", fieldName);
1219 } catch (ClassNotFoundException exc) {
1220 MessageOutput.println("is not a valid class name", className);
1221 }
1222 return list;
1223 }
1224
1225 void commandWatch(StringTokenizer t) {
1226 if (!t.hasMoreTokens()) {
1227 MessageOutput.println("Field to watch not specified");
1228 return;
1229 }
1230
1231 for (WatchpointSpec spec : parseWatchpointSpec(t)) {
1232 resolveNow(spec);
1233 }
1234 }
1235
1236 void commandUnwatch(StringTokenizer t) {
1237 if (!t.hasMoreTokens()) {
1238 MessageOutput.println("Field to unwatch not specified");
1239 return;
1240 }
1241
1242 for (WatchpointSpec spec : parseWatchpointSpec(t)) {
1243 if (Env.specList.delete(spec)) {
1244 MessageOutput.println("Removed:", spec.toString());
1245 } else {
1246 MessageOutput.println("Not found:", spec.toString());
1247 }
1248 }
1249 }
1250
1251 void turnOnExitTrace(ThreadInfo threadInfo, int suspendPolicy) {
1252 EventRequestManager erm = Env.vm().eventRequestManager();
1253 MethodExitRequest exit = erm.createMethodExitRequest();
1254 if (threadInfo != null) {
1255 exit.addThreadFilter(threadInfo.getThread());
1256 }
1257 Env.addExcludes(exit);
1258 exit.setSuspendPolicy(suspendPolicy);
1259 exit.enable();
1260
1261 }
1262
1263 static String methodTraceCommand = null;
1264
1265 void commandTrace(StringTokenizer t) {
1266 String modif;
1267 int suspendPolicy = EventRequest.SUSPEND_ALL;
1268 ThreadInfo threadInfo = null;
1269 String goStr = " ";
1270
1271 /*
1272 * trace [go] methods [thread]
1273 * trace [go] method exit | exits [thread]
1274 */
1275 if (t.hasMoreTokens()) {
1276 modif = t.nextToken();
1277 if (modif.equals("go")) {
1278 suspendPolicy = EventRequest.SUSPEND_NONE;
1279 goStr = " go ";
1280 if (t.hasMoreTokens()) {
1281 modif = t.nextToken();
1282 }
1283 } else if (modif.equals("thread")) {
1284 // this is undocumented as it doesn't work right.
1285 suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD;
1286 if (t.hasMoreTokens()) {
1287 modif = t.nextToken();
1288 }
1289 }
1290
1291 if (modif.equals("method")) {
1292 String traceCmd = null;
1293
1294 if (t.hasMoreTokens()) {
1295 String modif1 = t.nextToken();
1296 if (modif1.equals("exits") || modif1.equals("exit")) {
1297 if (t.hasMoreTokens()) {
1298 threadInfo = doGetThread(t.nextToken());
1299 }
1300 if (modif1.equals("exit")) {
1301 StackFrame frame;
1302 try {
1303 frame = ThreadInfo.getCurrentThreadInfo().getCurrentFrame();
1304 } catch (IncompatibleThreadStateException ee) {
1305 MessageOutput.println("Current thread isnt suspended.");
1306 return;
1307 }
1308 Env.setAtExitMethod(frame.location().method());
1309 traceCmd = MessageOutput.format("trace" +
1310 goStr + "method exit " +
1311 "in effect for",
1312 Env.atExitMethod().toString());
1313 } else {
1314 traceCmd = MessageOutput.format("trace" +
1315 goStr + "method exits " +
1316 "in effect");
1317 }
1318 commandUntrace(new StringTokenizer("methods"));
1319 turnOnExitTrace(threadInfo, suspendPolicy);
1320 methodTraceCommand = traceCmd;
1321 return;
1322 }
1323 } else {
1324 MessageOutput.println("Can only trace");
1325 return;
1326 }
1327 }
1328 if (modif.equals("methods")) {
1329 // Turn on method entry trace
1330 MethodEntryRequest entry;
1331 EventRequestManager erm = Env.vm().eventRequestManager();
1332 if (t.hasMoreTokens()) {
1333 threadInfo = doGetThread(t.nextToken());
1334 }
1335 if (threadInfo != null) {
1336 /*
1337 * To keep things simple we want each 'trace' to cancel
1338 * previous traces. However in this case, we don't do that
1339 * to preserve backward compatibility with pre JDK 6.0.
1340 * IE, you can currently do
1341 * trace methods 0x21
1342 * trace methods 0x22
1343 * and you will get xxx traced just on those two threads
1344 * But this feature is kind of broken because if you then do
1345 * untrace 0x21
1346 * it turns off both traces instead of just the one.
1347 * Another bogosity is that if you do
1348 * trace methods
1349 * trace methods
1350 * and you will get two traces.
1351 */
1352
1353 entry = erm.createMethodEntryRequest();
1354 entry.addThreadFilter(threadInfo.getThread());
1355 } else {
1356 commandUntrace(new StringTokenizer("methods"));
1357 entry = erm.createMethodEntryRequest();
1358 }
1359 Env.addExcludes(entry);
1360 entry.setSuspendPolicy(suspendPolicy);
1361 entry.enable();
1362 turnOnExitTrace(threadInfo, suspendPolicy);
1363 methodTraceCommand = MessageOutput.format("trace" + goStr +
1364 "methods in effect");
1365
1366 return;
1367 }
1368
1369 MessageOutput.println("Can only trace");
1370 return;
1371 }
1372
1373 // trace all by itself.
1374 if (methodTraceCommand != null) {
1375 MessageOutput.printDirectln(methodTraceCommand);
1376 }
1377
1378 // More trace lines can be added here.
1379 }
1380
1381 void commandUntrace(StringTokenizer t) {
1382 // untrace
1383 // untrace methods
1384
1385 String modif = null;
1386 EventRequestManager erm = Env.vm().eventRequestManager();
1387 if (t.hasMoreTokens()) {
1388 modif = t.nextToken();
1389 }
1390 if (modif == null || modif.equals("methods")) {
1391 erm.deleteEventRequests(erm.methodEntryRequests());
1392 erm.deleteEventRequests(erm.methodExitRequests());
1393 Env.setAtExitMethod(null);
1394 methodTraceCommand = null;
1395 }
1396 }
1397
1398 void commandList(StringTokenizer t) {
1399 StackFrame frame = null;
1400 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
1401 if (threadInfo == null) {
1402 MessageOutput.println("No thread specified.");
1403 return;
1404 }
1405 try {
1406 frame = threadInfo.getCurrentFrame();
1407 } catch (IncompatibleThreadStateException e) {
1408 MessageOutput.println("Current thread isnt suspended.");
1409 return;
1410 }
1411
1412 if (frame == null) {
1413 MessageOutput.println("No frames on the current call stack");
1414 return;
1415 }
1416
1417 Location loc = frame.location();
1418 if (loc.method().isNative()) {
1419 MessageOutput.println("Current method is native");
1420 return;
1421 }
1422
1423 String sourceFileName = null;
1424 try {
1425 sourceFileName = loc.sourceName();
1426
1427 ReferenceType refType = loc.declaringType();
1428 int lineno = loc.lineNumber();
1429
1430 if (t.hasMoreTokens()) {
1431 String id = t.nextToken();
1432
1433 // See if token is a line number.
1434 try {
1435 NumberFormat nf = NumberFormat.getNumberInstance();
1436 nf.setParseIntegerOnly(true);
1437 Number n = nf.parse(id);
1438 lineno = n.intValue();
1439 } catch (java.text.ParseException jtpe) {
1440 // It isn't -- see if it's a method name.
1441 List<Method> meths = refType.methodsByName(id);
1442 if (meths == null || meths.size() == 0) {
1443 MessageOutput.println("is not a valid line number or method name for",
1444 new Object [] {id, refType.name()});
1445 return;
1446 } else if (meths.size() > 1) {
1447 MessageOutput.println("is an ambiguous method name in",
1448 new Object [] {id, refType.name()});
1449 return;
1450 }
1451 loc = meths.get(0).location();
1452 lineno = loc.lineNumber();
1453 }
1454 }
1455 int startLine = Math.max(lineno - 4, 1);
1456 int endLine = startLine + 9;
1457 if (lineno < 0) {
1458 MessageOutput.println("Line number information not available for");
1459 } else if (Env.sourceLine(loc, lineno) == null) {
1460 MessageOutput.println("is an invalid line number for",
1461 new Object [] {new Integer (lineno),
1462 refType.name()});
1463 } else {
1464 for (int i = startLine; i <= endLine; i++) {
1465 String sourceLine = Env.sourceLine(loc, i);
1466 if (sourceLine == null) {
1467 break;
1468 }
1469 if (i == lineno) {
1470 MessageOutput.println("source line number current line and line",
1471 new Object [] {new Integer (i),
1472 sourceLine});
1473 } else {
1474 MessageOutput.println("source line number and line",
1475 new Object [] {new Integer (i),
1476 sourceLine});
1477 }
1478 }
1479 }
1480 } catch (AbsentInformationException e) {
1481 MessageOutput.println("No source information available for:", loc.toString());
1482 } catch(FileNotFoundException exc) {
1483 MessageOutput.println("Source file not found:", sourceFileName);
1484 } catch(IOException exc) {
1485 MessageOutput.println("I/O exception occurred:", exc.toString());
1486 }
1487 }
1488
1489 void commandLines(StringTokenizer t) { // Undocumented command: useful for testing
1490 if (!t.hasMoreTokens()) {
1491 MessageOutput.println("Specify class and method");
1492 } else {
1493 String idClass = t.nextToken();
1494 String idMethod = t.hasMoreTokens() ? t.nextToken() : null;
1495 try {
1496 ReferenceType refType = Env.getReferenceTypeFromToken(idClass);
1497 if (refType != null) {
1498 List<Location> lines = null;
1499 if (idMethod == null) {
1500 lines = refType.allLineLocations();
1501 } else {
1502 for (Method method : refType.allMethods()) {
1503 if (method.name().equals(idMethod)) {
1504 lines = method.allLineLocations();
1505 }
1506 }
1507 if (lines == null) {
1508 MessageOutput.println("is not a valid method name", idMethod);
1509 }
1510 }
1511 for (Location line : lines) {
1512 MessageOutput.printDirectln(line.toString());// Special case: use printDirectln()
1513 }
1514 } else {
1515 MessageOutput.println("is not a valid id or class name", idClass);
1516 }
1517 } catch (AbsentInformationException e) {
1518 MessageOutput.println("Line number information not available for", idClass);
1519 }
1520 }
1521 }
1522
1523 void commandClasspath(StringTokenizer t) {
1524 if (Env.vm() instanceof PathSearchingVirtualMachine) {
1525 PathSearchingVirtualMachine vm = (PathSearchingVirtualMachine)Env.vm();
1526 MessageOutput.println("base directory:", vm.baseDirectory());
1527 MessageOutput.println("classpath:", vm.classPath().toString());
1528 MessageOutput.println("bootclasspath:", vm.bootClassPath().toString());
1529 } else {
1530 MessageOutput.println("The VM does not use paths");
1531 }
1532 }
1533
1534 /* Get or set the source file path list. */
1535 void commandUse(StringTokenizer t) {
1536 if (!t.hasMoreTokens()) {
1537 MessageOutput.printDirectln(Env.getSourcePath());// Special case: use printDirectln()
1538 } else {
1539 /*
1540 * Take the remainder of the command line, minus
1541 * leading or trailing whitespace. Embedded
1542 * whitespace is fine.
1543 */
1544 Env.setSourcePath(t.nextToken("").trim());
1545 }
1546 }
1547
1548 /* Print a stack variable */
1549 private void printVar(LocalVariable var, Value value) {
1550 MessageOutput.println("expr is value",
1551 new Object [] {var.name(),
1552 value == null ? "null" : value.toString()});
1553 }
1554
1555 /* Print all local variables in current stack frame. */
1556 void commandLocals() {
1557 StackFrame frame;
1558 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
1559 if (threadInfo == null) {
1560 MessageOutput.println("No default thread specified:");
1561 return;
1562 }
1563 try {
1564 frame = threadInfo.getCurrentFrame();
1565 if (frame == null) {
1566 throw new AbsentInformationException();
1567 }
1568 List<LocalVariable> vars = frame.visibleVariables();
1569
1570 if (vars.size() == 0) {
1571 MessageOutput.println("No local variables");
1572 return;
1573 }
1574 Map<LocalVariable, Value> values = frame.getValues(vars);
1575
1576 MessageOutput.println("Method arguments:");
1577 for (LocalVariable var : vars) {
1578 if (var.isArgument()) {
1579 Value val = values.get(var);
1580 printVar(var, val);
1581 }
1582 }
1583 MessageOutput.println("Local variables:");
1584 for (LocalVariable var : vars) {
1585 if (!var.isArgument()) {
1586 Value val = values.get(var);
1587 printVar(var, val);
1588 }
1589 }
1590 } catch (AbsentInformationException aie) {
1591 MessageOutput.println("Local variable information not available.");
1592 } catch (IncompatibleThreadStateException exc) {
1593 MessageOutput.println("Current thread isnt suspended.");
1594 }
1595 }
1596
1597 private void dump(ObjectReference obj, ReferenceType refType,
1598 ReferenceType refTypeBase) {
1599 for (Field field : refType.fields()) {
1600 StringBuffer o = new StringBuffer();
1601 o.append(" ");
1602 if (!refType.equals(refTypeBase)) {
1603 o.append(refType.name());
1604 o.append(".");
1605 }
1606 o.append(field.name());
1607 o.append(MessageOutput.format("colon space"));
1608 o.append(obj.getValue(field));
1609 MessageOutput.printDirectln(o.toString()); // Special case: use printDirectln()
1610 }
1611 if (refType instanceof ClassType) {
1612 ClassType sup = ((ClassType)refType).superclass();
1613 if (sup != null) {
1614 dump(obj, sup, refTypeBase);
1615 }
1616 } else if (refType instanceof InterfaceType) {
1617 for (InterfaceType sup : ((InterfaceType)refType).superinterfaces()) {
1618 dump(obj, sup, refTypeBase);
1619 }
1620 } else {
1621 /* else refType is an instanceof ArrayType */
1622 if (obj instanceof ArrayReference) {
1623 for (Iterator<Value> it = ((ArrayReference)obj).getValues().iterator();
1624 it.hasNext(); ) {
1625 MessageOutput.printDirect(it.next().toString());// Special case: use printDirect()
1626 if (it.hasNext()) {
1627 MessageOutput.printDirect(", ");// Special case: use printDirect()
1628 }
1629 }
1630 MessageOutput.println();
1631 }
1632 }
1633 }
1634
1635 /* Print a specified reference.
1636 */
1637 void doPrint(StringTokenizer t, boolean dumpObject) {
1638 if (!t.hasMoreTokens()) {
1639 MessageOutput.println("No objects specified.");
1640 return;
1641 }
1642
1643 while (t.hasMoreTokens()) {
1644 String expr = t.nextToken("");
1645 Value val = evaluate(expr);
1646 if (val == null) {
1647 MessageOutput.println("expr is null", expr.toString());
1648 } else if (dumpObject && (val instanceof ObjectReference) &&
1649 !(val instanceof StringReference)) {
1650 ObjectReference obj = (ObjectReference)val;
1651 ReferenceType refType = obj.referenceType();
1652 MessageOutput.println("expr is value",
1653 new Object [] {expr.toString(),
1654 MessageOutput.format("grouping begin character")});
1655 dump(obj, refType, refType);
1656 MessageOutput.println("grouping end character");
1657 } else {
1658 String strVal = getStringValue();
1659 if (strVal != null) {
1660 MessageOutput.println("expr is value", new Object [] {expr.toString(),
1661 strVal});
1662 }
1663 }
1664 }
1665 }
1666
1667 void commandPrint(final StringTokenizer t, final boolean dumpObject) {
1668 new AsyncExecution() {
1669 @Override
1670 void action() {
1671 doPrint(t, dumpObject);
1672 }
1673 };
1674 }
1675
1676 void commandSet(final StringTokenizer t) {
1677 String all = t.nextToken("");
1678
1679 /*
1680 * Bare bones error checking.
1681 */
1682 if (all.indexOf('=') == -1) {
1683 MessageOutput.println("Invalid assignment syntax");
1684 MessageOutput.printPrompt();
1685 return;
1686 }
1687
1688 /*
1689 * The set command is really just syntactic sugar. Pass it on to the
1690 * print command.
1691 */
1692 commandPrint(new StringTokenizer(all), false);
1693 }
1694
1695 void doLock(StringTokenizer t) {
1696 if (!t.hasMoreTokens()) {
1697 MessageOutput.println("No object specified.");
1698 return;
1699 }
1700
1701 String expr = t.nextToken("");
1702 Value val = evaluate(expr);
1703
1704 try {
1705 if ((val != null) && (val instanceof ObjectReference)) {
1706 ObjectReference object = (ObjectReference)val;
1707 String strVal = getStringValue();
1708 if (strVal != null) {
1709 MessageOutput.println("Monitor information for expr",
1710 new Object [] {expr.trim(),
1711 strVal});
1712 }
1713 ThreadReference owner = object.owningThread();
1714 if (owner == null) {
1715 MessageOutput.println("Not owned");
1716 } else {
1717 MessageOutput.println("Owned by:",
1718 new Object [] {owner.name(),
1719 new Integer (object.entryCount())});
1720 }
1721 List<ThreadReference> waiters = object.waitingThreads();
1722 if (waiters.size() == 0) {
1723 MessageOutput.println("No waiters");
1724 } else {
1725 for (ThreadReference waiter : waiters) {
1726 MessageOutput.println("Waiting thread:", waiter.name());
1727 }
1728 }
1729 } else {
1730 MessageOutput.println("Expression must evaluate to an object");
1731 }
1732 } catch (IncompatibleThreadStateException e) {
1733 MessageOutput.println("Threads must be suspended");
1734 }
1735 }
1736
1737 void commandLock(final StringTokenizer t) {
1738 new AsyncExecution() {
1739 @Override
1740 void action() {
1741 doLock(t);
1742 }
1743 };
1744 }
1745
1746 private void printThreadLockInfo(ThreadInfo threadInfo) {
1747 ThreadReference thread = threadInfo.getThread();
1748 try {
1749 MessageOutput.println("Monitor information for thread", thread.name());
1750 List<ObjectReference> owned = thread.ownedMonitors();
1751 if (owned.size() == 0) {
1752 MessageOutput.println("No monitors owned");
1753 } else {
1754 for (ObjectReference monitor : owned) {
1755 MessageOutput.println("Owned monitor:", monitor.toString());
1756 }
1757 }
1758 ObjectReference waiting = thread.currentContendedMonitor();
1759 if (waiting == null) {
1760 MessageOutput.println("Not waiting for a monitor");
1761 } else {
1762 MessageOutput.println("Waiting for monitor:", waiting.toString());
1763 }
1764 } catch (IncompatibleThreadStateException e) {
1765 MessageOutput.println("Threads must be suspended");
1766 }
1767 }
1768
1769 void commandThreadlocks(final StringTokenizer t) {
1770 if (!t.hasMoreTokens()) {
1771 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
1772 if (threadInfo == null) {
1773 MessageOutput.println("Current thread not set.");
1774 } else {
1775 printThreadLockInfo(threadInfo);
1776 }
1777 return;
1778 }
1779 String token = t.nextToken();
1780 if (token.toLowerCase().equals("all")) {
1781 for (ThreadInfo threadInfo : ThreadInfo.threads()) {
1782 printThreadLockInfo(threadInfo);
1783 }
1784 } else {
1785 ThreadInfo threadInfo = doGetThread(token);
1786 if (threadInfo != null) {
1787 ThreadInfo.setCurrentThreadInfo(threadInfo);
1788 printThreadLockInfo(threadInfo);
1789 }
1790 }
1791 }
1792
1793 void doDisableGC(StringTokenizer t) {
1794 if (!t.hasMoreTokens()) {
1795 MessageOutput.println("No object specified.");
1796 return;
1797 }
1798
1799 String expr = t.nextToken("");
1800 Value val = evaluate(expr);
1801 if ((val != null) && (val instanceof ObjectReference)) {
1802 ObjectReference object = (ObjectReference)val;
1803 object.disableCollection();
1804 String strVal = getStringValue();
1805 if (strVal != null) {
1806 MessageOutput.println("GC Disabled for", strVal);
1807 }
1808 } else {
1809 MessageOutput.println("Expression must evaluate to an object");
1810 }
1811 }
1812
1813 void commandDisableGC(final StringTokenizer t) {
1814 new AsyncExecution() {
1815 @Override
1816 void action() {
1817 doDisableGC(t);
1818 }
1819 };
1820 }
1821
1822 void doEnableGC(StringTokenizer t) {
1823 if (!t.hasMoreTokens()) {
1824 MessageOutput.println("No object specified.");
1825 return;
1826 }
1827
1828 String expr = t.nextToken("");
1829 Value val = evaluate(expr);
1830 if ((val != null) && (val instanceof ObjectReference)) {
1831 ObjectReference object = (ObjectReference)val;
1832 object.enableCollection();
1833 String strVal = getStringValue();
1834 if (strVal != null) {
1835 MessageOutput.println("GC Enabled for", strVal);
1836 }
1837 } else {
1838 MessageOutput.println("Expression must evaluate to an object");
1839 }
1840 }
1841
1842 void commandEnableGC(final StringTokenizer t) {
1843 new AsyncExecution() {
1844 @Override
1845 void action() {
1846 doEnableGC(t);
1847 }
1848 };
1849 }
1850
1851 void doSave(StringTokenizer t) {// Undocumented command: useful for testing.
1852 if (!t.hasMoreTokens()) {
1853 MessageOutput.println("No save index specified.");
1854 return;
1855 }
1856
1857 String key = t.nextToken();
1858
1859 if (!t.hasMoreTokens()) {
1860 MessageOutput.println("No expression specified.");
1861 return;
1862 }
1863 String expr = t.nextToken("");
1864 Value val = evaluate(expr);
1865 if (val != null) {
1866 Env.setSavedValue(key, val);
1867 String strVal = getStringValue();
1868 if (strVal != null) {
1869 MessageOutput.println("saved", strVal);
1870 }
1871 } else {
1872 MessageOutput.println("Expression cannot be void");
1873 }
1874 }
1875
1876 void commandSave(final StringTokenizer t) { // Undocumented command: useful for testing.
1877 if (!t.hasMoreTokens()) {
1878 Set<String> keys = Env.getSaveKeys();
1879 if (keys.isEmpty()) {
1880 MessageOutput.println("No saved values");
1881 return;
1882 }
1883 for (String key : keys) {
1884 Value value = Env.getSavedValue(key);
1885 if ((value instanceof ObjectReference) &&
1886 ((ObjectReference)value).isCollected()) {
1887 MessageOutput.println("expr is value <collected>",
1888 new Object [] {key, value.toString()});
1889 } else {
1890 if (value == null){
1891 MessageOutput.println("expr is null", key);
1892 } else {
1893 MessageOutput.println("expr is value",
1894 new Object [] {key, value.toString()});
1895 }
1896 }
1897 }
1898 } else {
1899 new AsyncExecution() {
1900 @Override
1901 void action() {
1902 doSave(t);
1903 }
1904 };
1905 }
1906
1907 }
1908
1909 void commandBytecodes(final StringTokenizer t) { // Undocumented command: useful for testing.
1910 if (!t.hasMoreTokens()) {
1911 MessageOutput.println("No class specified.");
1912 return;
1913 }
1914 String className = t.nextToken();
1915
1916 if (!t.hasMoreTokens()) {
1917 MessageOutput.println("No method specified.");
1918 return;
1919 }
1920 // Overloading is not handled here.
1921 String methodName = t.nextToken();
1922
1923 List<ReferenceType> classes = Env.vm().classesByName(className);
1924 // TO DO: handle multiple classes found
1925 if (classes.size() == 0) {
1926 if (className.indexOf('.') < 0) {
1927 MessageOutput.println("not found (try the full name)", className);
1928 } else {
1929 MessageOutput.println("not found", className);
1930 }
1931 return;
1932 }
1933
1934 ReferenceType rt = classes.get(0);
1935 if (!(rt instanceof ClassType)) {
1936 MessageOutput.println("not a class", className);
1937 return;
1938 }
1939
1940 byte[] bytecodes = null;
1941 for (Method method : rt.methodsByName(methodName)) {
1942 if (!method.isAbstract()) {
1943 bytecodes = method.bytecodes();
1944 break;
1945 }
1946 }
1947
1948 StringBuffer line = new StringBuffer(80);
1949 line.append("0000: ");
1950 for (int i = 0; i < bytecodes.length; i++) {
1951 if ((i > 0) && (i % 16 == 0)) {
1952 MessageOutput.printDirectln(line.toString());// Special case: use printDirectln()
1953 line.setLength(0);
1954 line.append(String.valueOf(i));
1955 line.append(": ");
1956 int len = line.length();
1957 for (int j = 0; j < 6 - len; j++) {
1958 line.insert(0, '0');
1959 }
1960 }
1961 int val = 0xff & bytecodes[i];
1962 String str = Integer.toHexString(val);
1963 if (str.length() == 1) {
1964 line.append('0');
1965 }
1966 line.append(str);
1967 line.append(' ');
1968 }
1969 if (line.length() > 6) {
1970 MessageOutput.printDirectln(line.toString());// Special case: use printDirectln()
1971 }
1972 }
1973
1974 void commandExclude(StringTokenizer t) {
1975 if (!t.hasMoreTokens()) {
1976 MessageOutput.printDirectln(Env.excludesString());// Special case: use printDirectln()
1977 } else {
1978 String rest = t.nextToken("");
1979 if (rest.equals("none")) {
1980 rest = "";
1981 }
1982 Env.setExcludes(rest);
1983 }
1984 }
1985
1986 void commandRedefine(StringTokenizer t) {
1987 if (!t.hasMoreTokens()) {
1988 MessageOutput.println("Specify classes to redefine");
1989 } else {
1990 String className = t.nextToken();
1991 List<ReferenceType> classes = Env.vm().classesByName(className);
1992 if (classes.size() == 0) {
1993 MessageOutput.println("No class named", className);
1994 return;
1995 }
1996 if (classes.size() > 1) {
1997 MessageOutput.println("More than one class named", className);
1998 return;
1999 }
2000 Env.setSourcePath(Env.getSourcePath());
2001 ReferenceType refType = classes.get(0);
2002 if (!t.hasMoreTokens()) {
2003 MessageOutput.println("Specify file name for class", className);
2004 return;
2005 }
2006 String fileName = t.nextToken();
2007 File phyl = new File(fileName);
2008 byte[] bytes = new byte[(int)phyl.length()];
2009 try {
2010 InputStream in = new FileInputStream(phyl);
2011 in.read(bytes);
2012 in.close();
2013 } catch (Exception exc) {
2014 MessageOutput.println("Error reading file",
2015 new Object [] {fileName, exc.toString()});
2016 return;
2017 }
2018 Map<ReferenceType, byte[]> map
2019 = new HashMap<ReferenceType, byte[]>();
2020 map.put(refType, bytes);
2021 try {
2022 Env.vm().redefineClasses(map);
2023 } catch (Throwable exc) {
2024 MessageOutput.println("Error redefining class to file",
2025 new Object [] {className,
2026 fileName,
2027 exc});
2028 }
2029 }
2030 }
2031
2032 void commandPopFrames(StringTokenizer t, boolean reenter) {
2033 ThreadInfo threadInfo;
2034
2035 if (t.hasMoreTokens()) {
2036 String token = t.nextToken();
2037 threadInfo = doGetThread(token);
2038 if (threadInfo == null) {
2039 return;
2040 }
2041 } else {
2042 threadInfo = ThreadInfo.getCurrentThreadInfo();
2043 if (threadInfo == null) {
2044 MessageOutput.println("No thread specified.");
2045 return;
2046 }
2047 }
2048
2049 try {
2050 StackFrame frame = threadInfo.getCurrentFrame();
2051 threadInfo.getThread().popFrames(frame);
2052 threadInfo = ThreadInfo.getCurrentThreadInfo();
2053 ThreadInfo.setCurrentThreadInfo(threadInfo);
2054 if (reenter) {
2055 commandStepi();
2056 }
2057 } catch (Throwable exc) {
2058 MessageOutput.println("Error popping frame", exc.toString());
2059 }
2060 }
2061
2062 void commandExtension(StringTokenizer t) {
2063 if (!t.hasMoreTokens()) {
2064 MessageOutput.println("No class specified.");
2065 return;
2066 }
2067
2068 String idClass = t.nextToken();
2069 ReferenceType cls = Env.getReferenceTypeFromToken(idClass);
2070 String extension = null;
2071 if (cls != null) {
2072 try {
2073 extension = cls.sourceDebugExtension();
2074 MessageOutput.println("sourcedebugextension", extension);
2075 } catch (AbsentInformationException e) {
2076 MessageOutput.println("No sourcedebugextension specified");
2077 }
2078 } else {
2079 MessageOutput.println("is not a valid id or class name", idClass);
2080 }
2081 }
2082
2083 void commandVersion(String debuggerName,
2084 VirtualMachineManager vmm) {
2085 MessageOutput.println("minus version",
2086 new Object [] { debuggerName,
2087 new Integer(vmm.majorInterfaceVersion()),
2088 new Integer(vmm.minorInterfaceVersion()),
2089 System.getProperty("java.version")});
2090 if (Env.connection() != null) {
2091 try {
2092 MessageOutput.printDirectln(Env.vm().description());// Special case: use printDirectln()
2093 } catch (VMNotConnectedException e) {
2094 MessageOutput.println("No VM connected");
2095 }
2096 }
2097 }
2098}