]> git.tdb.fi Git - gldbg.git/blob - source/gldbg.cpp
Add help
[gldbg.git] / source / gldbg.cpp
1 /* $Id$
2
3 This file is part of gldbg
4 Copyright © 2009  Mikko Rasa, Mikkosoft Productions
5 Distributed under the GPL
6 */
7
8 #include <cstdlib>
9 #include <fcntl.h>
10 #include <signal.h>
11 #include <sys/poll.h>
12 #include <sys/socket.h>
13 #include <readline/readline.h>
14 #include <msp/core/except.h>
15 #include <msp/fs/dir.h>
16 #include <msp/io/print.h>
17 #include <msp/strings/lexicalcast.h>
18 #include "gldbg.h"
19 #include "glprint.h"
20
21 using namespace std;
22 using namespace Msp;
23
24 Application::RegApp<GlDbg> GlDbg::reg;
25
26 GlDbg::GlDbg(int argc, char **argv):
27         cmd_interp(*this),
28         process(vector<string>(argv+1, argv+argc)),
29         flushing(false),
30         got_sigchld(false)
31 {
32         FS::Path libdir = FS::get_sys_lib_dir(argv[0], "gldbg");
33         process.setenv("LD_PRELOAD", (libdir/"glwrap.so").str().c_str());
34 }
35
36 int GlDbg::main()
37 {
38         catch_signal(SIGINT);
39         catch_signal(SIGCHLD);
40         set_loop_mode(TICK_BUSY);
41
42         IO::print("GLdbg 0.0\n");
43         IO::print("Copyright © 2009 Mikkosoft Productions\n");
44         IO::print("Type \"help\" for a list of commands\n");
45
46         Application::main();
47 }
48
49 void GlDbg::launch()
50 {
51         if(process.get_state()!=Process::INACTIVE)
52                 throw InvalidState("Program is already running");
53
54         int fds[2];
55         socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
56         sock_fd = fds[0];
57
58         int flags = fcntl(sock_fd, F_GETFD);
59         fcntl(sock_fd, F_SETFD, flags|FD_CLOEXEC);
60
61         process.setenv("GLWRAP_FD", lexical_cast(fds[1]));
62         process.launch();
63         close(fds[1]);
64 }
65         
66 void GlDbg::quit()
67 {
68         if(process.get_state()!=Process::INACTIVE)
69                 throw InvalidState("Program is still running");
70         exit(0);
71 }
72
73 void GlDbg::tick()
74 {
75         if(got_sigchld)
76         {
77                 got_sigchld = false;
78                 int ret = process.check();
79                 if(ret==0x100)
80                         IO::print("Target process exited normally\n");
81                 else if((ret>>8)==1)
82                         IO::print("Target process exited with status %d\n", ret&0xFF);
83                 else if((ret>>8)==2)
84                         IO::print("Target process terminated with signal %d\n", ret&0xFF);
85                 else if((ret>>8)==3)
86                 {
87                         IO::print("Target process stopped by signal %d\n", ret&0xFF);
88                         flushing = true;
89                 }
90         }
91
92         Process::State pstate = process.get_state();
93         if((pstate!=Process::INACTIVE && pstate!=Process::STOPPED) || flushing)
94                 read_stream();
95         else
96         {
97                 char *line = readline("gldbg> ");
98                 if(line)
99                 {
100                         try
101                         {
102                                 cmd_interp.execute(line);
103                         }
104                         catch(const Exception &e)
105                         {
106                                 IO::print("%s\n", e.what());
107                         }
108                         free(line);
109                 }
110                 else if(pstate==Process::INACTIVE)
111                         exit(0);
112         }
113 }
114
115 void GlDbg::read_stream()
116 {
117         pollfd pfd = { sock_fd, POLLIN, 0 };
118         int ret = poll(&pfd, 1, (flushing ? 0 : -1));
119         if(ret>0)
120         {
121                 char rbuf[1024];
122                 ret = read(sock_fd, rbuf, 1024);
123                 if(ret>0)
124                 {
125                         buffer.append(rbuf, ret);
126                         while(buffer.size()>buf_offset)
127                         {
128                                 const char *data = buffer.data()+buf_offset;
129                                 unsigned len = buffer.size()-buf_offset;
130                                 int size = gldecoder_decode(0, data, len);
131                                 if(size<0)
132                                         break;
133                                 tracer.decode(data, len);
134                                 buf_offset += size;
135                         }
136                         if(buf_offset>8192)
137                         {
138                                 buffer.erase(0, buf_offset);
139                                 buf_offset=0;
140                         }
141                 }
142         }
143         else if(flushing)
144                 flushing = false;
145 }
146
147 void GlDbg::sighandler(int sig)
148 {
149         if(sig==SIGCHLD)
150                 got_sigchld = true;
151 }