*/
#include <cstdlib>
-#include <cerrno>
-#include <cstring>
+#include <fcntl.h>
+#include <signal.h>
#include <sys/poll.h>
#include <sys/socket.h>
-#include <sys/wait.h>
+#include <readline/readline.h>
#include <msp/core/except.h>
#include <msp/fs/dir.h>
#include <msp/io/print.h>
Application::RegApp<GlDbg> GlDbg::reg;
GlDbg::GlDbg(int argc, char **argv):
- pid(0),
- sock_fd(-1),
- glprint(glprint_new(0, 16384))
+ cmd_interp(*this),
+ process(vector<string>(argv+1, argv+argc)),
+ buf_offset(0),
+ flushing(false),
+ got_sigchld(false)
{
- libdir = FS::get_sys_lib_dir(argv[0], "gldbg");
- args.assign(argv+1, argv+argc);
+ FS::Path libdir = FS::get_sys_lib_dir(argv[0], "gldbg");
+ process.setenv("LD_PRELOAD", (libdir/"glwrap.so").str().c_str());
}
int GlDbg::main()
{
catch_signal(SIGINT);
- launch();
+ catch_signal(SIGCHLD);
+ set_loop_mode(TICK_BUSY);
+
+ IO::print("GLdbg 0.0\n");
+ IO::print("Copyright © 2009 Mikkosoft Productions\n");
+ IO::print("Type \"help\" for a list of commands\n");
Application::main();
+
+ return 0;
+}
+
+void GlDbg::launch()
+{
+ if(process.get_state()!=Process::INACTIVE)
+ throw InvalidState("Program is already running");
+
+ int fds[2];
+ socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+ sock_fd = fds[0];
+
+ int flags = fcntl(sock_fd, F_GETFD);
+ fcntl(sock_fd, F_SETFD, flags|FD_CLOEXEC);
+
+ process.setenv("GLWRAP_FD", lexical_cast(fds[1]));
+ process.launch();
+ close(fds[1]);
+}
+
+void GlDbg::quit(bool force)
+{
+ if(!force && process.get_state()!=Process::INACTIVE)
+ throw InvalidState("Program is still running");
+ exit(0);
}
void GlDbg::tick()
{
- int status;
- int ret = waitpid(pid, &status, WNOHANG);
- if(ret==pid)
+ if(got_sigchld)
{
- if(WIFEXITED(status) || WIFSIGNALED(status))
+ got_sigchld = false;
+ int ret = process.check();
+ if(ret==0x100)
+ IO::print("Target process exited normally\n");
+ else if((ret>>8)==1)
+ IO::print("Target process exited with status %d\n", ret&0xFF);
+ else if((ret>>8)==2)
+ IO::print("Target process terminated with signal %d\n", ret&0xFF);
+ else if((ret>>8)==3)
{
- IO::print("Target process exited\n");
- exit(0);
+ IO::print("Target process stopped by signal %d\n", ret&0xFF);
+ flushing = true;
+ }
+ }
+
+ Process::State pstate = process.get_state();
+ if((pstate!=Process::INACTIVE && pstate!=Process::STOPPED) || flushing)
+ read_stream();
+ else
+ {
+ char *line = readline("gldbg> ");
+ if(line)
+ {
+ try
+ {
+ cmd_interp.execute(line);
+ }
+ catch(const Exception &e)
+ {
+ IO::print("%s\n", e.what());
+ }
+ free(line);
}
+ else if(pstate==Process::INACTIVE)
+ exit(0);
}
+}
+void GlDbg::read_stream()
+{
pollfd pfd = { sock_fd, POLLIN, 0 };
- ret = poll(&pfd, 1, -1);
+ int ret = poll(&pfd, 1, (flushing ? 0 : -1));
if(ret>0)
{
char rbuf[1024];
buffer.append(rbuf, ret);
while(buffer.size()>buf_offset)
{
- int ret = gldecoder_decode(glprint, buffer.data()+buf_offset, buffer.size()-buf_offset);
- if(ret<0)
+ const char *data = buffer.data()+buf_offset;
+ unsigned len = buffer.size()-buf_offset;
+ int size = gldecoder_decode(0, data, len);
+ if(size<0)
break;
- buf_offset += ret;
- IO::print("%s\n", glprint_get_buffer(glprint));
+ tracer.decode(data, len);
+ glstate.decode(data, len);
+ profiler.decode(data, len);
+ buf_offset += size;
}
if(buf_offset>8192)
{
}
}
}
+ else if(flushing)
+ flushing = false;
}
-void GlDbg::launch()
+void GlDbg::sighandler(int sig)
{
- int fds[2];
- socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
- sock_fd = fds[0];
-
- pid = fork();
- if(pid==0)
- {
- string fd_str = lexical_cast(fds[1]);
- setenv("LD_PRELOAD", (libdir/"glwrap.so").str().c_str(), true);
- setenv("GLWRAP_FD", fd_str.c_str(), true);
- close(fds[0]);
- std::vector<char *> argv(args.size()+1);
- for(unsigned i=0; i<args.size(); ++i)
- argv[i] = strdup(args[i].c_str());
- argv[args.size()] = 0;
- execvp(argv[0], &argv[0]);
- ::exit(127);
- }
- else if(pid>0)
- {
- close(fds[1]);
- }
- else
- {
- throw SystemError("Could not launch process", errno);
- }
+ if(sig==SIGCHLD)
+ got_sigchld = true;
}