From ea3d851aa52e999b1c5a5fa52c97ff5019756c0e Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 19 Nov 2010 13:59:40 +0000 Subject: [PATCH] Enable bidirectional communication between gldbg and glwrap.so Breakpoint framework and commands --- Makefile | 4 +- flavors/gl/source/glwrap_funcs.c | 1 + flavors/gles2/source/glwrap_funcs.c | 1 + source/breakpoint.h | 17 ++++++ source/commandinterpreter.cpp | 45 ++++++++++++++ source/commandinterpreter.h | 4 ++ source/functions.c | 29 +++++++++ source/functions.enum.t | 7 ++- source/functions.h | 13 ++++- source/functions.table.t | 6 ++ source/gldbg.cpp | 40 +++++++++++-- source/gldbg.h | 2 + source/gldecoder.c | 3 + source/glwrap.c | 91 +++++++++++++++++++++++++++++ source/glwrap.funcs.t | 3 +- source/glwrap.h | 2 + source/packet.c | 60 +++++++++++++++---- source/packet.h | 19 ++++-- 18 files changed, 320 insertions(+), 27 deletions(-) create mode 100644 source/breakpoint.h create mode 100644 source/functions.c create mode 100644 source/functions.table.t diff --git a/Makefile b/Makefile index 3679ee7..6313e0f 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,8 @@ SOURCES_libgldbg := source/gldecoder.c \ source/enums.c \ source/arraysize.c \ source/tmpalloc.c \ - source/packet.c + source/packet.c \ + source/functions.c SOURCES_glwrap := source/glwrap.c \ source/glwrap_funcs.c \ source/arraysize.c \ @@ -37,6 +38,7 @@ SOURCES_inspector := source/inspector.cpp \ source/texturestate.cpp \ source/bufferstate.cpp TEMPLATES := source/functions.enum.t \ + source/functions.table.t \ source/gldecoder.funcs.t \ source/gldecoder.struct.t \ source/glprint.funcs.t \ diff --git a/flavors/gl/source/glwrap_funcs.c b/flavors/gl/source/glwrap_funcs.c index 38621f3..8928ef5 100644 --- a/flavors/gl/source/glwrap_funcs.c +++ b/flavors/gl/source/glwrap_funcs.c @@ -7,6 +7,7 @@ Distributed under the GPL #include #include "arraysize.h" +#include "breakpoint.h" #include "functions.h" #include "glwrap.h" #include "opengl.h" diff --git a/flavors/gles2/source/glwrap_funcs.c b/flavors/gles2/source/glwrap_funcs.c index e4f457a..01314f2 100644 --- a/flavors/gles2/source/glwrap_funcs.c +++ b/flavors/gles2/source/glwrap_funcs.c @@ -7,6 +7,7 @@ Distributed under the GPL #include #include "arraysize.h" +#include "breakpoint.h" #include "functions.h" #include "glwrap.h" #include "opengl.h" diff --git a/source/breakpoint.h b/source/breakpoint.h new file mode 100644 index 0000000..d02559e --- /dev/null +++ b/source/breakpoint.h @@ -0,0 +1,17 @@ +/* $Id$ + +This file is part of gldbg +Copyright © 2010 Mikko Rasa, Mikkosoft Productions +Distributed under the GPL +*/ + +#ifndef BREAKPOINT_H_ +#define BREAKPOINT_H_ + +enum +{ + BREAK_CALL = 1, + BREAK_RETURN = 2 +}; + +#endif diff --git a/source/commandinterpreter.cpp b/source/commandinterpreter.cpp index 2a28f69..25f004e 100644 --- a/source/commandinterpreter.cpp +++ b/source/commandinterpreter.cpp @@ -11,8 +11,10 @@ Distributed under the GPL #include #include #include +#include "breakpoint.h" #include "commandinterpreter.h" #include "enums.h" +#include "functions.h" #include "gldbg.h" #include "tracer.h" @@ -34,6 +36,19 @@ CommandInterpreter::CommandInterpreter(GlDbg &d): register_command("run", this, &CommandInterpreter::cmd_run) .set_help("Starts the program"); + register_command("break", this, &CommandInterpreter::cmd_break) + .set_help("Sets a breakpoint", + "break FUNC\n" + " Makes program execution stop at FUNC\n"); + register_command("unbreak", this, &CommandInterpreter::cmd_unbreak) + .set_help("Removes a breakpoint", + "unbreak FUNC\n" + " Makes program execution no longer stop at FUNC\n"); + register_command("next", this, &CommandInterpreter::cmd_next) + .set_help("Resumes program execution until the next function call"); + commands["step"] = new CommandAlias(commands["next"]); + register_command("finish", this, &CommandInterpreter::cmd_finish) + .set_help("Resumes program execution until the next function return"); register_command("continue", this, &CommandInterpreter::cmd_continue) .set_help("Resumes program execution"); register_command("kill", this, &CommandInterpreter::cmd_kill) @@ -98,6 +113,36 @@ void CommandInterpreter::cmd_run(const string &) gldbg.launch(); } +void CommandInterpreter::cmd_break(const string &args) +{ + unsigned short func = get_function(args.c_str()); + if(!func) + throw InvalidParameterValue("Unknown function"); + + gldbg.set_breakpoint(func, BREAK_CALL); +} + +void CommandInterpreter::cmd_unbreak(const string &args) +{ + unsigned short func = get_function(args.c_str()); + if(!func) + throw InvalidParameterValue("Unknown function"); + + gldbg.clear_breakpoint(func, BREAK_CALL); +} + +void CommandInterpreter::cmd_next(const string &) +{ + gldbg.set_breakpoint(0, BREAK_CALL); + gldbg.get_process().resume(); +} + +void CommandInterpreter::cmd_finish(const string &) +{ + gldbg.set_breakpoint(0, BREAK_RETURN); + gldbg.get_process().resume(); +} + void CommandInterpreter::cmd_continue(const string &) { IO::print("Continuing.\n"); diff --git a/source/commandinterpreter.h b/source/commandinterpreter.h index cc6246e..d39b8b1 100644 --- a/source/commandinterpreter.h +++ b/source/commandinterpreter.h @@ -81,6 +81,10 @@ public: private: void cmd_help(const std::string &); void cmd_run(const std::string &); + void cmd_break(const std::string &); + void cmd_unbreak(const std::string &); + void cmd_next(const std::string &); + void cmd_finish(const std::string &); void cmd_continue(const std::string &); void cmd_signal(const std::string &); void cmd_kill(const std::string &); diff --git a/source/functions.c b/source/functions.c new file mode 100644 index 0000000..f516fdc --- /dev/null +++ b/source/functions.c @@ -0,0 +1,29 @@ +/* $Id$ + +This file is part of gldbg +Copyright © 2010 Mikko Rasa, Mikkosoft Productions +Distributed under the GPL +*/ + +#include +#include "functions.h" + +#include "gensrc/functions.table" + +const char *get_function_name(unsigned short func) +{ + if(func #include #include +#include "functions.h" #include "gldbg.h" #include "gldecoder.h" +#include "packet.h" #include "tool.h" using namespace std; @@ -73,10 +75,29 @@ void GlDbg::launch() fcntl(sock_fd, F_SETFD, flags|FD_CLOEXEC); process.setenv("GLWRAP_FD", lexical_cast(fds[1])); + process.setenv("GLWRAP_CTRL_FD", lexical_cast(fds[1])); process.launch(); close(fds[1]); } - + +void GlDbg::set_breakpoint(unsigned short func, char flag) +{ + 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) +{ + 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); +} + void GlDbg::quit(bool force) { if(!force && process.get_state()!=Process::INACTIVE) @@ -141,12 +162,21 @@ void GlDbg::read_stream() { const char *data = buffer.data()+buf_offset; unsigned len = buffer.size()-buf_offset; - int size = gldecoder_decode(0, data, len); - if(size<0) + GlPacket *pkt = packet_receive_str(data, &len); + if(!pkt) break; + + unsigned short func; + packet_read_short(pkt, (short *)&func); + if(func==FUNC_GLDBREAK) + { + packet_read_short(pkt, (short *)&func); + IO::print("Breakpoint: %s\n", get_function_name(func)); + } + for(list::iterator i=tools.begin(); i!=tools.end(); ++i) - (*i)->decode(data, size); - buf_offset += size; + (*i)->decode(data, len); + buf_offset += len; } if(buf_offset>8192) { diff --git a/source/gldbg.h b/source/gldbg.h index e539982..da5664e 100644 --- a/source/gldbg.h +++ b/source/gldbg.h @@ -39,6 +39,8 @@ 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 quit(bool); private: void tick(); diff --git a/source/gldecoder.c b/source/gldecoder.c index 999accc..f5540c0 100644 --- a/source/gldecoder.c +++ b/source/gldecoder.c @@ -59,6 +59,9 @@ int gldecoder_decode(GlDecoder *dec, const char *data, unsigned len) return len; } +typedef const void *pointer; +typedef const char *string; + #include "gensrc/gldecoder.funcs" static void decode_gldError(GlDecoder *dec, GlPacket *pkt) diff --git a/source/glwrap.c b/source/glwrap.c index 10bfc77..c70b308 100644 --- a/source/glwrap.c +++ b/source/glwrap.c @@ -11,6 +11,14 @@ Distributed under the GPL #include #include #include +#include +#include "breakpoint.h" +#include "functions.h" +#include "packet.h" + +static unsigned char breakpoints[N_FUNCS] = { }; +static char break_any = 0; +static char hold = 0; static const char *get_lib_names(void) { @@ -102,3 +110,86 @@ int get_out_fd(void) return fd; } + +int get_in_fd(void) +{ + static int fd = -1; + + if(fd<0) + { + const char *var = getenv("GLWRAP_CTRL_FD"); + if(var) + fd = strtol(var, NULL, 0); + else + fd = 0; + } + + return fd; +} + +static void receive_gldBreak(GlPacket *pkt) +{ + unsigned short func; + unsigned char flags_set; + unsigned char flags_clr; + + packet_read_short(pkt, (short *)&func); + packet_read_char(pkt, (char *)&flags_set); + packet_read_char(pkt, (char *)&flags_clr); + + if(func) + { + breakpoints[func] &= ~flags_clr; + breakpoints[func] |= flags_set; + } + else + break_any = flags_set; +} + +static void receive_gldHold(GlPacket *pkt __attribute__((unused))) +{ + hold = 1; +} + +static void receive(void) +{ + GlPacket *pkt; + + while((pkt = packet_receive(get_in_fd()))) + { + unsigned short func; + + packet_read_short(pkt, (short *)&func); + switch(func) + { + case FUNC_GLDBREAK: receive_gldBreak(pkt); break; + case FUNC_GLDHOLD: receive_gldHold(pkt); break; + default:; + } + } +} + +void tracepoint(unsigned short func, int flag) +{ + receive(); + + if((breakpoints[func]|break_any)&flag) + { + GlPacket *pkt; + + pkt = packet_begin(FUNC_GLDBREAK); + packet_write_short(pkt, func); + packet_send(pkt, get_out_fd()); + + break_any = 0; + + while(1) + { + hold = 0; + raise(SIGTRAP); + receive(); + if(!hold) + break; + } + } +} diff --git a/source/glwrap.funcs.t b/source/glwrap.funcs.t index bcee771..f1527ba 100644 --- a/source/glwrap.funcs.t +++ b/source/glwrap.funcs.t @@ -13,6 +13,7 @@ if ret.ctype!='void': wl(' %s ret;', ret.ctype) wl(' if(!orig)') wl(' orig = glsym("%s");', func.name) +wl(' tracepoint(FUNC_%s, BREAK_CALL);', func.name.upper()) wl(' pkt = packet_begin(FUNC_%s);', func.name.upper()) head_sent = False for p in params: @@ -42,7 +43,7 @@ if not head_sent: wl(' orig(%s);', ", ".join([p.name for p in params])) if not func.name.startswith("glX"): wl(' check_error();') -#wl(' receive_packet();') +wl(' tracepoint(FUNC_%s, BREAK_RETURN);', func.name.upper()) if ret.ctype!='void': wl(' return ret;') wl('}') diff --git a/source/glwrap.h b/source/glwrap.h index f8422a5..437cd7c 100644 --- a/source/glwrap.h +++ b/source/glwrap.h @@ -10,5 +10,7 @@ Distributed under the GPL void *glsym(const char *); int get_out_fd(void); +int get_in_fd(void); +void tracepoint(unsigned short, int); #endif diff --git a/source/packet.c b/source/packet.c index 465f118..e0b687a 100644 --- a/source/packet.c +++ b/source/packet.c @@ -8,6 +8,7 @@ Distributed under the GPL #include #include #include +#include #include "packet.h" #include "tmpalloc.h" @@ -38,11 +39,11 @@ struct GlPacket }; // XXX Should make this stuff truly re-entrant -static char *out_buffer = 0; -static struct iovec *iovecs = 0; +static char *out_buffer = NULL; +static struct iovec *iovecs = NULL; static GlPacket packet; -/*static char *in_buffer = 0; -static unsigned in_length;*/ +static char *in_buffer = NULL; +static unsigned in_length; static void next_vec(GlPacket *pkt) { @@ -270,6 +271,43 @@ GlPacket *packet_receive_str(const char *data, unsigned *len) return pkt; } +GlPacket *packet_receive(int fd) +{ + int ret; + fd_set fds; + struct timeval tv = { 0, 0 }; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + ret = select(fd+1, &fds, NULL, NULL, &tv); + if(ret>0) + { + if(!in_buffer) + in_buffer = (char *)malloc(1024); + + ret = read(fd, in_buffer+in_length, 1024-in_length); + if(ret>0) + { + GlPacket *pkt; + unsigned pkt_length; + + in_length += ret; + + pkt_length = in_length; + pkt = packet_receive_str(in_buffer, &pkt_length); + if(pkt) + { + in_length -= pkt_length; + memmove(in_buffer, in_buffer+pkt_length, in_length); + } + + return pkt; + } + } + + return NULL; +} + static void next_chunk(GlPacket *pkt) { GlInPacket *in = &pkt->in; @@ -353,12 +391,12 @@ void packet_read_double(GlPacket *pkt, double *v) read_raw(pkt, (char *)v, sizeof(double), 1); } -void packet_read_pointer(GlPacket *pkt, pointer *v) +void packet_read_pointer(GlPacket *pkt, const void **v) { - read_raw(pkt, (char *)v, sizeof(pointer), 1); + read_raw(pkt, (char *)v, sizeof(const void *), 1); } -void packet_read_data(GlPacket *pkt, pointer *v) +void packet_read_data(GlPacket *pkt, const void **v) { GlInPacket *in = &pkt->in; int vlen; @@ -373,17 +411,17 @@ void packet_read_data(GlPacket *pkt, pointer *v) in->length -= vlen; } -void packet_read_string(GlPacket *pkt, string *v) +void packet_read_string(GlPacket *pkt, const char **v) { - packet_read_data(pkt, (pointer *)v); + packet_read_data(pkt, (const void **)v); } -void packet_read_string_array(GlPacket *pkt, string **v) +void packet_read_string_array(GlPacket *pkt, const char ***v) { int count; int i; packet_read_int(pkt, &count); - *v = (string *)tmpalloc(count*sizeof(string)); + *v = (const char **)tmpalloc(count*sizeof(const char *)); for(i=0; i