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/TTY.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/example/debug/tty/TTY.java+1063−0
@@ -0,0 +1,1063 @@
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.event.*;
30import com.sun.jdi.request.*;
31import com.sun.jdi.connect.*;
32
33import java.util.*;
34import java.io.*;
35
36public class TTY implements EventNotifier {
37 EventHandler handler = null;
38
39 /**
40 * List of Strings to execute at each stop.
41 */
42 private List<String> monitorCommands = new ArrayList<String>();
43 private int monitorCount = 0;
44
45 /**
46 * The name of this tool.
47 */
48 private static final String progname = "jdb";
49
50 @Override
51 public void vmStartEvent(VMStartEvent se) {
52 Thread.yield(); // fetch output
53 MessageOutput.lnprint("VM Started:");
54 }
55
56 @Override
57 public void vmDeathEvent(VMDeathEvent e) {
58 }
59
60 @Override
61 public void vmDisconnectEvent(VMDisconnectEvent e) {
62 }
63
64 @Override
65 public void threadStartEvent(ThreadStartEvent e) {
66 }
67
68 @Override
69 public void threadDeathEvent(ThreadDeathEvent e) {
70 }
71
72 @Override
73 public void classPrepareEvent(ClassPrepareEvent e) {
74 }
75
76 @Override
77 public void classUnloadEvent(ClassUnloadEvent e) {
78 }
79
80 @Override
81 public void breakpointEvent(BreakpointEvent be) {
82 Thread.yield(); // fetch output
83 MessageOutput.lnprint("Breakpoint hit:");
84 }
85
86 @Override
87 public void fieldWatchEvent(WatchpointEvent fwe) {
88 Field field = fwe.field();
89 ObjectReference obj = fwe.object();
90 Thread.yield(); // fetch output
91
92 if (fwe instanceof ModificationWatchpointEvent) {
93 MessageOutput.lnprint("Field access encountered before after",
94 new Object [] {field,
95 fwe.valueCurrent(),
96 ((ModificationWatchpointEvent)fwe).valueToBe()});
97 } else {
98 MessageOutput.lnprint("Field access encountered", field.toString());
99 }
100 }
101
102 @Override
103 public void stepEvent(StepEvent se) {
104 Thread.yield(); // fetch output
105 MessageOutput.lnprint("Step completed:");
106 }
107
108 @Override
109 public void exceptionEvent(ExceptionEvent ee) {
110 Thread.yield(); // fetch output
111 Location catchLocation = ee.catchLocation();
112 if (catchLocation == null) {
113 MessageOutput.lnprint("Exception occurred uncaught",
114 ee.exception().referenceType().name());
115 } else {
116 MessageOutput.lnprint("Exception occurred caught",
117 new Object [] {ee.exception().referenceType().name(),
118 Commands.locationString(catchLocation)});
119 }
120 }
121
122 @Override
123 public void methodEntryEvent(MethodEntryEvent me) {
124 Thread.yield(); // fetch output
125 /*
126 * These can be very numerous, so be as efficient as possible.
127 * If we are stopping here, then we will see the normal location
128 * info printed.
129 */
130 if (me.request().suspendPolicy() != EventRequest.SUSPEND_NONE) {
131 // We are stopping; the name will be shown by the normal mechanism
132 MessageOutput.lnprint("Method entered:");
133 } else {
134 // We aren't stopping, show the name
135 MessageOutput.print("Method entered:");
136 printLocationOfEvent(me);
137 }
138 }
139
140 @Override
141 public boolean methodExitEvent(MethodExitEvent me) {
142 Thread.yield(); // fetch output
143 /*
144 * These can be very numerous, so be as efficient as possible.
145 */
146 Method mmm = Env.atExitMethod();
147 Method meMethod = me.method();
148
149 if (mmm == null || mmm.equals(meMethod)) {
150 // Either we are not tracing a specific method, or we are
151 // and we are exitting that method.
152
153 if (me.request().suspendPolicy() != EventRequest.SUSPEND_NONE) {
154 // We will be stopping here, so do a newline
155 MessageOutput.println();
156 }
157 if (Env.vm().canGetMethodReturnValues()) {
158 MessageOutput.print("Method exitedValue:", me.returnValue() + "");
159 } else {
160 MessageOutput.print("Method exited:");
161 }
162
163 if (me.request().suspendPolicy() == EventRequest.SUSPEND_NONE) {
164 // We won't be stopping here, so show the method name
165 printLocationOfEvent(me);
166
167 }
168
169 // In case we want to have a one shot trace exit some day, this
170 // code disables the request so we don't hit it again.
171 if (false) {
172 // This is a one shot deal; we don't want to stop
173 // here the next time.
174 Env.setAtExitMethod(null);
175 EventRequestManager erm = Env.vm().eventRequestManager();
176 for (EventRequest eReq : erm.methodExitRequests()) {
177 if (eReq.equals(me.request())) {
178 eReq.disable();
179 }
180 }
181 }
182 return true;
183 }
184
185 // We are tracing a specific method, and this isn't it. Keep going.
186 return false;
187 }
188
189 @Override
190 public void vmInterrupted() {
191 Thread.yield(); // fetch output
192 printCurrentLocation();
193 for (String cmd : monitorCommands) {
194 StringTokenizer t = new StringTokenizer(cmd);
195 t.nextToken(); // get rid of monitor number
196 executeCommand(t);
197 }
198 MessageOutput.printPrompt();
199 }
200
201 @Override
202 public void receivedEvent(Event event) {
203 }
204
205 private void printBaseLocation(String threadName, Location loc) {
206 MessageOutput.println("location",
207 new Object [] {threadName,
208 Commands.locationString(loc)});
209 }
210
211 private void printCurrentLocation() {
212 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
213 StackFrame frame;
214 try {
215 frame = threadInfo.getCurrentFrame();
216 } catch (IncompatibleThreadStateException exc) {
217 MessageOutput.println("<location unavailable>");
218 return;
219 }
220 if (frame == null) {
221 MessageOutput.println("No frames on the current call stack");
222 } else {
223 Location loc = frame.location();
224 printBaseLocation(threadInfo.getThread().name(), loc);
225 // Output the current source line, if possible
226 if (loc.lineNumber() != -1) {
227 String line;
228 try {
229 line = Env.sourceLine(loc, loc.lineNumber());
230 } catch (java.io.IOException e) {
231 line = null;
232 }
233 if (line != null) {
234 MessageOutput.println("source line number and line",
235 new Object [] {new Integer(loc.lineNumber()),
236 line});
237 }
238 }
239 }
240 MessageOutput.println();
241 }
242
243 private void printLocationOfEvent(LocatableEvent theEvent) {
244 printBaseLocation(theEvent.thread().name(), theEvent.location());
245 }
246
247 void help() {
248 MessageOutput.println("zz help text");
249 }
250
251 private static final String[][] commandList = {
252 /*
253 * NOTE: this list must be kept sorted in ascending ASCII
254 * order by element [0]. Ref: isCommand() below.
255 *
256 *Command OK when OK when
257 * name disconnected? readonly?
258 *------------------------------------
259 */
260 {"!!", "n", "y"},
261 {"?", "y", "y"},
262 {"bytecodes", "n", "y"},
263 {"catch", "y", "n"},
264 {"class", "n", "y"},
265 {"classes", "n", "y"},
266 {"classpath", "n", "y"},
267 {"clear", "y", "n"},
268 {"connectors", "y", "y"},
269 {"cont", "n", "n"},
270 {"disablegc", "n", "n"},
271 {"down", "n", "y"},
272 {"dump", "n", "y"},
273 {"enablegc", "n", "n"},
274 {"eval", "n", "y"},
275 {"exclude", "y", "n"},
276 {"exit", "y", "y"},
277 {"extension", "n", "y"},
278 {"fields", "n", "y"},
279 {"gc", "n", "n"},
280 {"help", "y", "y"},
281 {"ignore", "y", "n"},
282 {"interrupt", "n", "n"},
283 {"kill", "n", "n"},
284 {"lines", "n", "y"},
285 {"list", "n", "y"},
286 {"load", "n", "y"},
287 {"locals", "n", "y"},
288 {"lock", "n", "n"},
289 {"memory", "n", "y"},
290 {"methods", "n", "y"},
291 {"monitor", "n", "n"},
292 {"next", "n", "n"},
293 {"pop", "n", "n"},
294 {"print", "n", "y"},
295 {"quit", "y", "y"},
296 {"read", "y", "y"},
297 {"redefine", "n", "n"},
298 {"reenter", "n", "n"},
299 {"resume", "n", "n"},
300 {"run", "y", "n"},
301 {"save", "n", "n"},
302 {"set", "n", "n"},
303 {"sourcepath", "y", "y"},
304 {"step", "n", "n"},
305 {"stepi", "n", "n"},
306 {"stop", "y", "n"},
307 {"suspend", "n", "n"},
308 {"thread", "n", "y"},
309 {"threadgroup", "n", "y"},
310 {"threadgroups", "n", "y"},
311 {"threadlocks", "n", "y"},
312 {"threads", "n", "y"},
313 {"trace", "n", "n"},
314 {"unmonitor", "n", "n"},
315 {"untrace", "n", "n"},
316 {"unwatch", "y", "n"},
317 {"up", "n", "y"},
318 {"use", "y", "y"},
319 {"version", "y", "y"},
320 {"watch", "y", "n"},
321 {"where", "n", "y"},
322 {"wherei", "n", "y"},
323 };
324
325 /*
326 * Look up the command string in commandList.
327 * If found, return the index.
328 * If not found, return index < 0
329 */
330 private int isCommand(String key) {
331 //Reference: binarySearch() in java/util/Arrays.java
332 // Adapted for use with String[][0].
333 int low = 0;
334 int high = commandList.length - 1;
335 while (low <= high) {
336 int mid = (low + high) >>> 1;
337 String midVal = commandList[mid][0];
338 int compare = midVal.compareTo(key);
339 if (compare < 0) {
340 low = mid + 1;
341 } else if (compare > 0) {
342 high = mid - 1;
343 }
344 else {
345 return mid; // key found
346 }
347 }
348 return -(low + 1); // key not found.
349 };
350
351 /*
352 * Return true if the command is OK when disconnected.
353 */
354 private boolean isDisconnectCmd(int ii) {
355 if (ii < 0 || ii >= commandList.length) {
356 return false;
357 }
358 return (commandList[ii][1].equals("y"));
359 }
360
361 /*
362 * Return true if the command is OK when readonly.
363 */
364 private boolean isReadOnlyCmd(int ii) {
365 if (ii < 0 || ii >= commandList.length) {
366 return false;
367 }
368 return (commandList[ii][2].equals("y"));
369 };
370
371
372 void executeCommand(StringTokenizer t) {
373 String cmd = t.nextToken().toLowerCase();
374 // Normally, prompt for the next command after this one is done
375 boolean showPrompt = true;
376
377
378 /*
379 * Anything starting with # is discarded as a no-op or 'comment'.
380 */
381 if (!cmd.startsWith("#")) {
382 /*
383 * Next check for an integer repetition prefix. If found,
384 * recursively execute cmd that number of times.
385 */
386 if (Character.isDigit(cmd.charAt(0)) && t.hasMoreTokens()) {
387 try {
388 int repeat = Integer.parseInt(cmd);
389 String subcom = t.nextToken("");
390 while (repeat-- > 0) {
391 executeCommand(new StringTokenizer(subcom));
392 showPrompt = false; // Bypass the printPrompt() below.
393 }
394 } catch (NumberFormatException exc) {
395 MessageOutput.println("Unrecognized command. Try help...", cmd);
396 }
397 } else {
398 int commandNumber = isCommand(cmd);
399 /*
400 * Check for an unknown command
401 */
402 if (commandNumber < 0) {
403 MessageOutput.println("Unrecognized command. Try help...", cmd);
404 } else if (!Env.connection().isOpen() && !isDisconnectCmd(commandNumber)) {
405 MessageOutput.println("Command not valid until the VM is started with the run command",
406 cmd);
407 } else if (Env.connection().isOpen() && !Env.vm().canBeModified() &&
408 !isReadOnlyCmd(commandNumber)) {
409 MessageOutput.println("Command is not supported on a read-only VM connection",
410 cmd);
411 } else {
412
413 Commands evaluator = new Commands();
414 try {
415 if (cmd.equals("print")) {
416 evaluator.commandPrint(t, false);
417 showPrompt = false; // asynchronous command
418 } else if (cmd.equals("eval")) {
419 evaluator.commandPrint(t, false);
420 showPrompt = false; // asynchronous command
421 } else if (cmd.equals("set")) {
422 evaluator.commandSet(t);
423 showPrompt = false; // asynchronous command
424 } else if (cmd.equals("dump")) {
425 evaluator.commandPrint(t, true);
426 showPrompt = false; // asynchronous command
427 } else if (cmd.equals("locals")) {
428 evaluator.commandLocals();
429 } else if (cmd.equals("classes")) {
430 evaluator.commandClasses();
431 } else if (cmd.equals("class")) {
432 evaluator.commandClass(t);
433 } else if (cmd.equals("connectors")) {
434 evaluator.commandConnectors(Bootstrap.virtualMachineManager());
435 } else if (cmd.equals("methods")) {
436 evaluator.commandMethods(t);
437 } else if (cmd.equals("fields")) {
438 evaluator.commandFields(t);
439 } else if (cmd.equals("threads")) {
440 evaluator.commandThreads(t);
441 } else if (cmd.equals("thread")) {
442 evaluator.commandThread(t);
443 } else if (cmd.equals("suspend")) {
444 evaluator.commandSuspend(t);
445 } else if (cmd.equals("resume")) {
446 evaluator.commandResume(t);
447 } else if (cmd.equals("cont")) {
448 evaluator.commandCont();
449 } else if (cmd.equals("threadgroups")) {
450 evaluator.commandThreadGroups();
451 } else if (cmd.equals("threadgroup")) {
452 evaluator.commandThreadGroup(t);
453 } else if (cmd.equals("catch")) {
454 evaluator.commandCatchException(t);
455 } else if (cmd.equals("ignore")) {
456 evaluator.commandIgnoreException(t);
457 } else if (cmd.equals("step")) {
458 evaluator.commandStep(t);
459 } else if (cmd.equals("stepi")) {
460 evaluator.commandStepi();
461 } else if (cmd.equals("next")) {
462 evaluator.commandNext();
463 } else if (cmd.equals("kill")) {
464 evaluator.commandKill(t);
465 } else if (cmd.equals("interrupt")) {
466 evaluator.commandInterrupt(t);
467 } else if (cmd.equals("trace")) {
468 evaluator.commandTrace(t);
469 } else if (cmd.equals("untrace")) {
470 evaluator.commandUntrace(t);
471 } else if (cmd.equals("where")) {
472 evaluator.commandWhere(t, false);
473 } else if (cmd.equals("wherei")) {
474 evaluator.commandWhere(t, true);
475 } else if (cmd.equals("up")) {
476 evaluator.commandUp(t);
477 } else if (cmd.equals("down")) {
478 evaluator.commandDown(t);
479 } else if (cmd.equals("load")) {
480 evaluator.commandLoad(t);
481 } else if (cmd.equals("run")) {
482 evaluator.commandRun(t);
483 /*
484 * Fire up an event handler, if the connection was just
485 * opened. Since this was done from the run command
486 * we don't stop the VM on its VM start event (so
487 * arg 2 is false).
488 */
489 if ((handler == null) && Env.connection().isOpen()) {
490 handler = new EventHandler(this, false);
491 }
492 } else if (cmd.equals("memory")) {
493 evaluator.commandMemory();
494 } else if (cmd.equals("gc")) {
495 evaluator.commandGC();
496 } else if (cmd.equals("stop")) {
497 evaluator.commandStop(t);
498 } else if (cmd.equals("clear")) {
499 evaluator.commandClear(t);
500 } else if (cmd.equals("watch")) {
501 evaluator.commandWatch(t);
502 } else if (cmd.equals("unwatch")) {
503 evaluator.commandUnwatch(t);
504 } else if (cmd.equals("list")) {
505 evaluator.commandList(t);
506 } else if (cmd.equals("lines")) { // Undocumented command: useful for testing.
507 evaluator.commandLines(t);
508 } else if (cmd.equals("classpath")) {
509 evaluator.commandClasspath(t);
510 } else if (cmd.equals("use") || cmd.equals("sourcepath")) {
511 evaluator.commandUse(t);
512 } else if (cmd.equals("monitor")) {
513 monitorCommand(t);
514 } else if (cmd.equals("unmonitor")) {
515 unmonitorCommand(t);
516 } else if (cmd.equals("lock")) {
517 evaluator.commandLock(t);
518 showPrompt = false; // asynchronous command
519 } else if (cmd.equals("threadlocks")) {
520 evaluator.commandThreadlocks(t);
521 } else if (cmd.equals("disablegc")) {
522 evaluator.commandDisableGC(t);
523 showPrompt = false; // asynchronous command
524 } else if (cmd.equals("enablegc")) {
525 evaluator.commandEnableGC(t);
526 showPrompt = false; // asynchronous command
527 } else if (cmd.equals("save")) { // Undocumented command: useful for testing.
528 evaluator.commandSave(t);
529 showPrompt = false; // asynchronous command
530 } else if (cmd.equals("bytecodes")) { // Undocumented command: useful for testing.
531 evaluator.commandBytecodes(t);
532 } else if (cmd.equals("redefine")) {
533 evaluator.commandRedefine(t);
534 } else if (cmd.equals("pop")) {
535 evaluator.commandPopFrames(t, false);
536 } else if (cmd.equals("reenter")) {
537 evaluator.commandPopFrames(t, true);
538 } else if (cmd.equals("extension")) {
539 evaluator.commandExtension(t);
540 } else if (cmd.equals("exclude")) {
541 evaluator.commandExclude(t);
542 } else if (cmd.equals("read")) {
543 readCommand(t);
544 } else if (cmd.equals("help") || cmd.equals("?")) {
545 help();
546 } else if (cmd.equals("version")) {
547 evaluator.commandVersion(progname,
548 Bootstrap.virtualMachineManager());
549 } else if (cmd.equals("quit") || cmd.equals("exit")) {
550 if (handler != null) {
551 handler.shutdown();
552 }
553 Env.shutdown();
554 } else {
555 MessageOutput.println("Unrecognized command. Try help...", cmd);
556 }
557 } catch (VMCannotBeModifiedException rovm) {
558 MessageOutput.println("Command is not supported on a read-only VM connection", cmd);
559 } catch (UnsupportedOperationException uoe) {
560 MessageOutput.println("Command is not supported on the target VM", cmd);
561 } catch (VMNotConnectedException vmnse) {
562 MessageOutput.println("Command not valid until the VM is started with the run command",
563 cmd);
564 } catch (Exception e) {
565 MessageOutput.printException("Internal exception:", e);
566 }
567 }
568 }
569 }
570 if (showPrompt) {
571 MessageOutput.printPrompt();
572 }
573 }
574
575 /*
576 * Maintain a list of commands to execute each time the VM is suspended.
577 */
578 void monitorCommand(StringTokenizer t) {
579 if (t.hasMoreTokens()) {
580 ++monitorCount;
581 monitorCommands.add(monitorCount + ": " + t.nextToken(""));
582 } else {
583 for (String cmd : monitorCommands) {
584 MessageOutput.printDirectln(cmd);// Special case: use printDirectln()
585 }
586 }
587 }
588
589 void unmonitorCommand(StringTokenizer t) {
590 if (t.hasMoreTokens()) {
591 String monTok = t.nextToken();
592 int monNum;
593 try {
594 monNum = Integer.parseInt(monTok);
595 } catch (NumberFormatException exc) {
596 MessageOutput.println("Not a monitor number:", monTok);
597 return;
598 }
599 String monStr = monTok + ":";
600 for (String cmd : monitorCommands) {
601 StringTokenizer ct = new StringTokenizer(cmd);
602 if (ct.nextToken().equals(monStr)) {
603 monitorCommands.remove(cmd);
604 MessageOutput.println("Unmonitoring", cmd);
605 return;
606 }
607 }
608 MessageOutput.println("No monitor numbered:", monTok);
609 } else {
610 MessageOutput.println("Usage: unmonitor <monitor#>");
611 }
612 }
613
614
615 void readCommand(StringTokenizer t) {
616 if (t.hasMoreTokens()) {
617 String cmdfname = t.nextToken();
618 if (!readCommandFile(new File(cmdfname))) {
619 MessageOutput.println("Could not open:", cmdfname);
620 }
621 } else {
622 MessageOutput.println("Usage: read <command-filename>");
623 }
624 }
625
626 /**
627 * Read and execute a command file. Return true if the file was read
628 * else false;
629 */
630 boolean readCommandFile(File f) {
631 BufferedReader inFile = null;
632 try {
633 if (f.canRead()) {
634 // Process initial commands.
635 MessageOutput.println("*** Reading commands from", f.getPath());
636 inFile = new BufferedReader(new FileReader(f));
637 String ln;
638 while ((ln = inFile.readLine()) != null) {
639 StringTokenizer t = new StringTokenizer(ln);
640 if (t.hasMoreTokens()) {
641 executeCommand(t);
642 }
643 }
644 }
645 } catch (IOException e) {
646 } finally {
647 if (inFile != null) {
648 try {
649 inFile.close();
650 } catch (Exception exc) {
651 }
652 }
653 }
654 return inFile != null;
655 }
656
657 /**
658 * Try to read commands from dir/fname, unless
659 * the canonical path passed in is the same as that
660 * for dir/fname.
661 * Return null if that file doesn't exist,
662 * else return the canonical path of that file.
663 */
664 String readStartupCommandFile(String dir, String fname, String canonPath) {
665 File dotInitFile = new File(dir, fname);
666 if (!dotInitFile.exists()) {
667 return null;
668 }
669
670 String myCanonFile;
671 try {
672 myCanonFile = dotInitFile.getCanonicalPath();
673 } catch (IOException ee) {
674 MessageOutput.println("Could not open:", dotInitFile.getPath());
675 return null;
676 }
677 if (canonPath == null || !canonPath.equals(myCanonFile)) {
678 if (!readCommandFile(dotInitFile)) {
679 MessageOutput.println("Could not open:", dotInitFile.getPath());
680 }
681 }
682 return myCanonFile;
683 }
684
685
686 public TTY() throws Exception {
687
688 MessageOutput.println("Initializing progname", progname);
689
690 if (Env.connection().isOpen() && Env.vm().canBeModified()) {
691 /*
692 * Connection opened on startup. Start event handler
693 * immediately, telling it (through arg 2) to stop on the
694 * VM start event.
695 */
696 this.handler = new EventHandler(this, true);
697 }
698 try {
699 BufferedReader in =
700 new BufferedReader(new InputStreamReader(System.in));
701
702 String lastLine = null;
703
704 Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
705
706 /*
707 * Read start up files. This mimics the behavior
708 * of gdb which will read both ~/.gdbinit and then
709 * ./.gdbinit if they exist. We have the twist that
710 * we allow two different names, so we do this:
711 * if ~/jdb.ini exists,
712 * read it
713 * else if ~/.jdbrc exists,
714 * read it
715 *
716 * if ./jdb.ini exists,
717 * if it hasn't been read, read it
718 * It could have been read above because ~ == .
719 * or because of symlinks, ...
720 * else if ./jdbrx exists
721 * if it hasn't been read, read it
722 */
723 {
724 String userHome = System.getProperty("user.home");
725 String canonPath;
726
727 if ((canonPath = readStartupCommandFile(userHome, "jdb.ini", null)) == null) {
728 // Doesn't exist, try alternate spelling
729 canonPath = readStartupCommandFile(userHome, ".jdbrc", null);
730 }
731
732 String userDir = System.getProperty("user.dir");
733 if (readStartupCommandFile(userDir, "jdb.ini", canonPath) == null) {
734 // Doesn't exist, try alternate spelling
735 readStartupCommandFile(userDir, ".jdbrc", canonPath);
736 }
737 }
738
739 // Process interactive commands.
740 MessageOutput.printPrompt();
741 while (true) {
742 String ln = in.readLine();
743 if (ln == null) {
744 MessageOutput.println("Input stream closed.");
745 ln = "quit";
746 }
747
748 if (ln.startsWith("!!") && lastLine != null) {
749 ln = lastLine + ln.substring(2);
750 MessageOutput.printDirectln(ln);// Special case: use printDirectln()
751 }
752
753 StringTokenizer t = new StringTokenizer(ln);
754 if (t.hasMoreTokens()) {
755 lastLine = ln;
756 executeCommand(t);
757 } else {
758 MessageOutput.printPrompt();
759 }
760 }
761 } catch (VMDisconnectedException e) {
762 handler.handleDisconnectedException();
763 }
764 }
765
766 private static void usage() {
767 MessageOutput.println("zz usage text", new Object [] {progname,
768 File.pathSeparator});
769 System.exit(1);
770 }
771
772 static void usageError(String messageKey) {
773 MessageOutput.println(messageKey);
774 MessageOutput.println();
775 usage();
776 }
777
778 static void usageError(String messageKey, String argument) {
779 MessageOutput.println(messageKey, argument);
780 MessageOutput.println();
781 usage();
782 }
783
784 private static boolean supportsSharedMemory() {
785 for (Connector connector :
786 Bootstrap.virtualMachineManager().allConnectors()) {
787 if (connector.transport() == null) {
788 continue;
789 }
790 if ("dt_shmem".equals(connector.transport().name())) {
791 return true;
792 }
793 }
794 return false;
795 }
796
797 private static String addressToSocketArgs(String address) {
798 int index = address.indexOf(':');
799 if (index != -1) {
800 String hostString = address.substring(0, index);
801 String portString = address.substring(index + 1);
802 return "hostname=" + hostString + ",port=" + portString;
803 } else {
804 return "port=" + address;
805 }
806 }
807
808 private static boolean hasWhitespace(String string) {
809 int length = string.length();
810 for (int i = 0; i < length; i++) {
811 if (Character.isWhitespace(string.charAt(i))) {
812 return true;
813 }
814 }
815 return false;
816 }
817
818 private static String addArgument(String string, String argument) {
819 if (hasWhitespace(argument) || argument.indexOf(',') != -1) {
820 // Quotes were stripped out for this argument, add 'em back.
821 StringBuffer buffer = new StringBuffer(string);
822 buffer.append('"');
823 for (int i = 0; i < argument.length(); i++) {
824 char c = argument.charAt(i);
825 if (c == '"') {
826 buffer.append('\\');
827 }
828 buffer.append(c);
829 }
830 buffer.append("\" ");
831 return buffer.toString();
832 } else {
833 return string + argument + ' ';
834 }
835 }
836
837 public static void main(String argv[]) throws MissingResourceException {
838 String cmdLine = "";
839 String javaArgs = "";
840 int traceFlags = VirtualMachine.TRACE_NONE;
841 boolean launchImmediately = false;
842 String connectSpec = null;
843
844 MessageOutput.textResources = ResourceBundle.getBundle
845 ("com.sun.tools.example.debug.tty.TTYResources",
846 Locale.getDefault());
847
848 for (int i = 0; i < argv.length; i++) {
849 String token = argv[i];
850 if (token.equals("-dbgtrace")) {
851 if ((i == argv.length - 1) ||
852 ! Character.isDigit(argv[i+1].charAt(0))) {
853 traceFlags = VirtualMachine.TRACE_ALL;
854 } else {
855 String flagStr = "";
856 try {
857 flagStr = argv[++i];
858 traceFlags = Integer.decode(flagStr).intValue();
859 } catch (NumberFormatException nfe) {
860 usageError("dbgtrace flag value must be an integer:",
861 flagStr);
862 return;
863 }
864 }
865 } else if (token.equals("-X")) {
866 usageError("Use java minus X to see");
867 return;
868 } else if (
869 // Standard VM options passed on
870 token.equals("-v") || token.startsWith("-v:") || // -v[:...]
871 token.startsWith("-verbose") || // -verbose[:...]
872 token.startsWith("-D") ||
873 // -classpath handled below
874 // NonStandard options passed on
875 token.startsWith("-X") ||
876 // Old-style options (These should remain in place as long as
877 // the standard VM accepts them)
878 token.equals("-noasyncgc") || token.equals("-prof") ||
879 token.equals("-verify") || token.equals("-noverify") ||
880 token.equals("-verifyremote") ||
881 token.equals("-verbosegc") ||
882 token.startsWith("-ms") || token.startsWith("-mx") ||
883 token.startsWith("-ss") || token.startsWith("-oss") ) {
884
885 javaArgs = addArgument(javaArgs, token);
886 } else if (token.equals("-tclassic")) {
887 usageError("Classic VM no longer supported.");
888 return;
889 } else if (token.equals("-tclient")) {
890 // -client must be the first one
891 javaArgs = "-client " + javaArgs;
892 } else if (token.equals("-tserver")) {
893 // -server must be the first one
894 javaArgs = "-server " + javaArgs;
895 } else if (token.equals("-sourcepath")) {
896 if (i == (argv.length - 1)) {
897 usageError("No sourcepath specified.");
898 return;
899 }
900 Env.setSourcePath(argv[++i]);
901 } else if (token.equals("-classpath")) {
902 if (i == (argv.length - 1)) {
903 usageError("No classpath specified.");
904 return;
905 }
906 javaArgs = addArgument(javaArgs, token);
907 javaArgs = addArgument(javaArgs, argv[++i]);
908 } else if (token.equals("-attach")) {
909 if (connectSpec != null) {
910 usageError("cannot redefine existing connection", token);
911 return;
912 }
913 if (i == (argv.length - 1)) {
914 usageError("No attach address specified.");
915 return;
916 }
917 String address = argv[++i];
918
919 /*
920 * -attach is shorthand for one of the reference implementation's
921 * attaching connectors. Use the shared memory attach if it's
922 * available; otherwise, use sockets. Build a connect
923 * specification string based on this decision.
924 */
925 if (supportsSharedMemory()) {
926 connectSpec = "com.sun.jdi.SharedMemoryAttach:name=" +
927 address;
928 } else {
929 String suboptions = addressToSocketArgs(address);
930 connectSpec = "com.sun.jdi.SocketAttach:" + suboptions;
931 }
932 } else if (token.equals("-listen") || token.equals("-listenany")) {
933 if (connectSpec != null) {
934 usageError("cannot redefine existing connection", token);
935 return;
936 }
937 String address = null;
938 if (token.equals("-listen")) {
939 if (i == (argv.length - 1)) {
940 usageError("No attach address specified.");
941 return;
942 }
943 address = argv[++i];
944 }
945
946 /*
947 * -listen[any] is shorthand for one of the reference implementation's
948 * listening connectors. Use the shared memory listen if it's
949 * available; otherwise, use sockets. Build a connect
950 * specification string based on this decision.
951 */
952 if (supportsSharedMemory()) {
953 connectSpec = "com.sun.jdi.SharedMemoryListen:";
954 if (address != null) {
955 connectSpec += ("name=" + address);
956 }
957 } else {
958 connectSpec = "com.sun.jdi.SocketListen:";
959 if (address != null) {
960 connectSpec += addressToSocketArgs(address);
961 }
962 }
963 } else if (token.equals("-launch")) {
964 launchImmediately = true;
965 } else if (token.equals("-listconnectors")) {
966 Commands evaluator = new Commands();
967 evaluator.commandConnectors(Bootstrap.virtualMachineManager());
968 return;
969 } else if (token.equals("-connect")) {
970 /*
971 * -connect allows the user to pick the connector
972 * used in bringing up the target VM. This allows
973 * use of connectors other than those in the reference
974 * implementation.
975 */
976 if (connectSpec != null) {
977 usageError("cannot redefine existing connection", token);
978 return;
979 }
980 if (i == (argv.length - 1)) {
981 usageError("No connect specification.");
982 return;
983 }
984 connectSpec = argv[++i];
985 } else if (token.equals("-help")) {
986 usage();
987 } else if (token.equals("-version")) {
988 Commands evaluator = new Commands();
989 evaluator.commandVersion(progname,
990 Bootstrap.virtualMachineManager());
991 System.exit(0);
992 } else if (token.startsWith("-")) {
993 usageError("invalid option", token);
994 return;
995 } else {
996 // Everything from here is part of the command line
997 cmdLine = addArgument("", token);
998 for (i++; i < argv.length; i++) {
999 cmdLine = addArgument(cmdLine, argv[i]);
1000 }
1001 break;
1002 }
1003 }
1004
1005 /*
1006 * Unless otherwise specified, set the default connect spec.
1007 */
1008
1009 /*
1010 * Here are examples of jdb command lines and how the options
1011 * are interpreted as arguments to the program being debugged.
1012 * arg1 arg2
1013 * ---- ----
1014 * jdb hello a b a b
1015 * jdb hello "a b" a b
1016 * jdb hello a,b a,b
1017 * jdb hello a, b a, b
1018 * jdb hello "a, b" a, b
1019 * jdb -connect "com.sun.jdi.CommandLineLaunch:main=hello a,b" illegal
1020 * jdb -connect com.sun.jdi.CommandLineLaunch:main=hello "a,b" illegal
1021 * jdb -connect 'com.sun.jdi.CommandLineLaunch:main=hello "a,b"' arg1 = a,b
1022 * jdb -connect 'com.sun.jdi.CommandLineLaunch:main=hello "a b"' arg1 = a b
1023 * jdb -connect 'com.sun.jdi.CommandLineLaunch:main=hello a b' arg1 = a arg2 = b
1024 * jdb -connect 'com.sun.jdi.CommandLineLaunch:main=hello "a," b' arg1 = a, arg2 = b
1025 */
1026 if (connectSpec == null) {
1027 connectSpec = "com.sun.jdi.CommandLineLaunch:";
1028 } else if (!connectSpec.endsWith(",") && !connectSpec.endsWith(":")) {
1029 connectSpec += ","; // (Bug ID 4285874)
1030 }
1031
1032 cmdLine = cmdLine.trim();
1033 javaArgs = javaArgs.trim();
1034
1035 if (cmdLine.length() > 0) {
1036 if (!connectSpec.startsWith("com.sun.jdi.CommandLineLaunch:")) {
1037 usageError("Cannot specify command line with connector:",
1038 connectSpec);
1039 return;
1040 }
1041 connectSpec += "main=" + cmdLine + ",";
1042 }
1043
1044 if (javaArgs.length() > 0) {
1045 if (!connectSpec.startsWith("com.sun.jdi.CommandLineLaunch:")) {
1046 usageError("Cannot specify target vm arguments with connector:",
1047 connectSpec);
1048 return;
1049 }
1050 connectSpec += "options=" + javaArgs + ",";
1051 }
1052
1053 try {
1054 if (! connectSpec.endsWith(",")) {
1055 connectSpec += ","; // (Bug ID 4285874)
1056 }
1057 Env.init(connectSpec, launchImmediately, traceFlags);
1058 new TTY();
1059 } catch(Exception e) {
1060 MessageOutput.printException("Internal exception:", e);
1061 }
1062 }
1063}