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+
26+package com.sun.tools.example.debug.tty;
27+
28+import com.sun.jdi.*;
29+import com.sun.jdi.event.*;
30+import com.sun.jdi.request.*;
31+import com.sun.jdi.connect.*;
32+
33+import java.util.*;
34+import java.io.*;
35+
36+public 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+}