diff options
author | Stu Grossman <grossman@cygnus> | 1994-07-28 22:07:02 +0000 |
---|---|---|
committer | Stu Grossman <grossman@cygnus> | 1994-07-28 22:07:02 +0000 |
commit | 754e5da26e5fb9374d6768188944fbca8d49d37c (patch) | |
tree | b875074ed1ccedc6d761f8dab2eb4b47091bc0f4 /gdb/gdbtk.c | |
parent | b98612f1fd9f751389044d28cfa5e66fbf2f1a7f (diff) | |
download | gdb-754e5da26e5fb9374d6768188944fbca8d49d37c.zip gdb-754e5da26e5fb9374d6768188944fbca8d49d37c.tar.gz gdb-754e5da26e5fb9374d6768188944fbca8d49d37c.tar.bz2 |
* Makefile.in (INSTALLED_LIBS, CLIBS, DEPFILES): Add support for
--enable-xxx configure option by adding ENABLE_{CLIBS DEPFILES}
where appropriate.
* General hackery to support alternate user-interface.
* breakpoint.c (mention, delete_breakpoint, enable_breakpoint,
disable_breakpoint): Call hooks for alternate user-interface.
* defs.h: Add declarations for alternate user-interface hooks.
* main.c (main): Add --nw (and --nowindows) options to disable
the GUI.
* (near call to command_loop): Call command_loop_hook if set.
* (fputs_unfiltered): Call fputs_unfiltered_hook if set.
* stack.c: Call print_frame_info_listing_hook if set.
* top.c (gdb_init): Initialize targets.c and utils.c prior to
other files to make sure that calls to error and warning will
work. Call init_ui_hook after everything else.
* utils.c (query): Call query_hook if set.
* (gdb_flush): Call flush_hook if set.
* Change _initialize_utils to initialize_utils cuz we don't use
automatic initialization of utils.c anymore.
* Support for TK GUI.
* Makefile.in: Add rule for gdbtk.o.
* configure.in: Add support for --enable-gdbtk.
* gdbtk.c: New file. Contains support routines for TK interface.
* gdbtk.tcl: New file. Implements GUI policy.
* remote.c: Get rid of #ifdef DONT_USE_REMOTE. It's no longer
necessary.
Diffstat (limited to 'gdb/gdbtk.c')
-rw-r--r-- | gdb/gdbtk.c | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/gdb/gdbtk.c b/gdb/gdbtk.c new file mode 100644 index 0000000..4746f2a --- /dev/null +++ b/gdb/gdbtk.c @@ -0,0 +1,424 @@ +/* TK interface routines. + Copyright 1994 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 2 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, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "symtab.h" +#include "inferior.h" +#include "command.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "target.h" +#include <sys/types.h> +#include <sys/time.h> +#include <sys/param.h> +#include <varargs.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/filio.h> +#include <setjmp.h> +#include <signal.h> +#include <sys/errno.h> +#include <termios.h> +#include <string.h> +#include <tcl.h> +#include <tk.h> + +/* Non-zero means that we're doing the gdbtk interface. */ +int gdbtk = 0; + +/* Non-zero means we are reloading breakpoints, etc from the + Gdbtk kernel, and we should suppress various messages */ +static int gdbtk_reloading = 0; + +/* Handle for TCL interpreter */ +static Tcl_Interp *interp = NULL; + +/* Handle for TK main window */ +static Tk_Window mainWindow = NULL; + +static void +null_routine(arg) + int arg; +{ +} + + +/* This routine redirects the output of fputs_unfiltered so that + the user can see what's going on in his debugger window. */ + +static void +gdbtk_fputs (ptr) + const char *ptr; +{ + Tcl_VarEval (interp, "gdbtk_tcl_fputs ", "{", ptr, "}", NULL); +} + +static void +gdbtk_flush (stream) + FILE *stream; +{ + Tcl_VarEval (interp, "gdbtk_tcl_flush", NULL); +} + +static int +gdbtk_query (args) + va_list args; +{ + char *query; + char buf[200]; + long val; + + query = va_arg (args, char *); + + vsprintf(buf, query, args); + Tcl_VarEval (interp, "gdbtk_tcl_query ", "{", buf, "}", NULL); + + val = atol (interp->result); + return val; +} + +static char * +full_filename(symtab) + struct symtab *symtab; +{ + int pathlen; + char *filename; + + if (!symtab) + return NULL; + + if (symtab->fullname) + return savestring(symtab->fullname, strlen(symtab->fullname)); + + if (symtab->filename[0] == '/') + return savestring(symtab->filename, strlen(symtab->filename)); + + if (symtab->dirname) + pathlen = strlen(symtab->dirname); + else + pathlen = 0; + if (symtab->filename) + pathlen += strlen(symtab->filename); + + filename = xmalloc(pathlen+1); + + if (symtab->dirname) + strcpy(filename, symtab->dirname); + else + *filename = '\000'; + if (symtab->filename) + strcat(filename, symtab->filename); + + return filename; +} + +static void +breakpoint_notify(b, action) + struct breakpoint *b; + const char *action; +{ + struct symbol *sym; + char bpnum[50], line[50]; + struct symtab_and_line sal; + char *filename; + int v; + + if (b->type != bp_breakpoint) + return; + + sal = find_pc_line (b->address, 0); + + filename = full_filename (sal.symtab); + + sprintf (bpnum, "%d", b->number); + sprintf (line, "%d", sal.line); + + v = Tcl_VarEval (interp, + "gdbtk_tcl_breakpoint ", + action, + " ", bpnum, + " ", filename, + " ", line, + NULL); + + if (v != TCL_OK) + { + gdbtk_fputs (interp->result); + gdbtk_fputs ("\n"); + } + + if (filename) + free (filename); +} + +static void +gdbtk_create_breakpoint(b) + struct breakpoint *b; +{ + breakpoint_notify(b, "create"); +} + +static void +gdbtk_delete_breakpoint(b) + struct breakpoint *b; +{ + breakpoint_notify(b, "delete"); +} + +static void +gdbtk_enable_breakpoint(b) + struct breakpoint *b; +{ + breakpoint_notify(b, "enable"); +} + +static void +gdbtk_disable_breakpoint(b) + struct breakpoint *b; +{ + breakpoint_notify(b, "disable"); +} + +/* This implements the TCL command `gdb_loc', which returns a list consisting + of the source and line number associated with the current pc. */ + +static int +gdb_loc (clientData, interp, argc, argv) + ClientData clientData; + Tcl_Interp *interp; + int argc; + char *argv[]; +{ + char *filename; + char buf[100]; + struct symtab_and_line sal; + char *funcname; + + if (argc == 1) + { + struct frame_info *frame; + struct symbol *func; + CORE_ADDR pc; + + frame = get_frame_info (selected_frame); + pc = frame ? frame->pc : stop_pc; + func = find_pc_function (pc); + funcname = func ? SYMBOL_NAME (func) : ""; + sal = find_pc_line (pc, 0); + } + else if (argc == 2) + { + struct cleanup *old_chain; + struct symtabs_and_lines sals; + + sals = decode_line_spec (argv[1], 1); + + if (sals.nelts != 1) + { + Tcl_SetResult (interp, "Ambiguous line spec", TCL_STATIC); + free (sals.sals); + return TCL_ERROR; + } + + sal = sals.sals[0]; + free (sals.sals); + funcname = "*"; + } + else + { + Tcl_SetResult (interp, "wrong # args", TCL_STATIC); + return TCL_ERROR; + } + + filename = full_filename (sal.symtab); + + sprintf (buf, "%d", sal.line); + + if (sal.symtab) + Tcl_AppendElement (interp, sal.symtab->filename); + else + Tcl_AppendElement (interp, ""); + Tcl_AppendElement (interp, funcname); + Tcl_AppendElement (interp, filename); + Tcl_AppendElement (interp, buf); /* line number */ + + if (filename) + free(filename); + + return TCL_OK; +} + +static int +gdb_cmd_stub (cmd) + char *cmd; +{ + execute_command (cmd, 1); + + return 1; /* Indicate success */ +} + +/* This implements the TCL command `gdb_cmd', which sends it's argument into + the GDB command scanner. */ + +static int +gdb_cmd (clientData, interp, argc, argv) + ClientData clientData; + Tcl_Interp *interp; + int argc; + char *argv[]; +{ + int val; + struct cleanup *old_chain; + + if (argc != 2) + { + Tcl_SetResult (interp, "wrong # args", TCL_STATIC); + return TCL_ERROR; + } + + old_chain = make_cleanup (null_routine, 0); + + val = catch_errors (gdb_cmd_stub, argv[1], "", RETURN_MASK_ERROR); + + bpstat_do_actions (&stop_bpstat); + do_cleanups (old_chain); + + /* We could base the return value on val, but that would require most users + to use catch. Since GDB errors are already being handled elsewhere, I + see no reason to pass them up to the caller. */ + + return TCL_OK; +} + +static int +gdb_listfiles (clientData, interp, argc, argv) + ClientData clientData; + Tcl_Interp *interp; + int argc; + char *argv[]; +{ + int val; + struct objfile *objfile; + struct partial_symtab *psymtab; + + ALL_PSYMTABS (objfile, psymtab) + Tcl_AppendElement (interp, psymtab->filename); + + return TCL_OK; +} + +static void +tk_command (cmd, from_tty) + char *cmd; + int from_tty; +{ + Tcl_VarEval (interp, cmd, NULL); + + gdbtk_fputs (interp->result); + gdbtk_fputs ("\n"); +} + +static void +cleanup_init (ignored) + int ignored; +{ + if (mainWindow != NULL) + Tk_DestroyWindow (mainWindow); + mainWindow = NULL; + + if (interp != NULL) + Tcl_DeleteInterp (interp); + interp = NULL; +} + +static void +gdbtk_init () +{ + struct cleanup *old_chain; + char *gdbtk_filename; + + old_chain = make_cleanup (cleanup_init, 0); + + /* First init tcl and tk. */ + + interp = Tcl_CreateInterp (); + + if (!interp) + error ("Tcl_CreateInterp failed"); + + mainWindow = Tk_CreateMainWindow (interp, NULL, "gdb", "Gdb"); + + if (!mainWindow) + return; /* DISPLAY probably not set */ + + if (Tcl_Init(interp) != TCL_OK) + error ("Tcl_Init failed: %s", interp->result); + + if (Tk_Init(interp) != TCL_OK) + error ("Tk_Init failed: %s", interp->result); + + Tcl_CreateCommand (interp, "gdb_cmd", gdb_cmd, NULL, NULL); + Tcl_CreateCommand (interp, "gdb_loc", gdb_loc, NULL, NULL); + Tcl_CreateCommand (interp, "gdb_listfiles", gdb_listfiles, NULL, NULL); + + gdbtk_filename = getenv ("GDBTK_FILENAME"); + if (gdbtk_filename) + { + if (Tcl_EvalFile (interp, gdbtk_filename) != TCL_OK) + error ("Failure reading %s: %s", gdbtk_filename, interp->result); + } + else + { + if (Tcl_EvalFile (interp, "gdbtk.tcl") != TCL_OK) + { + Tcl_ResetResult (interp); + if (Tcl_EvalFile (interp, GDBTK_FILENAME) != TCL_OK) + error ("Failure reading %s: %s", GDBTK_FILENAME, interp->result); + } + } + + command_loop_hook = Tk_MainLoop; + fputs_unfiltered_hook = gdbtk_fputs; + print_frame_info_listing_hook = null_routine; + query_hook = gdbtk_query; + flush_hook = gdbtk_flush; + create_breakpoint_hook = gdbtk_create_breakpoint; + delete_breakpoint_hook = gdbtk_delete_breakpoint; + enable_breakpoint_hook = gdbtk_enable_breakpoint; + disable_breakpoint_hook = gdbtk_disable_breakpoint; + + discard_cleanups (old_chain); + + add_com ("tk", class_obscure, tk_command, + "Send a command directly into tk."); +} + +/* Come here during initialze_all_files () */ + +void +_initialize_gdbtk () +{ + if (no_windows) + return; + + /* Tell the rest of the world that Gdbtk is now set up. */ + + init_ui_hook = gdbtk_init; +} |