]> git.tdb.fi Git - gldbg.git/blob - source/gldbg.cpp
5a4ad191f65c29a6c760deae5c329657b44b21b0
[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         Application::main();
43 }
44
45 void GlDbg::launch()
46 {
47         if(process.get_state()!=Process::INACTIVE)
48                 throw InvalidState("Program is already running");
49
50         int fds[2];
51         socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
52         sock_fd = fds[0];
53
54         int flags = fcntl(sock_fd, F_GETFD);
55         fcntl(sock_fd, F_SETFD, flags|FD_CLOEXEC);
56
57         process.setenv("GLWRAP_FD", lexical_cast(fds[1]));
58         process.launch();
59         close(fds[1]);
60 }
61         
62 void GlDbg::quit()
63 {
64         if(process.get_state()!=Process::INACTIVE)
65                 throw InvalidState("Program is still running");
66         exit(0);
67 }
68
69 void GlDbg::tick()
70 {
71         if(got_sigchld)
72         {
73                 got_sigchld = false;
74                 int ret = process.check();
75                 if(ret==0x100)
76                         IO::print("Target process exited normally\n");
77                 else if((ret>>8)==1)
78                         IO::print("Target process exited with status %d\n", ret&0xFF);
79                 else if((ret>>8)==2)
80                         IO::print("Target process terminated with signal %d\n", ret&0xFF);
81                 else if((ret>>8)==3)
82                 {
83                         IO::print("Target process stopped by signal %d\n", ret&0xFF);
84                         flushing = true;
85                 }
86         }
87
88         Process::State pstate = process.get_state();
89         if((pstate!=Process::INACTIVE && pstate!=Process::STOPPED) || flushing)
90                 read_stream();
91         else
92         {
93                 char *line = readline("gldbg> ");
94                 if(line)
95                 {
96                         try
97                         {
98                                 cmd_interp.execute(line);
99                         }
100                         catch(const Exception &e)
101                         {
102                                 IO::print("%s\n", e.what());
103                         }
104                         free(line);
105                 }
106                 else if(pstate==Process::INACTIVE)
107                         exit(0);
108         }
109 }
110
111 void GlDbg::read_stream()
112 {
113         pollfd pfd = { sock_fd, POLLIN, 0 };
114         int ret = poll(&pfd, 1, (flushing ? 0 : -1));
115         if(ret>0)
116         {
117                 char rbuf[1024];
118                 ret = read(sock_fd, rbuf, 1024);
119                 if(ret>0)
120                 {
121                         buffer.append(rbuf, ret);
122                         while(buffer.size()>buf_offset)
123                         {
124                                 const char *data = buffer.data()+buf_offset;
125                                 unsigned len = buffer.size()-buf_offset;
126                                 int size = gldecoder_decode(0, data, len);
127                                 if(size<0)
128                                         break;
129                                 tracer.decode(data, len);
130                                 buf_offset += size;
131                         }
132                         if(buf_offset>8192)
133                         {
134                                 buffer.erase(0, buf_offset);
135                                 buf_offset=0;
136                         }
137                 }
138         }
139         else if(flushing)
140                 flushing = false;
141 }
142
143 void GlDbg::sighandler(int sig)
144 {
145         if(sig==SIGCHLD)
146                 got_sigchld = true;
147 }