001    package nl.cwi.sen1.tide.adapters.gdb;
002    
003    import java.io.BufferedReader;
004    import java.io.File;
005    import java.io.IOException;
006    import java.io.InputStreamReader;
007    import java.io.OutputStreamWriter;
008    import java.io.Writer;
009    import java.util.Iterator;
010    
011    import nl.cwi.sen1.tide.adapters.DebugAdapter;
012    import nl.cwi.sen1.tide.adapters.DebugAdapterRule;
013    import aterm.ATermFactory;
014    import aterm.pure.PureFactory;
015    
016    public class GdbAdapter extends DebugAdapter {
017            static public final int MODE_STEP_INTO = 0;
018            static public final int MODE_STEP_OVER = 1;
019            static public final int MODE_RUN = 2;
020    
021            private String name;
022            private GdbProcess process;
023    
024            private BufferedReader input;
025            private BufferedReader error;
026            private Writer output;
027    
028            static public final void main(String[] args) throws IOException {
029                    int pid = -1;
030                    int port = 9500;
031                    String program = null;
032                    String arguments = "";
033                    ATermFactory factory = new PureFactory();
034    
035                    for (int i = 0; i < args.length; i++) {
036                            if (args[i].equals("-attach")) {
037                                    pid = Integer.parseInt(args[++i]);
038                            } else if (args[i].equals("-program")) {
039                                    program = args[++i];
040                            } else if (args[i].equals("-help")) {
041                                    usage();
042                            } else if (args[i].equals("-args")) {
043                                    arguments = arguments + " " + args[++i];
044                            } else if (args[i].equals("-port")) {
045                                    port = Integer.parseInt(args[++i]);
046                            }
047                    }
048                    
049                    if (program == null) {
050                            usage();
051                    }
052    
053                    // String cmd = "gdb -interpreter=mi -f -q " + program;
054                    String cmd = "gdb -f -q " + program;
055                    if (pid >= 0) {
056                            cmd += " " + pid;
057                    }
058    
059                    Process process = Runtime.getRuntime().exec(cmd);
060                    debugMsg("gdb started");
061                    GdbAdapter adapter = new GdbAdapter(factory, program, args, arguments, process, port);
062                    adapter.run();
063            }
064    
065            static void usage() {
066                    System.err.println(
067                            "usage: tide-gdb -port <tide-port> -program <prg> [-attach <pid>]");
068                    System.exit(1);
069            }
070            
071            static private void debugMsg(String msg) {
072                    System.err.println(msg);
073            }
074    
075            public GdbAdapter(
076                    ATermFactory factory,
077                    String filename,
078                    String[] args,
079                    String processArguments,
080                    Process proc,
081                    int port)
082                    throws IOException {
083                    super(factory, args, port);     
084    
085                    File file = new File(filename);
086                    this.name = file.getName();
087    
088                    createGdbIOReaders(proc);
089                    buildGdbConnection(processArguments, name);
090                    run();
091            }
092    
093            private void buildGdbConnection(String args, String name) {
094                    writeln("set args " + args);
095                    writeln("set prompt (gdb)\\n");
096                    writeln("define hook-stop");
097                    writeln("bt -1");
098                    writeln("end");
099            
100                    process = new GdbProcess(this,name);
101            
102                    evaluate(new SetBreakpointCmd(this, "main"));
103                    evaluate(new ContinueCmd(this, process) {
104                            public String command() {
105                                    return "run\n";
106                            }
107                    });
108                    evaluate(new RetrievePidCmd(this, process));
109                    
110                    processCreated(process);
111            }
112    
113            private void createGdbIOReaders(Process proc) {
114                    input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
115                    error = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
116                    output = new OutputStreamWriter(proc.getOutputStream());
117            }
118    
119            public void writeln(String line) {
120                    try {
121                            output.write(line);
122                            output.write("\n");
123                            output.flush();
124                    } catch (IOException e) {
125                            debugMsg("connection with gdb broken!");
126                    }
127            }
128            public void evaluate(Command cmd) {
129                    try {
130                            String string = cmd.command();
131                            debugMsg("entering poll mode with gdb command:\n\t" + string);
132                            output.write(string);
133                            output.flush();
134                            String line;
135                            do {
136                                    line = input.readLine();
137                                    debugMsg("processing line in poll mode:\n\t" + line);
138                                    if (line.length() == 0) {
139                                            continue; // Ignore empty lines
140                                    } else if (line.startsWith("(gdb)")) {
141                                            continue; // Ignore prompt
142                                    } else if (line.startsWith("Starting program:")) {
143                                            continue; // Ignore 'Starting program:' line
144                                    }
145                            } while (!cmd.response(line));
146                            debugMsg("poll mode done!");
147                    } catch (IOException e) {
148                            debugMsg("connection with GDB broken.");
149                            System.exit(1);
150                    }
151            }
152    
153            public int calcRunMode() {
154                    if (process.rulesPerPort[DebugAdapterRule.PORT_STEP].size() == 0) {
155                            return MODE_RUN;
156                    }
157    
158                    // Look for any 'non step-over' rules
159                    Iterator<DebugAdapterRule> iter = process.rulesPerPort[DebugAdapterRule.PORT_STEP].iterator();
160                    while (iter.hasNext()) {
161                            DebugAdapterRule rule = iter.next();
162                            if (!rule.isStepOver()) {
163                                    return MODE_STEP_INTO;
164                            }
165                    }
166    
167                    return MODE_STEP_OVER;
168            }
169    }