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 /* !!! 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 . + + 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) */ +