Source Code Cross Referenced for Debugger.java in  » Parser » Rats-Parser-Generators » xtc » lang » jeannie » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Parser » Rats Parser Generators » xtc.lang.jeannie 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package xtc.lang.jeannie;
0002:
0003:        import java.io.BufferedOutputStream;
0004:        import java.io.BufferedReader;
0005:        import java.io.BufferedWriter;
0006:        import java.io.IOException;
0007:        import java.io.InputStream;
0008:        import java.io.InputStreamReader;
0009:        import java.io.OutputStream;
0010:        import java.io.OutputStreamWriter;
0011:        import java.util.regex.Matcher;
0012:        import java.util.regex.Pattern;
0013:
0014:        import xtc.tree.GNode;
0015:
0016:        /**
0017:         * The Blink terminal debugger. This debugger internally uses jdb and gdb to
0018:         * support the Jeannie source level debugging.
0019:         * 
0020:         * @author Byeongcheol (BK) Lee
0021:         */
0022:        public class Debugger {
0023:
0024:            /**
0025:             * The debugger control status.
0026:             */
0027:            public enum DebugerControlStatus {
0028:                NONE, JDB, GDB, JDB_IN_GDB, GDB_IN_JDB,
0029:            }
0030:
0031:            /**
0032:             * The current state of jdb process.
0033:             */
0034:            private enum ProcessState {
0035:                NOT_CREATED, LIVE, DEAD,
0036:            }
0037:
0038:            /**
0039:             * Prints a usage message to the user, and terminate the Blink debugger with
0040:             * an error code(-1).
0041:             * 
0042:             * @param msg A message to the user to show what is wrong in the command line.
0043:             */
0044:            private static void usage(String msg) {
0045:                StringBuffer buf = new StringBuffer();
0046:                if (msg != null && msg.length() > 0) {
0047:                    buf.append(msg).append("\n\n");
0048:                }
0049:                buf
0050:                        .append("Usage: xtc.lang.jennie.Debugger [options] CLASS [arguments]\n");
0051:                buf.append("Blink options include:\n");
0052:                buf.append("\t-help\n");
0053:                buf.append('\n');
0054:
0055:                buf.append("options forwarded to jdb include:\n");
0056:                buf.append("\t-sourcepath <directories separated by \":\">\n");
0057:                buf.append("\t-attach <address>\n");
0058:                buf.append("\t-listen <address>\n");
0059:                buf.append("\t-listenany\n");
0060:                buf.append("\t-launch\n");
0061:                buf.append("\t-dbgtrace [flags]\n");
0062:                buf.append("\t-tclient\n");
0063:                buf.append("\t-tserver\n");
0064:                buf.append('\n');
0065:
0066:                buf
0067:                        .append("options forwarded to debuggee through jdb include:\n");
0068:                buf.append("\t-v -verbose[:class|gc|jni]\n");
0069:                buf.append("\t-D<name>=<value>  system property\n");
0070:                buf.append("\t-classpath <directories separated by \":\">\n");
0071:                buf.append("\t-X<option>\n");
0072:
0073:                System.out.println(buf.toString());
0074:                System.exit(-1);
0075:            }
0076:
0077:            /**
0078:             * Print the help message for the Blink command.
0079:             * 
0080:             */
0081:            void printCommandHelp() {
0082:                final StringBuilder sb = new StringBuilder();
0083:                sb.append("\n");
0084:                sb.append("help               print help\n");
0085:                sb.append("exit               exit the Blink debugger\n");
0086:                sb.append("run                start the program run\n");
0087:                sb.append("\n");
0088:                sb
0089:                        .append("break [file:line]         add a break point e.g.) break Main.jni:9\n");
0090:                sb
0091:                        .append("stop at <classid>:<line>  add a break point  e.g.) stop at Main:15\n");
0092:                sb.append("watch <expr>              add a watch point \n");
0093:                sb
0094:                        .append("watch [access/all] <class id>.<fieldname>  add a watch point\n");
0095:                sb.append("info break                list break points\n");
0096:                sb.append("info watch                list watch points\n");
0097:                sb
0098:                        .append("delete [n]                delete a break/watch point with its id [n].\n");
0099:                sb.append("\n");
0100:                sb.append("where                     dump stack trace\n");
0101:                sb.append("up n                      select n frames up\n");
0102:                sb.append("down n                    select n frames down\n");
0103:                sb
0104:                        .append("locals                    print local variables in selected frame\n");
0105:                sb.append("\n");
0106:                sb.append("continue                  coninue running.\n");
0107:                sb
0108:                        .append("step                      execute until another line reached\n");
0109:                sb
0110:                        .append("next                      execute the next line, including function calls\n");
0111:                sb.append("\n");
0112:                sb
0113:                        .append("print <jexpr>             print Jeannie expression\n");
0114:                sb.append("list                      print source code.\n");
0115:                out(sb.toString());
0116:            }
0117:
0118:            /**
0119:             * The main method for the Blink debugger.
0120:             * 
0121:             * @param args The command line arguments.
0122:             */
0123:            public static void main(String[] args) {
0124:                StringBuffer sbJDBOptions = new StringBuffer();
0125:                StringBuffer sbGDBOPtions = new StringBuffer();
0126:                String mainClass = null;
0127:                StringBuffer sbMainOptions = new StringBuffer();
0128:
0129:                // parse arguments
0130:                for (int i = 0; i < args.length; i++) {
0131:                    String arg = args[i];
0132:                    // [options] CLASS
0133:                    if (mainClass == null) {
0134:                        if (arg.equals("-help")) {
0135:                            usage("");
0136:                        } else if (arg.equals("-sourcepath")) {
0137:                            if ((i + 1) >= args.length)
0138:                                usage("Please, specify path after -sourcepath.");
0139:                            String argPath = args[++i];
0140:                            sbJDBOptions.append(' ').append(arg).append(' ')
0141:                                    .append(argPath);
0142:                        } else if (arg.equals("-attach")) {
0143:                            if ((i + 1) >= args.length)
0144:                                usage("Please, specify <address> after -attach.");
0145:                            String argPath = args[++i];
0146:                            sbJDBOptions.append(' ').append(arg).append(' ')
0147:                                    .append(argPath);
0148:                        } else if (arg.equals("-dbgtrace")) {
0149:                            sbJDBOptions.append(' ').append(arg);
0150:                        } else if (arg.equals("-classpath")) {
0151:                            if ((i + 1) >= args.length)
0152:                                usage("Please, specify path after -classpath.");
0153:                            String argPath = args[++i];
0154:                            sbJDBOptions.append(' ').append(arg).append(' ')
0155:                                    .append(argPath);
0156:                        } else if (arg.matches("-D[^=]+=.*")) {
0157:                            sbJDBOptions.append(' ').append(arg);
0158:                        } else {
0159:                            mainClass = arg;
0160:                        }
0161:                    } else {
0162:                        // [arguments]
0163:                        sbMainOptions.append(' ').append(args);
0164:                    }
0165:                }
0166:
0167:                // check arguments
0168:                if (mainClass == null) {
0169:                    usage("Please, specify the main CLASS name.");
0170:                }
0171:
0172:                // Now, run the Blink debugger.
0173:                StringBuffer jdbArguments = new StringBuffer();
0174:                jdbArguments.append(sbJDBOptions);
0175:                jdbArguments.append(' ').append(mainClass);
0176:                jdbArguments.append(' ').append(sbMainOptions);
0177:                Debugger jeannieDebugger = new Debugger(
0178:                        jdbArguments.toString(), sbGDBOPtions.toString());
0179:                try {
0180:                    jeannieDebugger.startDebugging();
0181:                    jeannieDebugger.runUserCommandLoop();
0182:                } catch (Exception e) {
0183:                    e.printStackTrace();
0184:                } finally {
0185:                    jeannieDebugger.ensureResourceRelease();
0186:                }
0187:
0188:            }
0189:
0190:            /**
0191:             * The option string to be forwarded to the jdb.
0192:             */
0193:            private final String jdbArguments;
0194:
0195:            /**
0196:             * The jdb slave process.
0197:             */
0198:            private SlaveProcessHandler jdbHandler;
0199:
0200:            /**
0201:             * The option string to be forwarded to the gdb.
0202:             */
0203:            private final String gdbOptions;
0204:
0205:            /**
0206:             * The gdb slave process.
0207:             */
0208:            private SlaveProcessHandler gdbHandler;
0209:
0210:            /**
0211:             * This flag is set to be true at the beginning. If any slave process is dead,
0212:             * this flag is set to be false, indicating that the current debugging session
0213:             * should terminate.
0214:             */
0215:            boolean allSlaveProcessLive = true;
0216:
0217:            /**
0218:             * The current debugger control status.
0219:             */
0220:            private DebugerControlStatus debugerControlStatus = DebugerControlStatus.NONE;
0221:
0222:            /**
0223:             * The user terminal input stream.
0224:             */
0225:            private final BufferedReader userInput;
0226:
0227:            /**
0228:             * The user terminal output stream.
0229:             */
0230:            private final BufferedOutputStream userOutput;
0231:
0232:            /**
0233:             * The user terminal error stream.
0234:             */
0235:            private final BufferedOutputStream userError;
0236:
0237:            /**
0238:             * This is a flag to recode a fact that the jdb and gdb are initialized for
0239:             * j2c and c2j debugger switching.
0240:             */
0241:            private boolean debuggerSwitchingInitialized = false;
0242:
0243:            /**
0244:             * The actual implementation of the blink macro command.
0245:             */
0246:            final DebuggerCommand debuggerCommand;
0247:
0248:            /**
0249:             * The Blink command parser.
0250:             */
0251:            final DebuggerInterpreter interpreter;
0252:
0253:            /**
0254:             * @param jdbArguments The jdb command line options.
0255:             * @param gdbOptions The gdb command line options.
0256:             */
0257:            private Debugger(final String jdbArguments, final String gdbOptions) {
0258:                this .jdbArguments = jdbArguments;
0259:                this .gdbOptions = gdbOptions;
0260:                //prepares terminal I/O members
0261:                this .userInput = new BufferedReader(new InputStreamReader(
0262:                        System.in));
0263:                this .userOutput = new BufferedOutputStream(System.out);
0264:                this .userError = new BufferedOutputStream(System.err);
0265:
0266:                this .debuggerCommand = new DebuggerCommand(this );
0267:                this .interpreter = new DebuggerInterpreter(this );
0268:            }
0269:
0270:            /**
0271:             * Start debugging processes with jdb.
0272:             */
0273:            private void startDebugging() throws IOException {
0274:                //jdb - attach the debugee
0275:                String jdbCommand = "jdb " + jdbArguments;
0276:                out("lanuching jdb : " + jdbCommand);
0277:                jdbHandler = new SlaveProcessHandler("jdb", jdbCommand);
0278:                jdbHandler.requestExpect("Initializing jdb ...");
0279:                jdbHandler.start();
0280:                jdbHandler.waitForExpect();
0281:                jdbHandler.runAndWait("stop in DebugHelper.c2j\n",
0282:                        "Deferring breakpoint DebugHelper.c2j");
0283:                jdbHandler.runAndWait("stop in java.lang.System.loadLibrary\n",
0284:                        "Deferring breakpoint java.lang.System.loadLibrary.");
0285:                out("jdb is initialized.");
0286:            }
0287:
0288:            /**
0289:             * Run the user command loop. Ask the user a command, and redirect the command
0290:             * to the Blink macro command executer. This command loop may return if any
0291:             * slave processes such as jdb, gdb and debuggee terminates or if the user
0292:             * asks the termination with "exit" command.
0293:             */
0294:            private void runUserCommandLoop() {
0295:                try {
0296:                    changeDebugStatus(DebugerControlStatus.JDB);
0297:                    sendUserMessage("\n");
0298:
0299:                    // The user command loop.
0300:                    for (String line = userInput.readLine(); line != null
0301:                            && allSlaveProcessLive; line = userInput.readLine()) {
0302:                        final String language;
0303:                        switch (debugerControlStatus) {
0304:                        case JDB_IN_GDB:
0305:                        case JDB:
0306:                            language = "Java";
0307:                            break;
0308:                        case GDB_IN_JDB:
0309:                        case GDB:
0310:                            language = "C";
0311:                            break;
0312:                        default:
0313:                            language = null;
0314:                            assert false;
0315:                            break;
0316:                        }
0317:                        final Object astOrMsg = Utilities
0318:                                .debuggerParseAndAnalyze(language, line,
0319:                                        debuggerCommand.dbgExpr);
0320:                        if (astOrMsg instanceof  GNode) {
0321:                            final GNode ast = (GNode) astOrMsg;
0322:                            if (ast.hasName("ExitCommand"))
0323:                                break;
0324:                            interpreter.dispatch(ast);
0325:                        } else {
0326:                            err((String) astOrMsg);
0327:                        }
0328:                    }
0329:                } catch (IOException e) {
0330:                    System.err.println("error in the system input stream");
0331:                    e.printStackTrace();
0332:                }
0333:            }
0334:
0335:            /**
0336:             * Implement Blink "run" command.
0337:             */
0338:            void run() {
0339:                try {
0340:                    assert (getControlStatus() == DebugerControlStatus.JDB);
0341:                    runAndWaitJDB("run\n", "run");
0342:                    changeDebugStatus(Debugger.DebugerControlStatus.NONE);
0343:                } catch (IOException e) {
0344:                    err("could not successfully run the application");
0345:                }
0346:            }
0347:
0348:            /**
0349:             * Implements the j2c macro command. This will activate the gdb assuming that
0350:             * the jdb has control over the debuggee.
0351:             */
0352:            void j2n() {
0353:                if (!IsDebuggerSwitchingInitialized()) {
0354:                    out("please run initj before j2c");
0355:                    return;
0356:                }
0357:                out("running j2c and switching gdb user interaction...");
0358:                try {
0359:                    runJDBAndWaitGDB("eval DebugHelper.j2c()\n",
0360:                            "Program received signal SIGTRAP, Trace/breakpoint trap.");
0361:                    changeDebugStatus(DebugerControlStatus.GDB_IN_JDB);
0362:                } catch (IOException e) {
0363:                    err("failed in executing j2c\n");
0364:                    e.printStackTrace();
0365:                }
0366:            }
0367:
0368:            /**
0369:             * Implements c2j macro command. This will activate the jdb assuming that gdb
0370:             * has control over the debugee.
0371:             */
0372:            void n2j() {
0373:                if (!IsDebuggerSwitchingInitialized()) {
0374:                    out("please run initj before c2j");
0375:                    return;
0376:                }
0377:                out("running c2j and switching jdb user interaction...");
0378:                try {
0379:                    runGDBAndWaitJDB("call DebugHelper_c2j()\n",
0380:                            "Breakpoint hit:");
0381:                    changeDebugStatus(DebugerControlStatus.JDB_IN_GDB);
0382:                } catch (IOException e) {
0383:                    err("failed in executing c2j\n");
0384:                    e.printStackTrace();
0385:                }
0386:            }
0387:
0388:            /**
0389:             * Implements jret macro command. If the current debugger nesting is jdb->gdb,
0390:             * then this will resume the gdb break point, and the user input redirection
0391:             * will be switched to the jdb. If the current debugger nesting is gdb->jdb,
0392:             * this will resume the jdb break point, and the user input redirection will
0393:             * be switched to the gdb.
0394:             */
0395:            void jret() {
0396:                if (!IsDebuggerSwitchingInitialized()) {
0397:                    out("please run initj before jret");
0398:                    return;
0399:                }
0400:                switch (getControlStatus()) {
0401:                case NONE:
0402:                case JDB:
0403:                case GDB:
0404:                    out("jret is for jdb and gdb nesting.");
0405:                    break;
0406:                case JDB_IN_GDB:
0407:                    out("return to gdb");
0408:                    try {
0409:                        runJDBAndWaitGDB("cont\n", "= 1");
0410:                        changeDebugStatus(DebugerControlStatus.GDB);
0411:                    } catch (IOException e) {
0412:                        err("failed in resuming jdb control nested in the gdb");
0413:                    }
0414:                    break;
0415:                case GDB_IN_JDB:
0416:                    out("returning to jdb");
0417:                    try {
0418:                        runGDBAndWaitJDB("continue\n",
0419:                                "DebugHelper.j2c\\(\\) = <void value>");
0420:                        changeDebugStatus(DebugerControlStatus.JDB);
0421:                    } catch (IOException e) {
0422:                        err("failed in resuming gdb control nested in the jdb");
0423:                    }
0424:                    break;
0425:                default:
0426:                    break;
0427:                }
0428:            }
0429:
0430:            /**
0431:             * Implement Blink "continue/cont" command.
0432:             * 
0433:             */
0434:            void cont() {
0435:                switch (getControlStatus()) {
0436:                case JDB:
0437:                    try {
0438:                        sendUserMessage("cont\n");
0439:                        changeDebugStatus(Debugger.DebugerControlStatus.NONE);
0440:                    } catch (IOException e) {
0441:                        err("failed in executing the continue");
0442:                    }
0443:                    break;
0444:                case GDB:
0445:                    try {
0446:                        sendUserMessage("continue\n");
0447:                        changeDebugStatus(Debugger.DebugerControlStatus.NONE);
0448:                    } catch (IOException e) {
0449:                        err("failed in executing the continue");
0450:                    }
0451:                    break;
0452:                case JDB_IN_GDB:
0453:                    out("\"continue\" is not allowed in jdb nested in the gdb.");
0454:                    out("use jret to return to the gdb");
0455:                    break;
0456:                case GDB_IN_JDB:
0457:                    out("\"continue\" is not allowed in gdb nested in the jdb.");
0458:                    out("use jret to return to the jdb");
0459:                    break;
0460:                }
0461:            }
0462:
0463:            /**
0464:             * @return Wheather or not the jdb/gdb switching is ready.
0465:             */
0466:            boolean IsDebuggerSwitchingInitialized() {
0467:                return debuggerSwitchingInitialized;
0468:            }
0469:
0470:            /**
0471:             * Prepare jdb and gdb for j2c and c2j debugger switching.
0472:             */
0473:            void preparingDebuggerSwitching() {
0474:                if (IsDebuggerSwitchingInitialized()) {
0475:                    out("debuggers were previously initialized for switching.");
0476:                    return;
0477:                }
0478:
0479:                // try to initialize the DebugHelper
0480:                try {
0481:                    runAndWaitJDB(
0482:                            "eval java.lang.Class.forName(\"DebugHelper\")\n",
0483:                            "java.lang.Class.forName\\(\"DebugHelper\"\\) = \"class DebugHelper\"");
0484:                    runAndWaitJDB("eval DebugHelper.init()\n",
0485:                            "DebugHelper.init\\(\\) = <void value>");
0486:                } catch (IOException e) {
0487:                    err("failed in executing initj for jdb\n");
0488:                    return;
0489:                }
0490:
0491:                // get debugee process id through the DebugHelper Code.
0492:                int debugeeProcessID;
0493:                try {
0494:                    Matcher m = runAndWaitJDB(
0495:                            "print DebugHelper.getProcessID()\n",
0496:                            "DebugHelper.getProcessID\\(\\) = (\\d+)");
0497:                    debugeeProcessID = Integer.parseInt(m.group(1));
0498:                } catch (IOException e) {
0499:                    err("failed in getting debugged process id\n");
0500:                    return;
0501:                }
0502:
0503:                // gdb - attach the debugee
0504:                try {
0505:                    String gdbCommand = "gdb -nw -quiet --pid "
0506:                            + debugeeProcessID + " -ex continue " + gdbOptions;
0507:                    gdbHandler = new SlaveProcessHandler("gdb", gdbCommand);
0508:                    gdbHandler.requestExpect("Continuing");
0509:                    gdbHandler.start();
0510:                    gdbHandler.waitForExpect();
0511:                    out("gdb is initialized.");
0512:                    sendUserMessage("\n"); // trigger 'jdb' prompt.
0513:                } catch (IOException e) {
0514:                    err("failed in \n");
0515:                    return;
0516:                }
0517:
0518:                debuggerSwitchingInitialized = true;
0519:            }
0520:
0521:            /**
0522:             * Send a message to the jdb , and wait until the jdb sends back an expected
0523:             * message.
0524:             * 
0525:             * @param msg The message to send to the jdb.
0526:             * @param expect The message to be expected from the jdb.
0527:             * @return The matched result for the expected messsage.
0528:             */
0529:            Matcher runAndWaitJDB(String msg, String expect) throws IOException {
0530:                return jdbHandler.runAndWait(msg, expect);
0531:            }
0532:
0533:            /**
0534:             * Send a message to the jdb, and wait for a number of expected messages from
0535:             * the jdb.
0536:             * 
0537:             * @param msg The message to send to jdb.
0538:             * @param expects The list of expected message message.
0539:             * @return The response from the jdb.
0540:             */
0541:            DebuggerResponse runAndWaitJDB(String msg, String[] expects)
0542:                    throws IOException {
0543:                return jdbHandler.runAndWait(msg, expects);
0544:            }
0545:
0546:            /**
0547:             * Send a message to the gdb process, and wait until the gdb sends back an
0548:             * expected message.
0549:             * 
0550:             * @param msg The message to send.
0551:             * @param expect The message to be expected from the gdb.
0552:             */
0553:            Matcher runAndWaitGDB(String msg, String expect) throws IOException {
0554:                return gdbHandler.runAndWait(msg, expect);
0555:            }
0556:
0557:            /**
0558:             * Send a message to the jdb process, and wait until the gdb sends back an
0559:             * expected message.
0560:             * 
0561:             * @param msg The message to send.
0562:             * @param expect The message to be expected from the slave process.
0563:             */
0564:            Matcher runJDBAndWaitGDB(String msg, String expect)
0565:                    throws IOException {
0566:                return jdbHandler.runAndWait(msg, expect, gdbHandler);
0567:            }
0568:
0569:            /**
0570:             * Send a message to the gdb process, and wait until the jdb sends back an
0571:             * expected message.
0572:             * 
0573:             * @param msg The message to send.
0574:             * @param expect The list of the messages expected from the jdb.
0575:             */
0576:            Matcher runGDBAndWaitJDB(String msg, String expect)
0577:                    throws IOException {
0578:                return gdbHandler.runAndWait(msg, expect, jdbHandler);
0579:            }
0580:
0581:            /**
0582:             * Print a message to the console.
0583:             * 
0584:             * @param msg The message to print.
0585:             */
0586:            void out(String msg) {
0587:                try {
0588:                    userOutput.write(msg.getBytes());
0589:                    userOutput.flush();
0590:                } catch (IOException e) {
0591:                    e.printStackTrace();
0592:                }
0593:            }
0594:
0595:            /**
0596:             * Print an error message to the console.
0597:             * 
0598:             * @param msg The error message to print.
0599:             */
0600:            void err(String msg) {
0601:                try {
0602:                    String msgAll = "\n[blink] error: " + msg + "\n";
0603:                    userError.write(msgAll.getBytes());
0604:                    userError.flush();
0605:                } catch (IOException e) {
0606:                    e.printStackTrace();
0607:                }
0608:            }
0609:
0610:            /**
0611:             * Switch to the new debugger state.
0612:             * 
0613:             * @param newStatus The requested new state.
0614:             */
0615:            synchronized void changeDebugStatus(DebugerControlStatus newStatus) {
0616:                if (newStatus == debugerControlStatus) {
0617:                    return;
0618:                }
0619:                boolean success = false;
0620:                switch (debugerControlStatus) {
0621:                case NONE:
0622:                    success = newStatus == DebugerControlStatus.JDB
0623:                            || newStatus == DebugerControlStatus.GDB;
0624:                    break;
0625:                case JDB:
0626:                    success = newStatus == DebugerControlStatus.NONE
0627:                            || newStatus == DebugerControlStatus.GDB_IN_JDB;
0628:                    break;
0629:                case GDB:
0630:                    success = newStatus == DebugerControlStatus.NONE
0631:                            || newStatus == DebugerControlStatus.JDB_IN_GDB;
0632:                    break;
0633:                case JDB_IN_GDB:
0634:                    success = newStatus == DebugerControlStatus.GDB;
0635:                    break;
0636:                case GDB_IN_JDB:
0637:                    success = newStatus == DebugerControlStatus.JDB;
0638:                    break;
0639:                }
0640:
0641:                if (success) {
0642:                    debugerControlStatus = newStatus;
0643:                } else {
0644:                    err("Not allowed transition:" + debugerControlStatus + "->"
0645:                            + newStatus);
0646:                    Thread.dumpStack();
0647:                }
0648:            }
0649:
0650:            /**
0651:             * @return The debugger control status.
0652:             */
0653:            DebugerControlStatus getControlStatus() {
0654:                return debugerControlStatus;
0655:            }
0656:
0657:            /**
0658:             * Show the current Blink status.
0659:             */
0660:            void printStatus() {
0661:                out("control: " + debugerControlStatus);
0662:            }
0663:
0664:            /**
0665:             * Send a message to the currently chose debugger.
0666:             * 
0667:             * @param msg The message.
0668:             */
0669:            synchronized void sendUserMessage(String msg) throws IOException {
0670:                switch (debugerControlStatus) {
0671:                case NONE:
0672:                    err("Not sure where to send this messsage:" + msg);
0673:                    break;
0674:                case JDB:
0675:                case JDB_IN_GDB:
0676:                    jdbHandler.sendMessage(msg);
0677:                    break;
0678:                case GDB:
0679:                case GDB_IN_JDB:
0680:                    gdbHandler.sendMessage(msg);
0681:                    break;
0682:                default:
0683:                    err("Unknown debug control status.");
0684:                    break;
0685:                }
0686:            }
0687:
0688:            /**
0689:             * Notification of the death of the slave process.
0690:             * 
0691:             * @param slave The dead process handler.
0692:             */
0693:            private synchronized void onSlaveProcessDeath(
0694:                    SlaveProcessHandler slave) {
0695:                if (slave == jdbHandler) {
0696:                    out("jdb finished...");
0697:                } else if (slave == gdbHandler) {
0698:                    out("gdb finished...");
0699:                }
0700:                allSlaveProcessLive = false;
0701:            }
0702:
0703:            /**
0704:             * Process the output message from the slave process. 
0705:             * 
0706:             * @param slave The handler of the slave process.
0707:             * @param buf The byte buffer.
0708:             * @param len The length of the data in the buffer.
0709:             */
0710:            private void onSlaveProcessOut(SlaveProcessHandler slave,
0711:                    byte[] buf, int len) {
0712:                try {
0713:                    userOutput.write(buf, 0, len);
0714:                    userOutput.flush();
0715:                } catch (IOException e) {
0716:                    e.printStackTrace();
0717:                }
0718:            }
0719:
0720:            /**
0721:             * Process the error message form the slave process.
0722:             * 
0723:             * @param slave The handler of the slave process.
0724:             * @param buf The byte buffer.
0725:             * @param len The length of the data in the buffer.
0726:             */
0727:            private void onSlaveProceeErr(SlaveProcessHandler slave,
0728:                    byte[] buf, int len) {
0729:                try {
0730:                    userError.write(buf, 0, len);
0731:                    userError.flush();
0732:                } catch (IOException e) {
0733:                    e.printStackTrace();
0734:                }
0735:            }
0736:
0737:            /**
0738:             * The process break point hit notification from the slave.
0739:             * @param slave The slave process that gets the break point.
0740:             */
0741:            private synchronized void onSlaveProcessBreakPointHit(
0742:                    SlaveProcessHandler slave) {
0743:                if (slave == jdbHandler) {
0744:                    changeDebugStatus(DebugerControlStatus.JDB);
0745:                } else if (slave == gdbHandler) {
0746:                    changeDebugStatus(DebugerControlStatus.GDB);
0747:                }
0748:            }
0749:
0750:            /**
0751:             * The jdb hits the System.loadLibrary event.
0752:             * @param slave The slave process that gets the System.loadLibrary event.
0753:             */
0754:            private synchronized void onSlaveLoadLibrary(
0755:                    SlaveProcessHandler slave) {
0756:                if (slave != jdbHandler) {
0757:                    return;
0758:                }
0759:
0760:                new Thread("loadLibraryHandler") {
0761:                    public void run() {
0762:                        try {
0763:                            changeDebugStatus(DebugerControlStatus.JDB);
0764:                            runAndWaitJDB(
0765:                                    "clear java.lang.System.loadLibrary\n",
0766:                                    "Removed: breakpoint java.lang.System.loadLibrary");
0767:                            runAndWaitJDB("step up\n", "Step completed:");
0768:                            if (!IsDebuggerSwitchingInitialized()) {
0769:                                preparingDebuggerSwitching();
0770:                            }
0771:
0772:                            if (debuggerCommand.HasDeferredBreakPoint()) {
0773:                                debuggerCommand.HandleDeferredBreakPoint();
0774:                            }
0775:
0776:                            runAndWaitJDB(
0777:                                    "stop in java.lang.System.loadLibrary\n",
0778:                                    "Set breakpoint java.lang.System.loadLibrary");
0779:                            jdbHandler.sendMessage("cont\n");
0780:                            changeDebugStatus(DebugerControlStatus.NONE);
0781:                        } catch (IOException e) {
0782:
0783:                        }
0784:                    }
0785:                }.start();
0786:            }
0787:
0788:            /**
0789:             * Release any system resource create for the debugging. For instance, we want
0790:             * to ensure the jdb and gdb are terminated at the end of this method.
0791:             */
0792:            private void ensureResourceRelease() {
0793:                if (jdbHandler != null) {
0794:                    jdbHandler.finish();
0795:                }
0796:                if (gdbHandler != null) {
0797:                    gdbHandler.finish();
0798:                }
0799:            }
0800:
0801:            /**
0802:             * The jdb break point hit event pattern.
0803:             */
0804:            private final static Pattern jdbBreakPointHitPattern = Pattern
0805:                    .compile("Breakpoint hit: \\\"thread=([^\"]+)\\\", ([^,]+), line=([0-9,]+) bci=([0-9]+)");
0806:
0807:            /**
0808:             * The gdb break point hit event pattern.
0809:             */
0810:            private final static Pattern gdbBreakPointHitPattern = Pattern
0811:                    .compile("Breakpoint [0-9]+, ([^ ]+)");
0812:
0813:            /**
0814:             * A slave process handler specifically for stream I/O and the process ending.
0815:             * This handler is an interface between the Jeannie debugger and its slave
0816:             * processes. This handler creates three thread to monitor the process state,
0817:             * the process input stream and the process output stream. Mostly all these
0818:             * threads will be blocked, not consuming CPU cycle too much.
0819:             */
0820:            private class SlaveProcessHandler {
0821:
0822:                /**
0823:                 * The name of this handler.
0824:                 */
0825:                private final String name;
0826:
0827:                /**
0828:                 * The command line to create the native process.
0829:                 */
0830:                private final String command;
0831:
0832:                /**
0833:                 * The native process.
0834:                 */
0835:                private Process process;
0836:
0837:                /**
0838:                 * The buffered writer to the process.
0839:                 */
0840:                private BufferedWriter out;
0841:
0842:                /**
0843:                 * A thread to redirect the process output message to the Jeannie debugger.
0844:                 */
0845:                private Thread outRedirector;
0846:
0847:                /**
0848:                 * A thread to redirect the process error message to the Jeannie debugger.
0849:                 */
0850:                private Thread errRedirector;
0851:
0852:                /**
0853:                 * If set, the output from the slave will be ignored.
0854:                 */
0855:                private boolean skipBytesInRedirection;
0856:
0857:                /**
0858:                 * The expected message from the output stream.
0859:                 */
0860:                private Pattern[] expectedMessagePatterns;
0861:
0862:                /**
0863:                 * The result of expected message matching;
0864:                 */
0865:                private DebuggerResponse debuggerResponse;
0866:
0867:                /**
0868:                 * This buffer keeps a output line whose length is less then 1024. The
0869:                 * process handler scans the output from the target process, and try to
0870:                 * recognize a line with less than 1024 bytes. If the line over flows, then
0871:                 * this handler will ignore the line.
0872:                 */
0873:                private final byte[] lineBuffer = new byte[1024];
0874:
0875:                /**
0876:                 * This state keeps track of the current line output. 0, ...,
0877:                 * (jdbLineOutputBuffer.length-1): reading the current line.
0878:                 * jdbLineOutputBuffer.length, ...: ignoring the current line.
0879:                 */
0880:                private int numBytesInLineBuffer;
0881:
0882:                /**
0883:                 * The current process state.
0884:                 */
0885:                private ProcessState state = ProcessState.NOT_CREATED;
0886:
0887:                /**
0888:                 * @param jeannieDebugger The Jeannie master debugger.
0889:                 * @param name The name of the slave process.
0890:                 * @param command The command line to create the slave process.
0891:                 */
0892:                SlaveProcessHandler(String name, String command) {
0893:                    this .name = name;
0894:                    this .command = command;
0895:                }
0896:
0897:                /**
0898:                 * Start the monitoring thread.
0899:                 */
0900:                void start() {
0901:                    assert state == ProcessState.NOT_CREATED;
0902:                    try {
0903:                        process = Runtime.getRuntime().exec(command);
0904:                        state = ProcessState.LIVE;
0905:                        OutputStream os = process.getOutputStream();
0906:                        OutputStreamWriter ow = new OutputStreamWriter(os);
0907:                        out = new BufferedWriter(ow);
0908:                        outRedirector = new Thread(name + "-out") {
0909:                            public void run() {
0910:                                handleOutputStream();
0911:                            }
0912:                        };
0913:                        errRedirector = new Thread(name + "-err") {
0914:                            public void run() {
0915:                                handleErrorStream();
0916:                            }
0917:                        };
0918:                        outRedirector.start();
0919:                        errRedirector.start();
0920:                    } catch (IOException e) {
0921:                        err("failed in executing initj for gdb\n");
0922:                        e.printStackTrace();
0923:                    }
0924:
0925:                    assert process != null & outRedirector != null
0926:                            & errRedirector != null;
0927:                }
0928:
0929:                /**
0930:                 * Complete this slave process.
0931:                 */
0932:                void finish() {
0933:                    switch (state) {
0934:                    case NOT_CREATED:
0935:                        state = ProcessState.DEAD;
0936:                        break;
0937:                    case LIVE:
0938:                        state = ProcessState.DEAD;
0939:                        process.destroy();
0940:                        break;
0941:                    case DEAD:
0942:                        break;
0943:                    default:
0944:                        assert false;
0945:                        break;
0946:                    }
0947:
0948:                }
0949:
0950:                /**
0951:                 * The background routine to redirect the slave output to the Jeannie
0952:                 * debugger.
0953:                 */
0954:                private void handleOutputStream() {
0955:                    InputStream is = process.getInputStream();
0956:                    final byte[] buf = new byte[4096];
0957:                    try {
0958:                        while (true) {
0959:                            if (state == ProcessState.DEAD)
0960:                                break;
0961:                            int nread = is.read(buf);
0962:                            if (nread == -1)
0963:                                break;
0964:                            if (state == ProcessState.DEAD)
0965:                                break;
0966:
0967:                            boolean OKToRedirect;
0968:                            synchronized (this ) {
0969:                                OKToRedirect = !skipBytesInRedirection;
0970:                            }
0971:                            if (OKToRedirect)
0972:                                onSlaveProcessOut(this , buf, nread);
0973:                            checkOutputLine(buf, nread);
0974:                        }
0975:                    } catch (IOException e) {
0976:                        if (state == ProcessState.LIVE) {
0977:                            System.err.println("IO error in piping thread"
0978:                                    + name);
0979:                            e.printStackTrace();
0980:                        }
0981:                    } finally {
0982:                        synchronized (this ) {
0983:                            if (state == ProcessState.LIVE) {
0984:                                state = ProcessState.DEAD;
0985:                                onSlaveProcessDeath(this );
0986:                            }
0987:                        }
0988:                    }
0989:                }
0990:
0991:                /**
0992:                 * The background routine to redirect the slave error stream output to the
0993:                 * Jeannie debugger.
0994:                 */
0995:                private void handleErrorStream() {
0996:                    InputStream is = process.getErrorStream();
0997:                    final byte[] buf = new byte[4096];
0998:                    try {
0999:                        while (true) {
1000:                            if (state == ProcessState.DEAD)
1001:                                break;
1002:                            int nread = is.read(buf);
1003:                            if (nread == -1) {
1004:                                synchronized (this ) {
1005:                                    state = ProcessState.DEAD;
1006:                                    onSlaveProcessDeath(this );
1007:                                }
1008:                                break;
1009:                            }
1010:                            if (state == ProcessState.DEAD)
1011:                                break;
1012:                            onSlaveProceeErr(this , buf, nread);
1013:                        }
1014:                    } catch (IOException e) {
1015:                        if (state == ProcessState.LIVE) {
1016:                            System.err.println("IO error in piping thread"
1017:                                    + name);
1018:                            e.printStackTrace();
1019:                        }
1020:                    } finally {
1021:                        synchronized (this ) {
1022:                            if (state == ProcessState.LIVE) {
1023:                                state = ProcessState.DEAD;
1024:                                onSlaveProcessDeath(this );
1025:                            }
1026:                        }
1027:                    }
1028:                }
1029:
1030:                /**
1031:                 * Send a message to the output stream.
1032:                 * 
1033:                 * @param msg The message.
1034:                 */
1035:                void sendMessage(String msg) throws IOException {
1036:                    out.write(msg);
1037:                    out.flush();
1038:                }
1039:
1040:                /**
1041:                 * Check the read data for the output line event.
1042:                 * 
1043:                 * @param buf The data buffer.
1044:                 * @param len The buffer length.
1045:                 */
1046:                void checkOutputLine(byte[] buf, int len) {
1047:                    for (int i = 0; i < len; i++) {
1048:                        byte c = buf[i];
1049:                        if (numBytesInLineBuffer < lineBuffer.length) {
1050:                            if (((char) c) == '\n') {
1051:                                handleOutputLine(new String(lineBuffer, 0,
1052:                                        numBytesInLineBuffer));
1053:                                numBytesInLineBuffer = 0;
1054:                            } else {
1055:                                lineBuffer[numBytesInLineBuffer++] = c;
1056:                            }
1057:                        } else {
1058:                            if (((char) c) == '\n') {
1059:                                numBytesInLineBuffer = 0;
1060:                            } else {
1061:                                numBytesInLineBuffer++;
1062:                            }
1063:                        }
1064:                    }
1065:                }
1066:
1067:                /**
1068:                 * Handle a line from process output.
1069:                 * 
1070:                 * @param line The line output from the process.
1071:                 */
1072:                void handleOutputLine(String line) {
1073:                    if (line.equals(""))
1074:                        return;
1075:
1076:                    // handle any expected message request at first.
1077:                    checkExpect(line);
1078:
1079:                    Matcher mjdbbp = jdbBreakPointHitPattern.matcher(line);
1080:                    if (mjdbbp.find()) {
1081:                        String method = mjdbbp.group(2);
1082:                        if (method.startsWith("java.lang.System.loadLibrary")) {
1083:                            onSlaveLoadLibrary(this );
1084:                        } else if (method.startsWith("DebugHelper")) {
1085:
1086:                        } else {
1087:                            onSlaveProcessBreakPointHit(this );
1088:                        }
1089:                    }
1090:
1091:                    Matcher mgdbbp = gdbBreakPointHitPattern.matcher(line);
1092:                    if (mgdbbp.find()) {
1093:                        onSlaveProcessBreakPointHit(this );
1094:                    }
1095:                }
1096:
1097:                /**
1098:                 * Send a message to the slave process, and wait until the slave sends back
1099:                 * an expected message.
1100:                 * 
1101:                 * @param msg The message to send.
1102:                 * @param expect The message to be expected from the slave process.
1103:                 */
1104:                Matcher runAndWait(String msg, String expect)
1105:                        throws IOException {
1106:                    requestExpect(expect);
1107:                    sendMessage(msg);
1108:                    waitForExpect();
1109:                    return getExpectedMatcher();
1110:                }
1111:
1112:                /**
1113:                 * Send a message to the slave process, and wait until the slave sends back
1114:                 * an expected message.
1115:                 * 
1116:                 * @param msg The message to send.
1117:                 * @param expects The message to be expected from the slave process.
1118:                 */
1119:                DebuggerResponse runAndWait(String msg, String[] expects)
1120:                        throws IOException {
1121:                    requestExpect(expects);
1122:                    sendMessage(msg);
1123:                    waitForExpect();
1124:                    return getDebuggerResponse();
1125:                }
1126:
1127:                /**
1128:                 * Send a message to this slave process, and wait until the other slave
1129:                 * process respond with the expected message.
1130:                 * 
1131:                 * @param msg The message to send.
1132:                 * @param expect The expected message.
1133:                 * @param other The other slave process.
1134:                 */
1135:                Matcher runAndWait(String msg, String expect,
1136:                        SlaveProcessHandler responder) throws IOException {
1137:                    responder.requestExpect(expect);
1138:                    sendMessage(msg);
1139:                    responder.waitForExpect();
1140:                    return responder.getExpectedMatcher();
1141:                }
1142:
1143:                /**
1144:                 * Check if the received bytes says that the expected message was received.
1145:                 * 
1146:                 * @param line The line output from the output stream.
1147:                 */
1148:                private synchronized void checkExpect(String line) {
1149:                    if (expectedMessagePatterns == null)
1150:                        return;
1151:
1152:                    for (int i = 0; i < expectedMessagePatterns.length; i++) {
1153:                        Pattern p = expectedMessagePatterns[i];
1154:                        Matcher m = p.matcher(line);
1155:                        if (m.find()) {
1156:                            this .expectedMessagePatterns = null;
1157:                            this .debuggerResponse = new DebuggerResponse(i, m);
1158:                            this .notify();
1159:                            return;
1160:                        }
1161:                    }
1162:                }
1163:
1164:                /**
1165:                 * Request a message arrival notification.
1166:                 * 
1167:                 * @param rexpr The regular expression to wait for.
1168:                 */
1169:                synchronized void requestExpect(String rexpr) {
1170:                    requestExpect(new String[] { rexpr });
1171:                }
1172:
1173:                /**
1174:                 * 
1175:                 * @param rexprs The array of regular repressions to wait for.
1176:                 */
1177:                synchronized void requestExpect(String[] exprs) {
1178:                    int numRegularExpressions = exprs.length;
1179:                    expectedMessagePatterns = new Pattern[numRegularExpressions];
1180:                    for (int i = 0; i < numRegularExpressions; i++) {
1181:                        String rexpr = exprs[i];
1182:                        expectedMessagePatterns[i] = Pattern.compile(rexpr);
1183:                    }
1184:                    skipBytesInRedirection = true;
1185:                }
1186:
1187:                /**
1188:                 * Wait until we see the expected message in the stream.
1189:                 */
1190:                synchronized void waitForExpect() {
1191:                    if (expectedMessagePatterns == null)
1192:                        return;
1193:                    try {
1194:                        this .wait(); // wait until awaken by the checkExpect.
1195:                    } catch (InterruptedException e) {
1196:                    }
1197:                    skipBytesInRedirection = false;
1198:                }
1199:
1200:                /**
1201:                 * Return the match object for the expected message.
1202:                 * 
1203:                 * @return The match object for the regular expression
1204:                 */
1205:                synchronized Matcher getExpectedMatcher() {
1206:                    assert debuggerResponse != null;
1207:                    return debuggerResponse.getMatcher();
1208:                }
1209:
1210:                /**
1211:                 * Return the debugger's response object.
1212:                 * 
1213:                 * @return The debugger's response.
1214:                 */
1215:                synchronized DebuggerResponse getDebuggerResponse() {
1216:                    return debuggerResponse;
1217:                }
1218:            }
1219:
1220:            /**
1221:             * A debugger's response to the blink's command.
1222:             *  
1223:             */
1224:            public static class DebuggerResponse {
1225:
1226:                /**
1227:                 * The message ID to show which expected message request. 
1228:                 */
1229:                final int expectedMessageID;
1230:
1231:                /**
1232:                 * The matched message.
1233:                 */
1234:                final Matcher matchedMessage;
1235:
1236:                /**
1237:                 * @param mid The message id.
1238:                 * @param msg THe matcher.
1239:                 */
1240:                DebuggerResponse(int mid, Matcher msg) {
1241:                    expectedMessageID = mid;
1242:                    matchedMessage = msg;
1243:                }
1244:
1245:                /**
1246:                 * @return The expected message ID.
1247:                 */
1248:                int getExpectedMessageID() {
1249:                    return expectedMessageID;
1250:                }
1251:
1252:                /**
1253:                 * @return The matcher object.
1254:                 */
1255:                Matcher getMatcher() {
1256:                    return matchedMessage;
1257:                }
1258:            }
1259:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.