This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Data plugins for gdb...



I spent a few hours hacking something out as a proof of concept; I'd appreciate some opinions from those that know better.


Before long, any development project generates complex data structures. Most of the time, gdb does a good job displaying even pretty complicated ones, and gives lots of options for customizing the output, such as turning off printing of static class members.

When you need more customization, there is some rudimentary scripting support, but it tends to be slow and there are lots of cases where it doesn't work so well.

I noticed one of my clients has a custom plugin for Visual Studio's debugger to view their string class (everyone rolls their own string class!), and I thought having that for GDB would be nice, too.

So I've implemented a plugin system for gdb that allows people to override the "print" command for specific data types.

The gist is this: you write some code to view the contents of some object and put it in a shared library. Then you punch "dataplugin SHAREDLIBRARYNAME.so" into gdb's console. GDB will look for a specific entry point in the library and call it, which lets the library register itself for certain data types. Then when the user attempts to view such a data type, control is handed to the library. GDB supplies a handful of functions that the library can call to get the job done: access to warning(), target_read_memory(), etc.

Here is an example of what I mean, in Hello World form:

You have a class Hello...

   class Hello
   {
   public:
       char *name;
       int times;
   };


...and a program that uses it...



int main(void) { int i; Hello hello; hello.name = (char *) "bob"; hello.times = 4;

       for (i = 0; i < hello.times; i++)
           printf("Hello, %s!\n", hello.name);

       return 0;
   }


If we were to set a breakpoint on the for loop and type "p hello", we'd get this:


$1 = {name = 0x4006b8 "bob", times = 4}

But if you were to build this data plugin and load it ...

http://hg.icculus.org/icculus/gdb-dataplugins/raw-file/1eb478462c3f/dataplugin_tests/hello/viewhello.cpp

...then "p hello" would report:

This Hello says heya to bob, 4 times!


Okay, that is not an upgrade. But it's a Hello World thing! Here are some more practical examples.


1) std::string (or insert your favorite string class here).

std::string x("Hello, world!");

"p x" in gdb will give you something like this:

$1 = {static npos = 18446744073709551615,
_M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x602028 "Hello, world!"}}


We are fortunate that the actual string data is visible here. I've seen string classes where it isn't.

Also, you could try this with a std::wstring...

std::wstring z(L"This is a wide string.");

$2 = {static npos = 18446744073709551615,
_M_dataplus = {<std::allocator<wchar_t>> = {<__gnu_cxx::new_allocator<wchar_t>> = {<No data fields>}, <No data fields>}, _M_p = 0x602088}}


...uhoh.


But using a data plugin for these two types...


http://hg.icculus.org/icculus/gdb-dataplugins/raw-file/1eb478462c3f/dataplugin_tests/std_str/viewstdstr.cpp

(gdb) p x
(std::string) "Hello, world!"
(gdb) p z
(std::wstring) L"This is a wide string."



2) wchar_t strings

As we just saw with the std::wstring, wide character strings can be problematic in gdb...there's a FIXME in the source about it. But gcc introduces an extra complication with -fshort-wchar ... now the size of wchar_t may vary.

Here's a plugin that handles both forms, by querying gdb for the sizeof (wchar_t) when loaded:

http://hg.icculus.org/icculus/gdb-dataplugins/raw-file/1eb478462c3f/dataplugin_tests/wchar_t/viewwchar.c


Breakpoint 1, main () at wchar.c:5 5 wchar_t *x = L"Hello, world!"; (gdb) p x $1 = (wchar_t *) 0x400558 (gdb) dataplugin ./viewwchar.so Loading data plugin "./viewwchar.so" ... Added data plugin viewer for 'wchar_t *' Data plugin added 1 viewers. (gdb) p x (wchar_t *) L"Hello, world!"


3) Linked lists.


Let's say you had a simple linked list for storing people and office numbers...

class LinkedList
{
public:
    const char *first;
    const char *last;
    int office_number;
    LinkedList *next;
};


...and some code to populate it...


    // this inserts a new item at the start of a global "list"
    AddToList("Ryan", "Gordon", 4923);
    AddToList("Greg", "Read", 227);
    AddToList("Linus", "Torvalds", 732);
    AddToList("Bill", "Gates", 666);  // I kid! I kid!
    AddToList("Richard", "Stallman", 1135);
    AddToList("Andrew", "Tannenbaum", 9986);

...and wanted to view this in gdb...

(gdb) p *list
$2 = {first = 0x601270 "Andrew", last = 0x601290 "Tannenbaum",
office_number = 9986, next = 0x6011d0}
(gdb) p *list->next
$3 = {first = 0x601200 "Richard", last = 0x601220 "Stallman",
office_number = 1135, next = 0x601160}
(gdb) p *list->next->next
$4 = {first = 0x601190 "Bill", last = 0x6011b0 "Gates", office_number = 666,
next = 0x6010f0}
(gdb) p *list->next->next->mext
There is no member named mext.


Sooner or later, you get sick of adding on more "->next".

(gdb) dataplugin ./viewlinkedlist.so
Loading data plugin "./viewlinkedlist.so" ...
Added data plugin viewer for 'LinkedList'
Data plugin added 1 viewers.
(gdb) p *list
item (0x601240) { "Andrew", "Tannenbaum", 9986 },
item (0x6011d0) { "Richard", "Stallman", 1135 },
item (0x601160) { "Bill", "Gates", 666 },
item (0x6010f0) { "Linus", "Torvalds", 732 },
item (0x601080) { "Greg", "Read", 227 },
item (0x601010) { "Ryan", "Gordon", 4923 }
(gdb)

http://hg.icculus.org/icculus/gdb-dataplugins/raw-file/1eb478462c3f/dataplugin_tests/linked_list/viewlinkedlist.cpp

It tightens down the output to what we care about, and walks the list for us.

A linked list is trivial enough for an example, but there are plenty of common data structures that could benefit from a data plugin much more. Hash tables come to mind immediately, as do binary trees.


4) Not-human readable data.


There are lots of things that are valid data that will never be comprehensible no matter what you pass to printf(). Images, mp3 data, 3d meshes, a million other things.

Here's a plugin that will handle a "surface," the pixels that make up a bitmapped image, in the SDL multimedia library ( http://libsdl.org/ ).

http://hg.icculus.org/icculus/gdb-dataplugins/file/1eb478462c3f/dataplugin_tests/sdl/viewsdl.c

At runtime, if you try to "print" an SDL_Surface, the plugin will create an X11 window with the current pixel content, so you can see if your data is actually sane. Debugging continues when you close the window. Many many times I've stepped through these in gdb like this...

(gdb) p/x ((unsigned int *) surface->pixels)[0]
$1 = 0x0
(gdb) p/x ((unsigned int *) surface->pixels)[1]
$2 = 0x0
(gdb) p/x ((unsigned int *) surface->pixels)[2]
$3 = 0x0

...and after 499 iterations think the entire bitmap is black, not realizing that it's only the top row having a black border and I'm still 301 pixels from the second row of the image. Having this data plugin would tell me if the whole image is black in under a second.



Now, granted, some of these examples may not follow best practices for gdb, and some of them might be solvable with a little scripting in your ~/.gdbinit file. But these are meant to be simple, general-use examples. I could envision lots of projects maintaining their own plugins that are built with everything else, having the benefit of access to the same data headers as the code they are debugging. Some organizations will use this in-house, and some projects--Gnome, Python, KDE and Mozilla all come to mind--may wrap some common but complex data structures in plugins with the expectation that they will be useful to outside contributors that just want to step through a piece of code without steeping in the particular religion of the project: just load viewgnome.so and some things are easier to digest as an outsider!


I have only tested this on GNU/Linux. It should, in theory, work on anything that has dlopen(). There are a few FIXMEs (such as the dlopen() requirement), there's isn't proper documentation, and the code is not up to quality standards...it's definitely usable and useful now, though. If this is something that could be accepted into gdb, I would welcome comments and guidance on cleaning it up for inclusion in CVS. I'm happy to walk anyone through the finer points of the patch, as well, if anything isn't clear.


Attached is the current patch against the latest CVS.

Thanks,
--ryan.


Index: gdb/printcmd.c
===================================================================
RCS file: /cvs/src/src/gdb/printcmd.c,v
retrieving revision 1.127
diff -u -r1.127 printcmd.c
--- gdb/printcmd.c	6 Jun 2008 20:58:08 -0000	1.127
+++ gdb/printcmd.c	7 Aug 2008 22:56:26 -0000
@@ -47,6 +47,18 @@
 #include "tui/tui.h"		/* For tui_active et.al.   */
 #endif
 
+/* !!! FIXME: needs to look for dlopen() support in the configure script. */
+/* !!! FIXME: (and deal with non-dlopen platforms...?) */
+#define SUPPORT_DATA_PLUGINS 1
+
+#if SUPPORT_DATA_PLUGINS
+#include <dlfcn.h>  /* !!! FIXME: support platforms without dlopen(). */
+#include "gdb-dataplugins.h"
+#define GDB_DATAPLUGIN_ENTRY_STR3(x) #x
+#define GDB_DATAPLUGIN_ENTRY_STR2(x) GDB_DATAPLUGIN_ENTRY_STR3(x)
+#define GDB_DATAPLUGIN_ENTRY_STR GDB_DATAPLUGIN_ENTRY_STR2(GDB_DATAPLUGIN_ENTRY)
+#endif
+
 #if defined(__MINGW32__)
 # define USE_PRINTF_I64 1
 # define PRINTF_HAS_LONG_LONG
@@ -161,6 +173,228 @@
 static void do_one_display (struct display *);
 
 
+
+#if SUPPORT_DATA_PLUGINS
+/* !!! FIXME: need a way to delete the hash at shutdown. just atexit()? */
+static htab_t dataplugin_htab = 0;
+
+static int
+dataplugin_get_size(const char *_exp, unsigned long *size)
+{
+    int retval = -1;
+
+    if (!_exp)
+        warning(_("Data plugin passed a NULL expression to get_size()"));
+    else if (!size)
+        warning(_("Data plugin passed a NULL size pointer to get_size()"));
+    else
+    {
+        char *exp = xstrdup(_exp);  /* so we're not const... */
+        struct expression *expr = parse_expression (exp);
+        struct cleanup *old_chain = make_cleanup (free_current_contents, &expr);
+        struct value *value = evaluate_type (expr);
+        if (value == NULL)
+            warning(_("Data plugin couldn't parse expression '%s'"), exp);
+        else
+        {
+            struct type *type = value_type (value);
+            if (type == NULL)
+                warning(_("Data plugin couldn't find type '%s' for get_size()"), exp);
+            else
+            {
+                *size = TYPE_LENGTH (type);
+                retval = 0;  /* success! */
+            }
+        }
+        do_cleanups (old_chain);
+        xfree(exp);
+    }
+
+    return retval;
+}
+
+static int
+dataplugin_read_memory(const void *src, void *dst, int len)
+{
+    const int rc = target_read_memory ((CORE_ADDR) src, (gdb_byte *)dst, len);
+    if (rc != 0)
+        warning(_("Data plugin failed to read memory from debug process."));
+    return rc;
+}
+
+static void *
+dataplugin_read_string(const void *src, int charlen)
+{
+    char *retval = NULL;
+    int err = 0;
+    target_read_string_multibyte ((CORE_ADDR) src, &retval, 1024 * 128, &err, charlen);
+    if (err != 0)
+    {
+        xfree(retval);
+        retval = NULL;
+        warning(_("Data plugin failed to read string from debug process."));
+    }
+    return retval;
+}
+
+static void *
+dataplugin_alloc_memory(int len)
+{
+    return xcalloc(1, len);
+}
+
+static void *
+dataplugin_realloc_memory(void *ptr, int len)
+{
+    return xrealloc(ptr, len);
+}
+
+static void
+dataplugin_free_memory(void *ptr)
+{
+    xfree(ptr);
+}
+
+typedef struct
+{
+    const char *typestr;
+    GDB_dataplugin_viewfn fn;
+} dataplugin_hash_data;
+
+static hashval_t
+dataplugin_hash (const void *p)
+{
+    const dataplugin_hash_data *data = (dataplugin_hash_data *) p;
+    return htab_hash_string(data->typestr);
+}
+
+static void
+dataplugin_hash_del(void *p)
+{
+    dataplugin_hash_data *data = (dataplugin_hash_data *) p;
+    xfree((void *) data->typestr);
+    xfree(data);
+}
+
+static int
+dataplugin_hash_eq(const void *a, const void *b)
+{
+    const dataplugin_hash_data *data1 = (dataplugin_hash_data *) a;
+    const dataplugin_hash_data *data2 = (dataplugin_hash_data *) b;
+    return streq(data1->typestr, data2->typestr);
+}
+
+static void
+dataplugin_add_viewer(const char *typestr, GDB_dataplugin_viewfn fn)
+{
+    const dataplugin_hash_data lookup = { typestr, NULL };
+    dataplugin_hash_data **slot = NULL;
+
+    if (!dataplugin_htab)
+    {
+        dataplugin_htab = htab_create_alloc (256, dataplugin_hash,
+                                  dataplugin_hash_eq, dataplugin_hash_del,
+                                  xcalloc, xfree);
+    }
+
+    slot = (dataplugin_hash_data **) htab_find_slot (dataplugin_htab, &lookup, INSERT);
+    if (*slot != NULL)
+        warning(_("Tried to readd data plugin viewer for '%s'"), typestr);
+    else
+    {
+        *slot = xmalloc(sizeof (dataplugin_hash_data));
+        (*slot)->typestr = xstrdup(typestr);
+        (*slot)->fn = fn;
+        printf_filtered(_("Added data plugin viewer for '%s'\n"), typestr);
+    }
+}
+
+static GDB_dataplugin_viewfn
+dataplugin_get_viewer(const char *typestr)
+{
+    const dataplugin_hash_data lookup = { typestr, NULL };
+    dataplugin_hash_data *data = NULL;
+    if ((!dataplugin_htab) || (htab_elements (dataplugin_htab) == 0))
+        return NULL;
+    data = (dataplugin_hash_data *) htab_find (dataplugin_htab, &lookup);
+    return (data) ? data->fn : NULL;
+}
+
+static const GDB_dataplugin_funcs dataplugin_funcs =
+{
+    warning,
+    printf_unfiltered,
+    dataplugin_get_size,
+    dataplugin_read_memory,
+    dataplugin_read_string,
+    dataplugin_alloc_memory,
+    dataplugin_realloc_memory,
+    dataplugin_free_memory,
+};
+
+static const GDB_dataplugin_entry_funcs dataplugin_entry_funcs =
+{
+    warning,
+    dataplugin_get_size,
+    dataplugin_alloc_memory,
+    dataplugin_realloc_memory,
+    dataplugin_free_memory,
+    dataplugin_add_viewer,
+};
+
+
+/* called in response to "dataplugin" command entered by user at console */
+static void
+dataplugin_command (char *arg, int from_tty)
+{
+    /* !!! FIXME: support platforms without dlopen(). */
+    int new_count = 0;
+    const int start_count = dataplugin_htab ? htab_elements (dataplugin_htab) : 0;
+    const char *entryname = GDB_DATAPLUGIN_ENTRY_STR;
+    GDB_dataplugin_entry entry = 0;
+    void *lib = NULL;
+
+    printf_filtered(_("Loading data plugin \"%s\" ...\n"), arg);
+
+    lib = dlopen(arg, RTLD_NOW | RTLD_LOCAL);
+    if (lib == NULL)
+    {
+        warning(_("dlopen(\"%s\") failed: %s"), arg, dlerror());
+        return;
+    }
+
+    entry = (GDB_dataplugin_entry) dlsym(lib, entryname);
+    if (entry == NULL)
+    {
+        warning(_("dlsym(lib, \"%s\") failed: %s"), entryname, dlerror());
+        dlclose(lib);
+        return;
+    }
+
+    entry(&dataplugin_entry_funcs);
+
+    new_count = dataplugin_htab ? htab_elements (dataplugin_htab) : 0;
+    gdb_assert(start_count <= new_count);
+    if (start_count < new_count)
+    {
+        printf_filtered(_("Data plugin added %d viewers.\n"),
+                        new_count - start_count);
+    }
+    else
+    {
+        warning(_("Data plugin added no viewers."));
+        dlclose(lib);
+    }
+
+    /*
+     * !!! FIXME: we're leaking library handles. Maybe store them
+     * !!! FIXME:  in a linked list and close them atexit()?
+     */
+}
+
+#endif
+
+
 /* Decode a format specification.  *STRING_PTR should point to it.
    OFORMAT and OSIZE are used as defaults for the format and size
    if none are given in the format specification.
@@ -857,14 +1091,38 @@
 
   if (exp && *exp)
     {
-      struct type *type;
       expr = parse_expression (exp);
       old_chain = make_cleanup (free_current_contents, &expr);
       cleanup = 1;
       val = evaluate_expression (expr);
+
+      #if SUPPORT_DATA_PLUGINS
+      {
+          long dummy = 0;
+          GDB_dataplugin_viewfn viewfn = 0;
+          struct ui_file *memfile = mem_fileopen ();
+          struct cleanup *memfile_chain = make_cleanup_ui_file_delete (memfile);
+          struct type *type = value_type(evaluate_type (expr));
+          char *typestr = NULL;
+          type_print (type, NULL, memfile, 0);
+          typestr = ui_file_xstrdup (memfile, &dummy);
+          do_cleanups (memfile_chain);
+          viewfn = dataplugin_get_viewer(typestr);
+          xfree(typestr);
+          if (viewfn != NULL)
+          {
+            if (fmt.format)
+                warning(_("using data visualization plugin; formatters are ignored."));
+            viewfn((void *) VALUE_ADDRESS(val), &dataplugin_funcs);
+            do_cleanups (old_chain);
+            inspect_it = 0;
+            return;
+          }
+      }
+      #endif
     }
   else
-    val = access_value_history (0);
+      val = access_value_history (0);
 
   if (voidprint || (val && value_type (val) &&
 		    TYPE_CODE (value_type (val)) != TYPE_CODE_VOID))
@@ -2267,6 +2525,13 @@
 
   current_display_number = -1;
 
+#if SUPPORT_DATA_PLUGINS
+  c = add_com ("dataplugin", class_vars, dataplugin_command, _("\
+Load a data visualization plugin: dataplugin FILENAME\n\
+Load the shared library FILENAME to handle viewing of specific data types."));
+  set_cmd_completer (c, filename_completer);
+#endif
+
   add_info ("address", address_info,
 	    _("Describe where symbol SYM is stored."));
 
Index: gdb/target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.169
diff -u -r1.169 target.c
--- gdb/target.c	9 Jul 2008 22:42:42 -0000	1.169
+++ gdb/target.c	7 Aug 2008 22:56:27 -0000
@@ -918,18 +918,38 @@
 int
 target_read_string (CORE_ADDR memaddr, char **string, int len, int *errnop)
 {
+  return target_read_string_multibyte(memaddr, string, len, errnop, 1);
+}
+
+/* target_read_string_multibyte -- functions just like target_read_string,
+   but you can specify the size of a character. This means you can use it
+   with wchar_t strings, etc, and the end of the string has to be
+   CHARSIZE null bytes in a row. target_read_string just calls this with
+   CHARSIZE set to 1. This returns bytes read, not characters! */
+
+int
+target_read_string_multibyte (CORE_ADDR memaddr, char **string, int len, int *errnop, int charsize)
+{
   int tlen, origlen, offset, i;
-  gdb_byte buf[4];
+  gdb_byte buf[8];
   int errcode = 0;
-  char *buffer;
+  int charbytecount = 0;
+  int nullcount = 0;
+  char *buffer = 0;
   int buffer_allocated;
   char *bufptr;
   unsigned int nbytes_read = 0;
 
+  if ((charsize < 1) || (charsize > sizeof (buf)))
+  {
+    errcode = EIO;
+    goto done;
+  }
+
   gdb_assert (string);
 
   /* Small for testing.  */
-  buffer_allocated = 4;
+  buffer_allocated = 8;
   buffer = xmalloc (buffer_allocated);
   bufptr = buffer;
 
@@ -937,10 +957,10 @@
 
   while (len > 0)
     {
-      tlen = MIN (len, 4 - (memaddr & 3));
-      offset = memaddr & 3;
+      tlen = MIN (len, 8 - (memaddr & 7));
+      offset = memaddr & 7;
 
-      errcode = target_read_memory (memaddr & ~3, buf, sizeof buf);
+      errcode = target_read_memory (memaddr & ~7, buf, sizeof buf);
       if (errcode != 0)
 	{
 	  /* The transfer request might have crossed the boundary to an
@@ -967,8 +987,23 @@
 	  *bufptr++ = buf[i + offset];
 	  if (buf[i + offset] == '\000')
 	    {
-	      nbytes_read += i + 1;
-	      goto done;
+	      nullcount++;
+	      if (nullcount == charsize)
+	        {
+	          nbytes_read += i + 1;
+	          goto done;
+	        }
+	    }
+	  else
+	    {
+	      nullcount = 0;
+	    }
+
+	  charbytecount++;
+	  if (charbytecount == charsize)
+	    {
+	      charbytecount = 0;
+	      nullcount = 0;  /* reset count for new character. */
 	    }
 	}
 
Index: gdb/target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.126
diff -u -r1.126 target.h
--- gdb/target.h	9 Jul 2008 22:42:42 -0000	1.126
+++ gdb/target.h	7 Aug 2008 22:56:27 -0000
@@ -635,6 +635,8 @@
 
 extern DCACHE *target_dcache;
 
+extern int target_read_string_multibyte (CORE_ADDR, char **, int, int *, int);
+
 extern int target_read_string (CORE_ADDR, char **, int, int *);
 
 extern int target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len);
diff -r 44fef237b45c -r 1eb478462c3f src/gdb/gdb-dataplugins.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ gdb/gdb-dataplugins.h	Thu Aug 07 17:30:38 2008 -0400
@@ -0,0 +1,110 @@
+/* Public interfaces for GDB data plugins.
+
+   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Free Software Foundation, Inc.
+
+   Contributed by Ryan C. Gordon.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+   This file has a runtime exception to the GPL: you may use this header
+   in a GDB data plugin that is not licensed under the GPL.
+*/
+
+#if !defined (GDB_DATAPLUGINS_H)
+#define GDB_DATAPLUGINS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GDB_DATAPLUGIN_INTERFACE_VERSION 1
+
+/* callback for outputting data from a data plugin. printf_unfiltered(). */
+typedef void (*GDB_dataplugin_printfn)(const char *fmt, ...);
+
+/* callback for reading memory from debuggee address space to debugger. */
+typedef int (*GDB_dataplugin_readmemfn)(const void *src, void *dst, int len);
+
+/* callback for reading a null-terminated string from debuggee address space to debugger. */
+/* readstrfn(ptr, sizeof (wchar_t)), for example. */
+typedef void *(*GDB_dataplugin_readstrfn)(const void *src, int charsize);
+
+/* callback for allocating memory. */
+typedef void *(*GDB_dataplugin_mallocfn)(int len);
+
+/* callback for reallocating memory. */
+typedef void *(*GDB_dataplugin_reallocfn)(void *ptr, int len);
+
+/* callback for freeing memory allocated by other function pointers. */
+typedef void (*GDB_dataplugin_freefn)(void *ptr);
+
+/* callback for reporting a problem inside a data plugin. warning(). */
+typedef void (*GDB_dataplugin_warning)(const char *, ...);
+
+/* callback for querying a data type's size. */
+typedef int (*GDB_dataplugin_get_size)(const char *, unsigned long *);
+
+typedef struct
+{
+    GDB_dataplugin_warning warning;
+    GDB_dataplugin_printfn print;
+    GDB_dataplugin_get_size getsize;
+    GDB_dataplugin_readmemfn readmem;
+    GDB_dataplugin_readstrfn readstr;
+    GDB_dataplugin_mallocfn allocmem;
+    GDB_dataplugin_reallocfn reallocmem;
+    GDB_dataplugin_freefn freemem;
+} GDB_dataplugin_funcs;
+
+/* function pointer where data plugins do their work. */
+typedef void (*GDB_dataplugin_viewfn)(const void *, const GDB_dataplugin_funcs *);
+
+/* callback for registering a viewer for a specific data type. */
+typedef void (*GDB_dataplugin_register)(const char *, GDB_dataplugin_viewfn);
+
+typedef struct
+{
+    GDB_dataplugin_warning warning;
+    GDB_dataplugin_get_size getsize;
+    GDB_dataplugin_mallocfn allocmem;
+    GDB_dataplugin_reallocfn reallocmem;
+    GDB_dataplugin_freefn freemem;
+    GDB_dataplugin_register register_viewer;
+} GDB_dataplugin_entry_funcs;
+
+/* the entry point into a data plugin shared library. */
+typedef void (*GDB_dataplugin_entry)(const GDB_dataplugin_entry_funcs *);
+
+/* ignore this. Just some macro magic. */
+#define __GDB_DATAPLUGIN_ENTRY3(fn,ver) fn##_##ver
+#define __GDB_DATAPLUGIN_ENTRY2(fn,ver) __GDB_DATAPLUGIN_ENTRY3(fn,ver)
+
+/* name of the function in the data plugin to use for the entry point. */
+#define GDB_DATAPLUGIN_ENTRY __GDB_DATAPLUGIN_ENTRY2( \
+                                            GDB_dataview_plugin_entry, \
+                                            GDB_DATAPLUGIN_INTERFACE_VERSION)
+
+/* just so this is forced to be extern "C" in the plugin itself... */
+void GDB_DATAPLUGIN_ENTRY(const GDB_dataplugin_entry_funcs *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined (GDB_DATAPLUGINS_H) */
+

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]