9 #include <sys/socket.h>
10 #include <readline/readline.h>
11 #include "functions.h"
13 #include "gldecoder.h"
15 #include "strformat.h"
20 GlDbg *GlDbg::instance = 0;
22 GlDbg::GlDbg(int argc, char **argv):
25 process(vector<string>(argv+1, argv+argc)),
36 unsigned len = readlink("/proc/self/exe", buf, sizeof(buf));
38 string::size_type slash = exe.rfind('/');
39 process.setenv("LD_PRELOAD", (exe.substr(0, slash+1)+"glwrap.so"));
41 const list<Tool::Factory *> &factories = Tool::get_factories();
42 for(list<Tool::Factory *>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
43 tools.push_back((*i)->create(*this));
48 for(ToolList::iterator i=tools.begin(); i!=tools.end(); ++i)
54 signal(SIGINT, &sighandler);
55 signal(SIGCHLD, &sighandler);
57 printf("GLdbg 0.0\n");
58 printf("Copyright © 2009-2010 Mikkosoft Productions\n");
59 printf("Type \"help\" for a list of commands\n");
69 if(process.get_state()!=Process::INACTIVE)
70 throw runtime_error("Program is already running");
73 socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
76 int flags = fcntl(sock_fd, F_GETFD);
77 fcntl(sock_fd, F_SETFD, flags|FD_CLOEXEC);
79 process.setenv("GLWRAP_FD", strformat("%d", fds[1]));
80 process.setenv("GLWRAP_CTRL_FD", strformat("%d", fds[1]));
84 for(BreakList::iterator i=breakpoints.begin(); i!=breakpoints.end(); )
89 i->owners.push_back(0);
90 send_breakpoint(i->function, i->flag, 0);
94 breakpoints.erase(i++);
97 for(ToolList::iterator i=tools.begin(); i!=tools.end(); ++i)
98 (*i)->process_started();
101 void GlDbg::send(GlPacket *pkt)
103 if(process.get_state()==Process::INACTIVE)
104 throw runtime_error("Program is not running");
106 packet_send(pkt, sock_fd);
111 GlPacket *pkt = packet_begin(FUNC_GLDHOLD);
115 void GlDbg::send_breakpoint(unsigned short func, unsigned char set_flags, unsigned char clear_flags)
117 GlPacket *pkt = packet_begin(FUNC_GLDBREAK);
118 packet_write_short(pkt, func);
119 packet_write_char(pkt, set_flags);
120 packet_write_char(pkt, clear_flags);
124 void GlDbg::set_breakpoint(unsigned short func, unsigned char flag, Tool *owner)
126 Breakpoint *bp = (func ? get_breakpoint(func, flag) : 0);
128 bp->add_owner(owner);
133 breakpoints.push_back(Breakpoint(func, flag));
134 breakpoints.back().add_owner(owner);
137 if(process.get_state()>=Process::RUNNING)
138 send_breakpoint(func, flag, 0);
142 void GlDbg::clear_breakpoint(unsigned short func, unsigned char flag, Tool *owner)
144 Breakpoint *bp = get_breakpoint(func, flag);
147 bp->remove_owner(owner);
148 if(bp->owners.empty())
150 if(current_break==bp)
153 // XXX Inefficient. Should get_breakpoint() return an iterator?
154 for(BreakList::iterator i=breakpoints.begin(); i!=breakpoints.end(); ++i)
155 if(i->function==func && i->flag==flag)
157 breakpoints.erase(i);
161 if(process.get_state()>=Process::RUNNING)
162 send_breakpoint(func, 0, flag);
167 void GlDbg::resume_from_break(Tool *tool)
172 ToolList::iterator i = find(break_holders.begin(), break_holders.end(), tool);
173 if(i!=break_holders.end())
174 break_holders.erase(i);
176 if(break_holders.empty())
180 void GlDbg::quit(bool force)
182 if(!force && process.get_state()!=Process::INACTIVE)
183 throw runtime_error("Program is still running");
192 stop_reason = process.check();
193 if((stop_reason>>8)==3)
197 Process::State pstate = process.get_state();
198 if((pstate!=Process::INACTIVE && pstate!=Process::STOPPED) || flushing)
204 if(stop_reason==0x100)
205 printf("Target process exited normally\n");
206 else if((stop_reason>>8)==1)
207 printf("Target process exited with status %d\n", stop_reason&0xFF);
208 else if((stop_reason>>8)==2)
209 printf("Target process terminated with signal %d\n", stop_reason&0xFF);
210 else if((stop_reason>>8)==3)
211 printf("Target process stopped by signal %d\n", stop_reason&0xFF);
216 char *line = readline("gldbg> ");
221 cmd_interp.execute(line);
223 catch(const exception &e)
225 printf("%s\n", e.what());
229 else if(pstate==Process::INACTIVE)
234 void GlDbg::read_stream()
236 pollfd pfd = { sock_fd, POLLIN, 0 };
237 int ret = poll(&pfd, 1, (flushing ? 0 : -1));
241 ret = read(sock_fd, rbuf, 1024);
244 buffer.append(rbuf, ret);
245 while(buffer.size()>buf_offset)
247 const char *data = buffer.data()+buf_offset;
248 unsigned len = buffer.size()-buf_offset;
249 GlPacket *pkt = packet_receive_str(data, &len);
254 packet_read_short(pkt, (short *)&func);
255 if(func==FUNC_GLDBREAK)
257 packet_read_short(pkt, (short *)&func);
259 packet_read_char(pkt, (char *)&flag);
261 current_break = get_breakpoint(func, flag);
262 bool announce = !current_break;
265 break_holders = current_break->owners;
266 announce = current_break->has_owner(0);
270 printf("Breakpoint: %s\n", get_function_name(func));
273 for(ToolList::iterator i=tools.begin(); i!=tools.end(); ++i)
274 (*i)->decode(data, len);
279 buffer.erase(0, buf_offset);
290 for(ToolList::iterator i=tools.begin(); i!=tools.end(); ++i)
291 (*i)->process_stopped(stop_reason);
293 if(process.get_state()==Process::RUNNING)
299 GlDbg::Breakpoint *GlDbg::get_breakpoint(unsigned short func, unsigned char flag)
301 for(BreakList::iterator i=breakpoints.begin(); i!=breakpoints.end(); ++i)
302 if(i->function==func && i->flag==flag)
308 void GlDbg::sighandler(int sig)
311 instance->got_sigchld = true;
315 GlDbg::Breakpoint::Breakpoint(unsigned short f, unsigned char l):
320 void GlDbg::Breakpoint::add_owner(Tool *t)
322 ToolList::iterator i = find(owners.begin(), owners.end(), t);
327 bool GlDbg::Breakpoint::has_owner(Tool *t) const
329 ToolList::const_iterator i = find(owners.begin(), owners.end(), t);
330 return i!=owners.end();
333 void GlDbg::Breakpoint::remove_owner(Tool *t)
335 ToolList::iterator i = find(owners.begin(), owners.end(), t);