From: Mikko Rasa Date: Wed, 12 Jan 2011 11:59:07 +0000 (+0000) Subject: Track owners of breakpoints X-Git-Url: http://git.tdb.fi/?p=gldbg.git;a=commitdiff_plain;h=6d297b506314c07bff3d77c2853a5f59380cfcb0 Track owners of breakpoints Send breakpoint flag from glwrap.so Delay announcing stop until the stream has been flushed Let tools know about process starting and stopping Add methods for hold and sending arbitary packets to GlDbg Break on any tracepoint if holding Link glwrap.so against dl.so --- diff --git a/Makefile b/Makefile index 6313e0f..010fe28 100644 --- a/Makefile +++ b/Makefile @@ -71,6 +71,7 @@ $(OBJECTS_gldbg): CXXFLAGS += $(shell pkg-config --cflags $(PACKAGES_gldbg)) gldbg: LIBS += $(shell pkg-config --libs $(PACKAGES_gldbg)) -lreadline gldump gldbg: LIBS += ./libgldbg.a glwrap.so: LDFLAGS += -s +glwrap.so: LIBS += -ldl glwrap.so: $(OBJECTS_glwrap) glwrap.ld $(CC) -shared -o $@ $^ $(LIBS) $(LDFLAGS) diff --git a/source/commandinterpreter.cpp b/source/commandinterpreter.cpp index 25f004e..fe0c3f1 100644 --- a/source/commandinterpreter.cpp +++ b/source/commandinterpreter.cpp @@ -119,7 +119,7 @@ void CommandInterpreter::cmd_break(const string &args) if(!func) throw InvalidParameterValue("Unknown function"); - gldbg.set_breakpoint(func, BREAK_CALL); + gldbg.set_breakpoint(func, BREAK_CALL, 0); } void CommandInterpreter::cmd_unbreak(const string &args) @@ -128,18 +128,18 @@ void CommandInterpreter::cmd_unbreak(const string &args) if(!func) throw InvalidParameterValue("Unknown function"); - gldbg.clear_breakpoint(func, BREAK_CALL); + gldbg.clear_breakpoint(func, BREAK_CALL, 0); } void CommandInterpreter::cmd_next(const string &) { - gldbg.set_breakpoint(0, BREAK_CALL); + gldbg.set_breakpoint(0, BREAK_CALL, 0); gldbg.get_process().resume(); } void CommandInterpreter::cmd_finish(const string &) { - gldbg.set_breakpoint(0, BREAK_RETURN); + gldbg.set_breakpoint(0, BREAK_RETURN, 0); gldbg.get_process().resume(); } diff --git a/source/gldbg.cpp b/source/gldbg.cpp index 4382737..001742d 100644 --- a/source/gldbg.cpp +++ b/source/gldbg.cpp @@ -5,6 +5,7 @@ Copyright © 2009-2010 Mikko Rasa, Mikkosoft Productions Distributed under the GPL */ +#include #include #include #include @@ -31,7 +32,9 @@ GlDbg::GlDbg(int argc, char **argv): process(vector(argv+1, argv+argc)), buf_offset(0), flushing(false), - got_sigchld(false) + got_sigchld(false), + stop_reason(0), + current_break(0) { FS::Path libdir = FS::get_sys_lib_dir(argv[0], "gldbg"); process.setenv("LD_PRELOAD", (libdir/"glwrap.so").str().c_str()); @@ -43,7 +46,7 @@ GlDbg::GlDbg(int argc, char **argv): GlDbg::~GlDbg() { - for(list::iterator i=tools.begin(); i!=tools.end(); ++i) + for(ToolList::iterator i=tools.begin(); i!=tools.end(); ++i) delete *i; } @@ -78,24 +81,83 @@ void GlDbg::launch() process.setenv("GLWRAP_CTRL_FD", lexical_cast(fds[1])); process.launch(); close(fds[1]); + + breakpoints.clear(); + for(ToolList::iterator i=tools.begin(); i!=tools.end(); ++i) + (*i)->process_started(); } -void GlDbg::set_breakpoint(unsigned short func, char flag) +void GlDbg::send(GlPacket *pkt) { - GlPacket *pkt = packet_begin(FUNC_GLDBREAK); - packet_write_short(pkt, func); - packet_write_char(pkt, flag); - packet_write_char(pkt, 0); packet_send(pkt, sock_fd); } -void GlDbg::clear_breakpoint(unsigned short func, char flag) +void GlDbg::hold() { - GlPacket *pkt = packet_begin(FUNC_GLDBREAK); - packet_write_short(pkt, func); - packet_write_char(pkt, 0); - packet_write_char(pkt, flag); - packet_send(pkt, sock_fd); + GlPacket *pkt = packet_begin(FUNC_GLDHOLD); + send(pkt); +} + +void GlDbg::set_breakpoint(unsigned short func, unsigned char flag, Tool *owner) +{ + Breakpoint *bp = (func ? get_breakpoint(func, flag) : 0); + if(bp) + bp->add_owner(owner); + else + { + if(func) + { + breakpoints.push_back(Breakpoint(func, flag)); + breakpoints.back().add_owner(owner); + } + + GlPacket *pkt = packet_begin(FUNC_GLDBREAK); + packet_write_short(pkt, func); + packet_write_char(pkt, flag); + packet_write_char(pkt, 0); + send(pkt); + } +} + +void GlDbg::clear_breakpoint(unsigned short func, unsigned char flag, Tool *owner) +{ + Breakpoint *bp = get_breakpoint(func, flag); + if(bp) + { + bp->remove_owner(owner); + if(bp->owners.empty()) + { + if(current_break==bp) + current_break = 0; + + // XXX Inefficient. Should get_breakpoint() return an iterator? + for(BreakList::iterator i=breakpoints.begin(); i!=breakpoints.end(); ++i) + if(i->function==func && i->flag==flag) + { + breakpoints.erase(i); + break; + } + + GlPacket *pkt = packet_begin(FUNC_GLDBREAK); + packet_write_short(pkt, func); + packet_write_char(pkt, 0); + packet_write_char(pkt, flag); + send(pkt); + } + } +} + +void GlDbg::resume_from_break(Tool *tool) +{ + if(!current_break) + return; + + ToolList::iterator i = find(break_holders.begin(), break_holders.end(), tool); + if(i!=break_holders.end()) + break_holders.erase(i); + + if(break_holders.empty()) + process.resume(); } void GlDbg::quit(bool force) @@ -110,18 +172,9 @@ void GlDbg::tick() if(got_sigchld) { 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 stopped by signal %d\n", ret&0xFF); + stop_reason = process.check(); + if((stop_reason>>8)==3) flushing = true; - } } Process::State pstate = process.get_state(); @@ -129,6 +182,20 @@ void GlDbg::tick() read_stream(); else { + if(stop_reason) + { + if(stop_reason==0x100) + IO::print("Target process exited normally\n"); + else if((stop_reason>>8)==1) + IO::print("Target process exited with status %d\n", stop_reason&0xFF); + else if((stop_reason>>8)==2) + IO::print("Target process terminated with signal %d\n", stop_reason&0xFF); + else if((stop_reason>>8)==3) + IO::print("Target process stopped by signal %d\n", stop_reason&0xFF); + + stop_reason = 0; + } + char *line = readline("gldbg> "); if(line) { @@ -171,10 +238,22 @@ void GlDbg::read_stream() if(func==FUNC_GLDBREAK) { packet_read_short(pkt, (short *)&func); - IO::print("Breakpoint: %s\n", get_function_name(func)); + unsigned char flag; + packet_read_char(pkt, (char *)&flag); + + current_break = get_breakpoint(func, flag); + bool announce = !current_break; + if(current_break) + { + break_holders = current_break->owners; + announce = current_break->has_owner(0); + } + + if(announce) + IO::print("Breakpoint: %s\n", get_function_name(func)); } - for(list::iterator i=tools.begin(); i!=tools.end(); ++i) + for(ToolList::iterator i=tools.begin(); i!=tools.end(); ++i) (*i)->decode(data, len); buf_offset += len; } @@ -186,7 +265,27 @@ void GlDbg::read_stream() } } else if(flushing) + { flushing = false; + + if(stop_reason) + { + for(ToolList::iterator i=tools.begin(); i!=tools.end(); ++i) + (*i)->process_stopped(stop_reason); + + if(process.get_state()==Process::RUNNING) + current_break = 0; + } + } +} + +GlDbg::Breakpoint *GlDbg::get_breakpoint(unsigned short func, unsigned char flag) +{ + for(BreakList::iterator i=breakpoints.begin(); i!=breakpoints.end(); ++i) + if(i->function==func && i->flag==flag) + return &*i; + + return 0; } void GlDbg::sighandler(int sig) @@ -194,3 +293,29 @@ void GlDbg::sighandler(int sig) if(sig==SIGCHLD) got_sigchld = true; } + + +GlDbg::Breakpoint::Breakpoint(unsigned short f, unsigned char l): + function(f), + flag(l) +{ } + +void GlDbg::Breakpoint::add_owner(Tool *t) +{ + ToolList::iterator i = find(owners.begin(), owners.end(), t); + if(i==owners.end()) + owners.push_back(t); +} + +bool GlDbg::Breakpoint::has_owner(Tool *t) const +{ + ToolList::const_iterator i = find(owners.begin(), owners.end(), t); + return i!=owners.end(); +} + +void GlDbg::Breakpoint::remove_owner(Tool *t) +{ + ToolList::iterator i = find(owners.begin(), owners.end(), t); + if(i!=owners.end()) + owners.erase(i); +} diff --git a/source/gldbg.h b/source/gldbg.h index da5664e..99f0863 100644 --- a/source/gldbg.h +++ b/source/gldbg.h @@ -13,6 +13,7 @@ Distributed under the GPL #include #include #include "commandinterpreter.h" +#include "packet.h" #include "process.h" class Tool; @@ -20,14 +21,35 @@ class Tool; class GlDbg: public Msp::Application { private: + typedef std::list ToolList; + + struct Breakpoint + { + unsigned short function; + unsigned char flag; + ToolList owners; + + Breakpoint(unsigned short, unsigned char); + + void add_owner(Tool *); + bool has_owner(Tool *) const; + void remove_owner(Tool *); + }; + + typedef std::list BreakList; + CommandInterpreter cmd_interp; Process process; int sock_fd; std::string buffer; unsigned buf_offset; bool flushing; - std::list tools; + ToolList tools; bool got_sigchld; + int stop_reason; + BreakList breakpoints; + const Breakpoint *current_break; + ToolList break_holders; static RegApp reg; @@ -39,13 +61,17 @@ public: CommandInterpreter &get_command_interpreter() { return cmd_interp; } Process &get_process() { return process; } void launch(); - void set_breakpoint(unsigned short, char); - void clear_breakpoint(unsigned short, char); + void send(GlPacket *); + void hold(); + void set_breakpoint(unsigned short, unsigned char, Tool *); + void clear_breakpoint(unsigned short, unsigned char, Tool *); + void resume_from_break(Tool *); void quit(bool); private: void tick(); void check_child(); void read_stream(); + Breakpoint *get_breakpoint(unsigned short, unsigned char); virtual void sighandler(int); }; diff --git a/source/gldecoder.c b/source/gldecoder.c index 81b1a43..22b6285 100644 --- a/source/gldecoder.c +++ b/source/gldecoder.c @@ -74,9 +74,11 @@ static void decode_gldError(GlDecoder *dec, GlPacket *pkt) static void decode_gldBreak(GlDecoder *dec, GlPacket *pkt) { unsigned short func; + unsigned char flag; packet_read_short(pkt, (short *)&func); + packet_read_char(pkt, (char *)&flag); if(dec->gldBreak) - dec->gldBreak(dec->user_data, func); + dec->gldBreak(dec->user_data, func, flag); else if(dec->unhandled) dec->unhandled(dec->user_data, FUNC_GLDBREAK); } diff --git a/source/gldecoder.struct.t b/source/gldecoder.struct.t index cc146cc..ac0e098 100644 --- a/source/gldecoder.struct.t +++ b/source/gldecoder.struct.t @@ -10,6 +10,6 @@ for p in params: w(', %s', p.ctype) wl(');') : void (*gldError)(void *, GLenum); -: void (*gldBreak)(void *, unsigned short); +: void (*gldBreak)(void *, unsigned short, unsigned char); : void (*unhandled)(void *, unsigned short); :} GlDecoder; diff --git a/source/glwrap.c b/source/glwrap.c index c70b308..c121e22 100644 --- a/source/glwrap.c +++ b/source/glwrap.c @@ -171,15 +171,22 @@ static void receive(void) void tracepoint(unsigned short func, int flag) { + int breakpoint; + receive(); - if((breakpoints[func]|break_any)&flag) + breakpoint = (breakpoints[func]|break_any)&flag; + if(breakpoint || hold) { GlPacket *pkt; - pkt = packet_begin(FUNC_GLDBREAK); - packet_write_short(pkt, func); - packet_send(pkt, get_out_fd()); + if(breakpoint) + { + pkt = packet_begin(FUNC_GLDBREAK); + packet_write_short(pkt, func); + packet_write_char(pkt, flag); + packet_send(pkt, get_out_fd()); + } break_any = 0; diff --git a/source/tool.h b/source/tool.h index 0d234d2..29f9ca8 100644 --- a/source/tool.h +++ b/source/tool.h @@ -31,6 +31,8 @@ public: virtual ~Tool() { } virtual void decode(const char *, unsigned) = 0; + virtual void process_started() { } + virtual void process_stopped(int) { } static std::list &get_factories(); };