3 This file is part of gldbg
4 Copyright © 2009-2010 Mikko Rasa, Mikkosoft Productions
5 Distributed under the GPL
13 #include <sys/socket.h>
14 #include <readline/readline.h>
15 #include <msp/core/except.h>
16 #include <msp/fs/dir.h>
17 #include <msp/io/print.h>
18 #include <msp/strings/lexicalcast.h>
19 #include "functions.h"
21 #include "gldecoder.h"
28 Application::RegApp<GlDbg> GlDbg::reg;
30 GlDbg::GlDbg(int argc, char **argv):
32 process(vector<string>(argv+1, argv+argc)),
39 FS::Path libdir = FS::get_sys_lib_dir(argv[0], "gldbg");
40 process.setenv("LD_PRELOAD", (libdir/"glwrap.so").str().c_str());
42 const list<Tool::Factory *> &factories = Tool::get_factories();
43 for(list<Tool::Factory *>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
44 tools.push_back((*i)->create(*this));
49 for(ToolList::iterator i=tools.begin(); i!=tools.end(); ++i)
56 catch_signal(SIGCHLD);
57 set_loop_mode(TICK_BUSY);
59 IO::print("GLdbg 0.0\n");
60 IO::print("Copyright © 2009-2010 Mikkosoft Productions\n");
61 IO::print("Type \"help\" for a list of commands\n");
70 if(process.get_state()!=Process::INACTIVE)
71 throw InvalidState("Program is already running");
74 socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
77 int flags = fcntl(sock_fd, F_GETFD);
78 fcntl(sock_fd, F_SETFD, flags|FD_CLOEXEC);
80 process.setenv("GLWRAP_FD", lexical_cast(fds[1]));
81 process.setenv("GLWRAP_CTRL_FD", lexical_cast(fds[1]));
86 for(ToolList::iterator i=tools.begin(); i!=tools.end(); ++i)
87 (*i)->process_started();
90 void GlDbg::send(GlPacket *pkt)
92 packet_send(pkt, sock_fd);
97 GlPacket *pkt = packet_begin(FUNC_GLDHOLD);
101 void GlDbg::set_breakpoint(unsigned short func, unsigned char flag, Tool *owner)
103 Breakpoint *bp = (func ? get_breakpoint(func, flag) : 0);
105 bp->add_owner(owner);
110 breakpoints.push_back(Breakpoint(func, flag));
111 breakpoints.back().add_owner(owner);
114 GlPacket *pkt = packet_begin(FUNC_GLDBREAK);
115 packet_write_short(pkt, func);
116 packet_write_char(pkt, flag);
117 packet_write_char(pkt, 0);
122 void GlDbg::clear_breakpoint(unsigned short func, unsigned char flag, Tool *owner)
124 Breakpoint *bp = get_breakpoint(func, flag);
127 bp->remove_owner(owner);
128 if(bp->owners.empty())
130 if(current_break==bp)
133 // XXX Inefficient. Should get_breakpoint() return an iterator?
134 for(BreakList::iterator i=breakpoints.begin(); i!=breakpoints.end(); ++i)
135 if(i->function==func && i->flag==flag)
137 breakpoints.erase(i);
141 GlPacket *pkt = packet_begin(FUNC_GLDBREAK);
142 packet_write_short(pkt, func);
143 packet_write_char(pkt, 0);
144 packet_write_char(pkt, flag);
150 void GlDbg::resume_from_break(Tool *tool)
155 ToolList::iterator i = find(break_holders.begin(), break_holders.end(), tool);
156 if(i!=break_holders.end())
157 break_holders.erase(i);
159 if(break_holders.empty())
163 void GlDbg::quit(bool force)
165 if(!force && process.get_state()!=Process::INACTIVE)
166 throw InvalidState("Program is still running");
175 stop_reason = process.check();
176 if((stop_reason>>8)==3)
180 Process::State pstate = process.get_state();
181 if((pstate!=Process::INACTIVE && pstate!=Process::STOPPED) || flushing)
187 if(stop_reason==0x100)
188 IO::print("Target process exited normally\n");
189 else if((stop_reason>>8)==1)
190 IO::print("Target process exited with status %d\n", stop_reason&0xFF);
191 else if((stop_reason>>8)==2)
192 IO::print("Target process terminated with signal %d\n", stop_reason&0xFF);
193 else if((stop_reason>>8)==3)
194 IO::print("Target process stopped by signal %d\n", stop_reason&0xFF);
199 char *line = readline("gldbg> ");
204 cmd_interp.execute(line);
206 catch(const Exception &e)
208 IO::print("%s\n", e.what());
212 else if(pstate==Process::INACTIVE)
217 void GlDbg::read_stream()
219 pollfd pfd = { sock_fd, POLLIN, 0 };
220 int ret = poll(&pfd, 1, (flushing ? 0 : -1));
224 ret = read(sock_fd, rbuf, 1024);
227 buffer.append(rbuf, ret);
228 while(buffer.size()>buf_offset)
230 const char *data = buffer.data()+buf_offset;
231 unsigned len = buffer.size()-buf_offset;
232 GlPacket *pkt = packet_receive_str(data, &len);
237 packet_read_short(pkt, (short *)&func);
238 if(func==FUNC_GLDBREAK)
240 packet_read_short(pkt, (short *)&func);
242 packet_read_char(pkt, (char *)&flag);
244 current_break = get_breakpoint(func, flag);
245 bool announce = !current_break;
248 break_holders = current_break->owners;
249 announce = current_break->has_owner(0);
253 IO::print("Breakpoint: %s\n", get_function_name(func));
256 for(ToolList::iterator i=tools.begin(); i!=tools.end(); ++i)
257 (*i)->decode(data, len);
262 buffer.erase(0, buf_offset);
273 for(ToolList::iterator i=tools.begin(); i!=tools.end(); ++i)
274 (*i)->process_stopped(stop_reason);
276 if(process.get_state()==Process::RUNNING)
282 GlDbg::Breakpoint *GlDbg::get_breakpoint(unsigned short func, unsigned char flag)
284 for(BreakList::iterator i=breakpoints.begin(); i!=breakpoints.end(); ++i)
285 if(i->function==func && i->flag==flag)
291 void GlDbg::sighandler(int sig)
298 GlDbg::Breakpoint::Breakpoint(unsigned short f, unsigned char l):
303 void GlDbg::Breakpoint::add_owner(Tool *t)
305 ToolList::iterator i = find(owners.begin(), owners.end(), t);
310 bool GlDbg::Breakpoint::has_owner(Tool *t) const
312 ToolList::const_iterator i = find(owners.begin(), owners.end(), t);
313 return i!=owners.end();
316 void GlDbg::Breakpoint::remove_owner(Tool *t)
318 ToolList::iterator i = find(owners.begin(), owners.end(), t);