diff -rup src/gdb/Makefile.in dst/gdb/Makefile.in --- src/gdb/Makefile.in 2012-05-14 16:36:05.849377050 +0530 +++ dst/gdb/Makefile.in 2012-05-14 16:36:30.629371941 +0530 @@ -718,6 +718,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr objfiles.c osabi.c observer.c osdata.c \ opencl-lang.c \ p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \ + plugin.c \ proc-service.list progspace.c \ prologue-value.c psymtab.c \ regcache.c reggroups.c remote.c remote-fileio.c reverse.c \ @@ -875,6 +876,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $ event-loop.o event-top.o inf-loop.o completer.o \ gdbarch.o arch-utils.o gdbtypes.o osabi.o copying.o \ memattr.o mem-break.o target.o parse.o language.o buildsym.o \ + plugin.o \ findcmd.o \ std-regs.o \ signals.o \ diff -rup src/gdb/plugin.c dst/gdb/plugin.c --- src/gdb/plugin.c 2012-05-14 16:35:32.821376922 +0530 +++ dst/gdb/plugin.c 2012-05-14 16:21:24.005377051 +0530 @@ -0,0 +1,327 @@ +/* Everything about plugin command, for GDB. + + Copyright (C) 2012 Free Software Foundation, Inc. + + 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 . */ + +#include "defs.h" +#include "gdb_string.h" +#include "gdbcmd.h" +#include "gdb-dlfcn.h" +#include "readline/tilde.h" +#include "gdb/plugin.h" + +static void (*null_func) (char *, int) = (void (*) (char *, int)) 0; +static char *null_str = (char *) 0; + +void _initialize_plugin (void); + +static struct cmd_list_element *plugin_cmdlist; + +/* Structure to encapsulate all entities associated with plugin. */ + +struct plugin +{ + /* Null terminated string containing filename with relative or absolute path + of a plugin which is essentially a dynamic library file. */ + char *filename; + + /* Opeque plugin handle. */ + void *handle; + + /* List of commands introduced by plugin. */ + struct plugin_cmd *cmdlist; + + /* Flag to indicate whether user defined plugin destructor routine needs to + be called. This flag is set when user defined constructor routine for the + plugin gets called. */ + int init_done; + + /* Points to previous plugin in this list. */ + struct plugin *prev; + + /* Points to next plugin in this list. */ + struct plugin *next; +}; + +/* List of active plugins. */ + +static struct plugin *pluginlist; + +/* Delete a plugin from query list. */ + +static void +delete_plugin_from_linkedlist (struct plugin *plugin) +{ + if (plugin->next) + plugin->next->prev = plugin->prev; + if (plugin->prev) + plugin->prev->next = plugin->next; + else + pluginlist = plugin->next; +} + +/* Given a plugin filename FILENAME, search for a plugin in query list. */ + +static struct plugin * +do_lookup_plugin_into_linkedlist (char *filename) +{ + struct plugin *iter = pluginlist; + + while (iter) + { + if (strcmp (iter->filename, filename) == 0) + break; + iter = iter->next; + } + return iter; +} + +/* Insert a plugin in query list. */ + +static void +insert_plugin_into_linkedlist (struct plugin *plugin) +{ + if (pluginlist) + { + pluginlist->prev = plugin; + plugin->next = pluginlist; + } + pluginlist = plugin; +} + +/* Destroy plugin referenced by ARG. */ + +static void +destroy_plugin (void *arg) +{ + struct plugin *plugin = (struct plugin *) arg; + plugin_func_type *fini_func; + + if (!plugin) + error (_("Plugin not found.")); + + if (plugin->filename) + xfree (plugin->filename); + + if (plugin->init_done) + { + struct plugin_cmd *iter = plugin->cmdlist; + + while (iter) + { + /* Delete user supplied commands in plugin to GDB command list. */ + add_cmd (iter->name, no_class, null_func, null_str, &cmdlist); + iter = iter->next; + } + } + + fini_func = gdb_dlsym (plugin->handle, plugin_destructor_fn_sym); + + if (!fini_func) + error (_("Plugin destructor routine %s not found."), + plugin_destructor_fn_sym); + + if (fini_func (&plugin->cmdlist) < 0) + error (_("Failed to delete plugin.")); + + if (plugin->handle) + gdb_dlclose (plugin->handle); + + xfree (plugin); +} + +/* Create plugin referenced by ARG. */ + +static void * +create_plugin (char *arg) +{ + struct plugin *plugin; + plugin_func_type *init_func; + struct plugin_cmd *iter; + struct cleanup *old_chain; + + plugin = XCNEW (struct plugin); + old_chain = make_cleanup (destroy_plugin, plugin); + + plugin->filename = tilde_expand (arg); + plugin->handle = gdb_dlopen (plugin->filename); + + init_func = gdb_dlsym (plugin->handle, plugin_constructor_fn_sym); + + if (!init_func) + error (_("Plugin constructor routine %s not found."), + plugin_constructor_fn_sym); + + if (init_func (&plugin->cmdlist) < 0) + error (_("Failed to add plugin.")); + + iter = plugin->cmdlist; + + while (iter) + { + /* Add user supplied commands in plugin to GDB command list. */ + add_cmd (iter->name, no_class, iter->func, iter->doc, &cmdlist); + iter = iter->next; + } + + plugin->init_done = 1; + + discard_cleanups (old_chain); + + return plugin; +} + +/* The 'plugin del' command delete a plugin. */ + +static void +plugin_del_command (char *arg, int from_tty) +{ + char *filename; + struct plugin *plugin; + struct cleanup *old_chain; + + if (!is_dl_available ()) + error (_("Plugin not supported.")); + + if (arg == NULL) + error (_("Plugin not specified.")); + + filename = tilde_expand (arg); + old_chain = make_cleanup (xfree, filename); + + /* Shouldn't delete already deleted plugin. */ + if (!(plugin = do_lookup_plugin_into_linkedlist (filename))) + error (_("Plugin not found.")); + + do_cleanups (old_chain); + + delete_plugin_from_linkedlist (plugin); + + destroy_plugin (plugin); +} + +/* The 'plugin add' command add a plugin. */ + +static void +plugin_add_command (char *arg, int from_tty) +{ + char *filename; + struct plugin *plugin; + struct cleanup *old_chain; + + if (!is_dl_available ()) + error (_("Plugin not supported.")); + + if (arg == NULL) + error (_("Plugin not specified.")); + + filename = tilde_expand (arg); + old_chain = make_cleanup (xfree, filename); + + /* Shouldn't add already added plugin. */ + if (do_lookup_plugin_into_linkedlist (filename)) + error (_("Plugin already added.")); + + do_cleanups (old_chain); + + plugin = create_plugin (arg); + old_chain = make_cleanup (destroy_plugin, plugin); + + insert_plugin_into_linkedlist (plugin); + + discard_cleanups (old_chain); +} + +/* Execute the plugin command with argument ARG and FROM_TTY. */ + +static void +plugin_command (char *arg, int from_tty) +{ + if (!is_dl_available ()) + error (_("Plugin not supported.")); + + if (!arg) + { + struct plugin *iter = pluginlist; + + if (!iter) + printf_filtered (_("No GDB-plugin is added.\n")); + else + { + printf_filtered (_("Following GDB-plugin(s) are added:\n\n")); + + while (iter) + { + printf_filtered (_("\t%s\n"), iter->filename); + iter = iter->next; + } + } + } + else + { + char *filename; + struct plugin *plugin; + struct cleanup *old_chain; + + filename = tilde_expand (arg); + old_chain = make_cleanup (xfree, filename); + + if (!(plugin = do_lookup_plugin_into_linkedlist (filename))) + error (_("Plugin not found.")); + + do_cleanups (old_chain); + + if (plugin) + { + struct plugin_cmd *iter = plugin->cmdlist; + + while (iter) + { + printf_filtered (_("\t%s\n"), iter->name); + iter = iter->next; + } + } + } +} + +/* Module initialization. */ + +void +_initialize_plugin (void) +{ + add_prefix_cmd ("plugin", no_class, plugin_command, _("\ +Provide an interface to plug-in a custom GDB-extension or plugin.\n\ +A custom GDB-extension is a dynamic library file with native OS supported\n\ +file-format.\n\n\ +Given a plugin as argument, list down command(s) introduced by the plugin.\n\ +With no subcommand, existing plugins are displayed."), + &plugin_cmdlist, "plugin ", 1, &cmdlist); + + add_cmd ("add", no_class, plugin_add_command, _("\ +Add a GDB plugin.\n\ +Argument is a dynamic library filename with relative or absolute path."), + &plugin_cmdlist); + + add_com_alias ("add-plugin", "plugin add", no_class, 0); + + add_cmd ("del", no_class, plugin_del_command, _("\ +Delete a GDB plugin.\n\ +Argument is a dynamic library filename with relative or absolute path."), + &plugin_cmdlist); + + add_com_alias ("del-plugin", "plugin del", no_class, 0); +} diff -rup src/gdb/testsuite/gdb.base/plugin.c dst/gdb/testsuite/gdb.base/plugin.c --- src/gdb/testsuite/gdb.base/plugin.c 2012-05-14 16:37:14.037376909 +0530 +++ dst/gdb/testsuite/gdb.base/plugin.c 2012-05-14 16:21:55.985376773 +0530 @@ -0,0 +1,50 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012 Free Software Foundation, Inc. + + 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 . */ + +#define SUCCESS 0 +#define FAILURE -1 + +#include +#include +#include + +#include "plugin.h" + +static void +func1_command (char *arg, int tty) +{ + printf ("Invoked func1.\n"); +} + +int +gdb_plugin_constructor (struct plugin_cmd **cmds) +{ + (*cmds) = malloc (sizeof (struct plugin_cmd)); + (*cmds)->name = strdup ("func1"); + (*cmds)->func = func1_command; + (*cmds)->doc = strdup ("Help for func1."); + (*cmds)->next = NULL; + return SUCCESS; +} + +int +gdb_plugin_destructor (struct plugin_cmd **cmds) +{ + free ((*cmds)->name); + free ((*cmds)->doc); + free ((*cmds)); +} diff -rup src/gdb/testsuite/gdb.base/plugin.exp dst/gdb/testsuite/gdb.base/plugin.exp --- src/gdb/testsuite/gdb.base/plugin.exp 2012-05-14 16:37:05.837377490 +0530 +++ dst/gdb/testsuite/gdb.base/plugin.exp 2012-05-14 16:21:29.165376866 +0530 @@ -0,0 +1,51 @@ +# Copyright 2012 Free Software Foundation, Inc. + +# 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 . + +# +# test gdb plugin commands +# + +set test "plugin" +set libsrc ${test}.c +set library ${objdir}/${subdir}/${test}.so + +file delete $library + +if {[get_compiler_info not-used]} { + warning "Could not get compiler info." + untested plugin.exp + return 1 +} + +if { [gdb_compile_shlib ${srcdir}/${subdir}/${libsrc} ${library} {-fPIC}] != "" } { + untested "Could not compile shared library." + return -1 +} + +gdb_exit +gdb_start + +gdb_test "plugin" "No GDB-plugin is added." +gdb_test "plugin add" "Plugin not specified." +gdb_test "plugin del" "Plugin not specified." +gdb_test_no_output "plugin add $library" +gdb_test "plugin add $library" "Plugin already added." +gdb_test "plugin" "Following GDB-plugin(s) are added:\n\n\t$library" +gdb_test "plugin $library" "func1" +gdb_test "func1" "Invoked func1." +gdb_test "help func1" "Help for func1." +gdb_test_no_output "plugin del $library" +gdb_test "plugin del $library" "Plugin not found." +gdb_test "plugin" "No GDB-plugin is added." diff -rup src/gdb/testsuite/gdb.base/plugin.h dst/gdb/testsuite/gdb.base/plugin.h --- src/gdb/testsuite/gdb.base/plugin.h 2012-05-14 16:37:16.593376908 +0530 +++ dst/gdb/testsuite/gdb.base/plugin.h 2012-05-14 16:21:56.217376878 +0530 @@ -0,0 +1,63 @@ +/* This file defines the interface between the simulator and gdb. + + Copyright (C) 2012 Free Software Foundation, Inc. + + 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 . */ + +#if !defined (PLUGIN_H) +#define PLUGIN_H 1 + +/* Plugin constructor routine define by the plugin developer. This must add all + newly introduced GDB-commands defined in the plugin to a list exposed by + GDB. Each element of this list will contain the name of the command, the + pointer to a function which executes on invocation of this command, a + document string which get displayed when help is asked for this command and + a pointer pointing to the next element in the list. */ + +static const char *plugin_constructor_fn_sym = "gdb_plugin_constructor"; + +/* Plugin destructor routine define by the plugin developer. This must cleanup + the command list created by the plugin constructor routine. */ + +static const char *plugin_destructor_fn_sym = "gdb_plugin_destructor"; + +/* Structure to encapsulate all entities associated with plugin command. */ + +struct plugin_cmd +{ + /* Name of the command. */ + char *name; + + /* Pointer referencing to the function that is executed on invocation of this + command. This must be reset to NULL on deletion of the plugin. */ + void (*func) (char *args, int from_tty); + + /* Documentation of this command (or help topic). + First line is brief documentation; remaining lines form, with it, the full + documentation. First line should end with a period. Entire string should + also end with a period, not a newline. */ + char *doc; + + /* Points to next command in this list. */ + struct plugin_cmd *next; +}; + +/* Prototype of plugin constructor and destructor routines. + It must return 0 on success and -1 on failure. */ + +typedef int (plugin_func_type) (struct plugin_cmd *); + +#endif diff -rup src/include/gdb/plugin.h dst/include/gdb/plugin.h --- src/include/gdb/plugin.h 2012-05-14 16:35:23.349376973 +0530 +++ dst/include/gdb/plugin.h 2012-05-14 16:22:25.721376989 +0530 @@ -0,0 +1,63 @@ +/* This file defines the interface between the simulator and gdb. + + Copyright (C) 2012 Free Software Foundation, Inc. + + 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 . */ + +#if !defined (PLUGIN_H) +#define PLUGIN_H 1 + +/* Plugin constructor routine define by the plugin developer. This must add all + newly introduced GDB-commands defined in the plugin to a list exposed by + GDB. Each element of this list will contain the name of the command, the + pointer to a function which executes on invocation of this command, a + document string which get displayed when help is asked for this command and + a pointer pointing to the next element in the list. */ + +static const char *plugin_constructor_fn_sym = "gdb_plugin_constructor"; + +/* Plugin destructor routine define by the plugin developer. This must cleanup + the command list created by the plugin constructor routine. */ + +static const char *plugin_destructor_fn_sym = "gdb_plugin_destructor"; + +/* Structure to encapsulate all entities associated with plugin command. */ + +struct plugin_cmd +{ + /* Name of the command. */ + char *name; + + /* Pointer referencing to the function that is executed on invocation of this + command. This must be reset to NULL on deletion of the plugin. */ + void (*func) (char *args, int from_tty); + + /* Documentation of this command (or help topic). + First line is brief documentation; remaining lines form, with it, the full + documentation. First line should end with a period. Entire string should + also end with a period, not a newline. */ + char *doc; + + /* Points to next command in this list. */ + struct plugin_cmd *next; +}; + +/* Prototype of plugin constructor and destructor routines. + It must return 0 on success and -1 on failure. */ + +typedef int (plugin_func_type) (struct plugin_cmd **); + +#endif