]> git.tdb.fi Git - gldbg.git/commitdiff
Enable bidirectional communication between gldbg and glwrap.so
authorMikko Rasa <tdb@tdb.fi>
Fri, 19 Nov 2010 13:59:40 +0000 (13:59 +0000)
committerMikko Rasa <tdb@tdb.fi>
Fri, 19 Nov 2010 13:59:40 +0000 (13:59 +0000)
Breakpoint framework and commands

18 files changed:
Makefile
flavors/gl/source/glwrap_funcs.c
flavors/gles2/source/glwrap_funcs.c
source/breakpoint.h [new file with mode: 0644]
source/commandinterpreter.cpp
source/commandinterpreter.h
source/functions.c [new file with mode: 0644]
source/functions.enum.t
source/functions.h
source/functions.table.t [new file with mode: 0644]
source/gldbg.cpp
source/gldbg.h
source/gldecoder.c
source/glwrap.c
source/glwrap.funcs.t
source/glwrap.h
source/packet.c
source/packet.h

index 3679ee7955bac9a976f952ef35928bd2b8f2a646..6313e0fb8477387beb171fcb9461b274473d722a 100644 (file)
--- 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 \
index 38621f3b15d42f71e1b60322ce14db75eaff1b0c..8928ef50db1006b8000981c67fb5bba5e5acb035 100644 (file)
@@ -7,6 +7,7 @@ Distributed under the GPL
 
 #include <dlfcn.h>
 #include "arraysize.h"
+#include "breakpoint.h"
 #include "functions.h"
 #include "glwrap.h"
 #include "opengl.h"
index e4f457abe6a5c7586832c660ca9a0bd9477cc4ec..01314f2295fb7299e498cbc491fa52605bc2ceef 100644 (file)
@@ -7,6 +7,7 @@ Distributed under the GPL
 
 #include <dlfcn.h>
 #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 (file)
index 0000000..d02559e
--- /dev/null
@@ -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
index 2a28f69acd6e06a2dc8c523ef2e58a388a62124d..25f004ef32a639497437eaf5709c0b87c64465d5 100644 (file)
@@ -11,8 +11,10 @@ Distributed under the GPL
 #include <msp/io/print.h>
 #include <msp/strings/lexicalcast.h>
 #include <msp/strings/utils.h>
+#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");
index cc6246e927390465301983e03cd290662a8d37e3..d39b8b13c0559e7b8d424e797630f5f6372cbf5f 100644 (file)
@@ -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 (file)
index 0000000..f516fdc
--- /dev/null
@@ -0,0 +1,29 @@
+/* $Id$
+
+This file is part of gldbg
+Copyright © 2010  Mikko Rasa, Mikkosoft Productions
+Distributed under the GPL
+*/
+
+#include <string.h>
+#include "functions.h"
+
+#include "gensrc/functions.table"
+
+const char *get_function_name(unsigned short func)
+{
+       if(func<N_FUNCS)
+               return func_names[func];
+
+       return NULL;
+}
+
+unsigned short get_function(const char *name)
+{
+       unsigned i;
+       for(i=1; i<N_FUNCS; ++i)
+               if(!strcmp(func_names[i], name))
+                       return i;
+
+       return 0;
+}
index ad1bc2de7c525c6a618f9d1c0696f7b1b0574713..c1c0db7a927e9779ec7a30b4b245e8f096a6fd63 100644 (file)
@@ -1,7 +1,10 @@
 # $Id$
-:enum Function
+:enum
 :{
 :      FUNC_NONE,
 wl('   FUNC_%s,', func.name.upper())
-:      FUNC_GLDERROR = 0x8000
+:      N_FUNCS,
+:      FUNC_GLDERROR = 0x8000,
+:      FUNC_GLDBREAK,
+:      FUNC_GLDHOLD
 :};
index caa99e9217f4ded977e16b696fb431a8530c1348..f39c0680ebf5a57cc39742065c8c79aef2c23ed2 100644 (file)
@@ -1,13 +1,24 @@
 /* $Id$
 
 This file is part of gldbg
-Copyright © 2009  Mikko Rasa, Mikkosoft Productions
+Copyright © 2009-2010  Mikko Rasa, Mikkosoft Productions
 Distributed under the GPL
 */
 
 #ifndef FUNCTIONS_H_
 #define FUNCTIONS_H_
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "gensrc/functions.enum"
 
+const char *get_function_name(unsigned short);
+unsigned short get_function(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/source/functions.table.t b/source/functions.table.t
new file mode 100644 (file)
index 0000000..7ffd16f
--- /dev/null
@@ -0,0 +1,6 @@
+# $Id$
+:static const char *func_names[N_FUNCS] =
+:{
+:      NULL,
+wl('   "%s",', func.name)
+:};
index 7990fabae61f6f9ed4b1daef344b5715ded4004f..43827378f4faed462e35efe2be4b3a2ca2dfffcb 100644 (file)
@@ -15,8 +15,10 @@ Distributed under the GPL
 #include <msp/fs/dir.h>
 #include <msp/io/print.h>
 #include <msp/strings/lexicalcast.h>
+#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<Tool *>::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)
                        {
index e53998251e3821bef667526e5346de0717741a22..da5664eddf749102f4a996bdab12e14f35983fdc 100644 (file)
@@ -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();
index 999acccc9cec140d141f5db97f878af136282cdf..f5540c09077930b0a1875031610df71008642dbb 100644 (file)
@@ -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)
index 10bfc77fcb12cd56f21149444593f8df57de8d52..c70b308384b339888dc4ab4527fc7a86df4fa4dc 100644 (file)
@@ -11,6 +11,14 @@ Distributed under the GPL
 #include <errno.h>
 #include <dlfcn.h>
 #include <fcntl.h>
+#include <signal.h>
+#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;
+               }
+       }
+}
index bcee77166ec5053ad5238f25b60dd1e4d0f71075..f1527ba25dee59998992fe6cc2c888c1ac030377 100644 (file)
@@ -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('}')
index f8422a53b21bf4bfb942ede7049be52c810f971d..437cd7c6a9a53b1d6be2e0670a28fd5ce915ef04 100644 (file)
@@ -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
index 465f11868ccdb1197577273b804f13b1e7b1da61..e0b687ac7c54846c2a9dd9d7710d15f5a9650d1c 100644 (file)
@@ -8,6 +8,7 @@ Distributed under the GPL
 #include <stdlib.h>
 #include <string.h>
 #include <sys/uio.h>
+#include <unistd.h>
 #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<count; ++i)
                packet_read_string(pkt, *v+i);
 }
index deacca0bf1f1e8bb85111821055549785fddacef..135e2c54429383c23d0d3c223ca8c5f089b2a24b 100644 (file)
@@ -8,6 +8,10 @@ Distributed under the GPL
 #ifndef PACKET_H_
 #define PACKET_H_
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct GlPacket;
 typedef struct GlPacket GlPacket;
 
@@ -30,6 +34,7 @@ void packet_write_string(GlPacket *, const char *);
 void packet_write_string_array(GlPacket *, const char **, unsigned);
 
 GlPacket *packet_receive_str(const char *, unsigned *);
+GlPacket *packet_receive(int);
 
 void packet_read_char(GlPacket *, char *);
 void packet_read_short(GlPacket *, short *);
@@ -38,11 +43,13 @@ void packet_read_long(GlPacket *, long *);
 void packet_read_long_long(GlPacket *, long long *);
 void packet_read_float(GlPacket *, float *);
 void packet_read_double(GlPacket *, double *);
-typedef const void *pointer;
-void packet_read_pointer(GlPacket *, pointer *);
-void packet_read_data(GlPacket *, pointer *);
-typedef const char *string;
-void packet_read_string(GlPacket *, string *);
-void packet_read_string_array(GlPacket *, string **);
+void packet_read_pointer(GlPacket *, const void **);
+void packet_read_data(GlPacket *, const void **);
+void packet_read_string(GlPacket *, const char **);
+void packet_read_string_array(GlPacket *, const char ***);
+
+#ifdef __cplusplus
+}
+#endif
 
 #endif