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