aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbtk-hooks.c
diff options
context:
space:
mode:
authorJim Ingham <jingham@apple.com>1998-07-01 20:17:31 +0000
committerJim Ingham <jingham@apple.com>1998-07-01 20:17:31 +0000
commitf3b86a30f914d3a74e4f167bd4a97170f21a9776 (patch)
treec3d026f7147ca17b2f561a501611b6c99b0135d7 /gdb/gdbtk-hooks.c
parenta57fc6b9c04a78607b8f929f771f04ef82f82684 (diff)
downloadgdb-f3b86a30f914d3a74e4f167bd4a97170f21a9776.zip
gdb-f3b86a30f914d3a74e4f167bd4a97170f21a9776.tar.gz
gdb-f3b86a30f914d3a74e4f167bd4a97170f21a9776.tar.bz2
Wed Jul 1 13:10:58 1998 Jim Ingham <jingham@cygnus.com>
* Moved gdbtk_hooks.c & gdbtk_cmds.c to gdbtk-hooks.c & gdbtk-cmds.c to comply with the gdb conventions. Changed the configure & makefile to reflect the change...
Diffstat (limited to 'gdb/gdbtk-hooks.c')
-rw-r--r--gdb/gdbtk-hooks.c689
1 files changed, 689 insertions, 0 deletions
diff --git a/gdb/gdbtk-hooks.c b/gdb/gdbtk-hooks.c
new file mode 100644
index 0000000..b76f2ff
--- /dev/null
+++ b/gdb/gdbtk-hooks.c
@@ -0,0 +1,689 @@
+/* Startup code for gdbtk.
+ Copyright 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Stu Grossman <grossman@cygnus.com> of Cygnus Support.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 "gdbcore.h"
+#include "tracepoint.h"
+#include "demangle.h"
+
+#ifdef _WIN32
+#include <winuser.h>
+#endif
+
+#include <sys/stat.h>
+
+#include <tcl.h>
+#include <tk.h>
+#include <itcl.h>
+#include <tix.h>
+#include "guitcl.h"
+#include "gdbtk.h"
+
+#ifdef IDE
+/* start-sanitize-ide */
+#include "event.h"
+#include "idetcl.h"
+#include "ilutk.h"
+/* end-sanitize-ide */
+#endif
+
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <setjmp.h>
+#include "top.h"
+#include <sys/ioctl.h>
+#include "gdb_string.h"
+#include "dis-asm.h"
+#include <stdio.h>
+#include "gdbcmd.h"
+
+#include "annotate.h"
+#include <sys/time.h>
+
+int in_fputs = 0;
+
+int (*ui_load_progress_hook) PARAMS ((char *, unsigned long));
+void (*pre_add_symbol_hook) PARAMS ((char *));
+void (*post_add_symbol_hook) PARAMS ((void));
+
+#ifdef __CYGWIN32__
+extern void (*ui_loop_hook) PARAMS ((int));
+#endif
+static void gdbtk_create_tracepoint PARAMS ((struct tracepoint *));
+static void gdbtk_delete_tracepoint PARAMS ((struct tracepoint *));
+static void gdbtk_modify_tracepoint PARAMS ((struct tracepoint *));
+static void gdbtk_create_breakpoint PARAMS ((struct breakpoint *));
+static void gdbtk_delete_breakpoint PARAMS ((struct breakpoint *));
+static void gdbtk_modify_breakpoint PARAMS ((struct breakpoint *));
+static void tk_command_loop PARAMS ((void));
+static void gdbtk_call_command PARAMS ((struct cmd_list_element *, char *, int));
+static int gdbtk_wait PARAMS ((int, struct target_waitstatus *));
+ void x_event PARAMS ((int));
+static int gdbtk_query PARAMS ((const char *, va_list));
+static void gdbtk_warning PARAMS ((const char *, va_list));
+void gdbtk_ignorable_warning PARAMS ((const char *));
+static char* gdbtk_readline PARAMS ((char *));
+static void
+#ifdef ANSI_PROTOTYPES
+gdbtk_readline_begin (char *format, ...);
+#else
+gdbtk_readline_begin ();
+#endif
+static void gdbtk_readline_end PARAMS ((void));
+static void gdbtk_flush PARAMS ((FILE *));
+static void gdbtk_pre_add_symbol PARAMS ((char *));
+static void gdbtk_print_frame_info PARAMS ((struct symtab *, int, int, int));
+static void gdbtk_post_add_symbol PARAMS ((void));
+static void pc_changed PARAMS ((void));
+static void tracepoint_notify PARAMS ((struct tracepoint *, const char *));
+
+/*
+ * gdbtk_fputs can't be static, because we need to call it in gdbtk.c.
+ * See note there for details.
+ */
+
+void gdbtk_fputs PARAMS ((const char *, FILE *));
+int gdbtk_load_hash PARAMS ((char *, unsigned long));
+static void breakpoint_notify PARAMS ((struct breakpoint *, const char *));
+
+/*
+ * gdbtk_add_hooks - add all the hooks to gdb. This will get called by the
+ * startup code to fill in the hooks needed by core gdb.
+ */
+
+void
+gdbtk_add_hooks(void)
+{
+ command_loop_hook = tk_command_loop;
+ call_command_hook = gdbtk_call_command;
+ readline_begin_hook = gdbtk_readline_begin;
+ readline_hook = gdbtk_readline;
+ readline_end_hook = gdbtk_readline_end;
+
+ print_frame_info_listing_hook = gdbtk_print_frame_info;
+ query_hook = gdbtk_query;
+ warning_hook = gdbtk_warning;
+ flush_hook = gdbtk_flush;
+
+ create_breakpoint_hook = gdbtk_create_breakpoint;
+ delete_breakpoint_hook = gdbtk_delete_breakpoint;
+ modify_breakpoint_hook = gdbtk_modify_breakpoint;
+
+ interactive_hook = gdbtk_interactive;
+ target_wait_hook = gdbtk_wait;
+ ui_load_progress_hook = gdbtk_load_hash;
+#ifdef __CYGWIN32__
+ ui_loop_hook = x_event;
+#endif
+ pre_add_symbol_hook = gdbtk_pre_add_symbol;
+ post_add_symbol_hook = gdbtk_post_add_symbol;
+
+ create_tracepoint_hook = gdbtk_create_tracepoint;
+ delete_tracepoint_hook = gdbtk_delete_tracepoint;
+ modify_tracepoint_hook = gdbtk_modify_tracepoint;
+ pc_changed_hook = pc_changed;
+
+}
+
+/* These control where to put the gdb output which is created by
+ {f}printf_{un}filtered and friends. gdbtk_fputs and gdbtk_flush are the
+ lowest level of these routines and capture all output from the rest of GDB.
+
+ The reason to use the result_ptr rather than the gdbtk_interp's result
+ directly is so that a call_wrapper invoked function can preserve its result
+ across calls into Tcl which might be made in the course of the function's
+ execution.
+
+ * result_ptr->obj_ptr is where to accumulate the result.
+ * GDBTK_TO_RESULT flag means the output goes to the gdbtk_tcl_fputs proc
+ instead of to the result_ptr.
+ * GDBTK_MAKES_LIST flag means add to the result as a list element.
+
+ */
+
+gdbtk_result *result_ptr = NULL;
+
+
+/* This allows you to Tcl_Eval a tcl command which takes
+ a command word, and then a single argument. */
+
+int gdbtk_two_elem_cmd (cmd_name, argv1)
+ char *cmd_name;
+ char * argv1;
+{
+ char *command;
+ int result, flags_ptr, arg_len, cmd_len;
+
+ arg_len = Tcl_ScanElement (argv1, &flags_ptr);
+ cmd_len = strlen (cmd_name);
+ command = malloc(arg_len + cmd_len + 2);
+ strcpy (command, cmd_name);
+ strcat (command, " ");
+
+ Tcl_ConvertElement (argv1, command + cmd_len + 1, flags_ptr);
+
+ result = Tcl_Eval (gdbtk_interp, command);
+ free (command);
+ return result;
+
+}
+
+static void
+gdbtk_flush (stream)
+ FILE *stream;
+{
+#if 0
+ /* Force immediate screen update */
+
+ Tcl_VarEval (gdbtk_interp, "gdbtk_tcl_flush", NULL);
+#endif
+}
+
+/* This handles all the output from gdb. All the gdb printf_xxx functions
+ * eventually end up here. The output is either passed to the result_ptr
+ * where it will go to the result of some gdbtk command, or passed to the
+ * Tcl proc gdbtk_tcl_fputs (where it is usually just dumped to the console
+ * window.
+ *
+ * The cases are:
+ *
+ * 1) result_ptr == NULL - This happens when some output comes from gdb which
+ * is not generated by a command in gdbtk-cmds, usually startup stuff.
+ * In this case we just route the data to gdbtk_tcl_fputs.
+ * 2) The GDBTK_TO_RESULT flag is set - The result is supposed to go to Tcl.
+ * We place the data into the result_ptr, either as a string,
+ * or a list, depending whether the GDBTK_MAKES_LIST bit is set.
+ * 3) The GDBTK_TO_RESULT flag is unset - We route the data to gdbtk_tcl_fputs
+ * UNLESS it was coming to stderr. Then we place it in the result_ptr
+ * anyway, so it can be dealt with.
+ *
+ */
+
+void
+gdbtk_fputs (ptr, stream)
+ const char *ptr;
+ FILE *stream;
+{
+ in_fputs = 1;
+
+ if (result_ptr != NULL)
+ {
+ if (result_ptr->flags & GDBTK_TO_RESULT)
+ {
+ if (result_ptr->flags & GDBTK_MAKES_LIST)
+ Tcl_ListObjAppendElement(NULL, result_ptr->obj_ptr,
+ Tcl_NewStringObj((char *) ptr, -1));
+ else
+ Tcl_AppendToObj (result_ptr->obj_ptr, (char *) ptr, -1);
+ }
+ else if (stream == gdb_stderr)
+ {
+ if (result_ptr->flags & GDBTK_ERROR_STARTED)
+ Tcl_AppendToObj (result_ptr->obj_ptr, (char *) ptr, -1);
+ else
+ {
+ Tcl_SetStringObj (result_ptr->obj_ptr, (char *) ptr, -1);
+ result_ptr->flags |= GDBTK_ERROR_STARTED;
+ }
+ }
+ else
+ {
+ gdbtk_two_elem_cmd ("gdbtk_tcl_fputs", (char *) ptr);
+ if (result_ptr->flags & GDBTK_MAKES_LIST)
+ gdbtk_two_elem_cmd ("gdbtk_tcl_fputs", " ");
+ }
+ }
+ else
+ {
+ gdbtk_two_elem_cmd ("gdbtk_tcl_fputs", (char *) ptr);
+ }
+
+ in_fputs = 0;
+}
+
+/*
+ * This routes all warnings to the Tcl function "gdbtk_tcl_warning".
+ */
+
+static void
+gdbtk_warning (warning, args)
+ const char *warning;
+ va_list args;
+{
+ char buf[200];
+
+ vsprintf (buf, warning, args);
+ gdbtk_two_elem_cmd ("gdbtk_tcl_warning", buf);
+
+}
+
+/*
+ * This routes all ignorable warnings to the Tcl function
+ * "gdbtk_tcl_ignorable_warning".
+ */
+
+void
+gdbtk_ignorable_warning (warning)
+ const char *warning;
+{
+ char buf[200], *merge[2];
+ char *command;
+
+ sprintf (buf, warning);
+ gdbtk_two_elem_cmd ("gdbtk_tcl_ignorable_warning", buf);
+
+}
+
+
+
+static void
+pc_changed()
+{
+ Tcl_Eval (gdbtk_interp, "gdbtk_pc_changed");
+}
+
+
+/* This function is called instead of gdb's internal command loop. This is the
+ last chance to do anything before entering the main Tk event loop.
+ At the end of the command, we enter the main loop. */
+
+static void
+tk_command_loop ()
+{
+ extern GDB_FILE *instream;
+
+ /* We no longer want to use stdin as the command input stream */
+ instream = NULL;
+
+ if (Tcl_Eval (gdbtk_interp, "gdbtk_tcl_preloop") != TCL_OK)
+ {
+ char *msg;
+
+ /* Force errorInfo to be set up propertly. */
+ Tcl_AddErrorInfo (gdbtk_interp, "");
+
+ msg = Tcl_GetVar (gdbtk_interp, "errorInfo", TCL_GLOBAL_ONLY);
+#ifdef _WIN32
+ MessageBox (NULL, msg, NULL, MB_OK | MB_ICONERROR | MB_TASKMODAL);
+#else
+ fputs_unfiltered (msg, gdb_stderr);
+#endif
+ }
+
+#ifdef _WIN32
+ close_bfds ();
+#endif
+
+ Tk_MainLoop ();
+}
+
+/* Come here when there is activity on the X file descriptor. */
+
+void
+x_event (signo)
+ int signo;
+{
+ static int in_x_event = 0;
+ static Tcl_Obj *varname = NULL;
+ if (in_x_event || in_fputs)
+ return;
+
+ in_x_event = 1;
+
+#ifdef __CYGWIN32__
+ if (signo == -2)
+ gdbtk_stop_timer ();
+#endif
+
+ /* Process pending events */
+ while (Tcl_DoOneEvent (TCL_DONT_WAIT|TCL_ALL_EVENTS) != 0)
+ ;
+
+ if (load_in_progress)
+ {
+ int val;
+ if (varname == NULL)
+ {
+ Tcl_Obj *varnamestrobj = Tcl_NewStringObj("download_cancel_ok",-1);
+ varname = Tcl_ObjGetVar2(gdbtk_interp,varnamestrobj,NULL,TCL_GLOBAL_ONLY);
+ }
+ if ((Tcl_GetIntFromObj(gdbtk_interp,varname,&val) == TCL_OK) && val)
+ {
+ quit_flag = 1;
+#ifdef REQUEST_QUIT
+ REQUEST_QUIT;
+#else
+ if (immediate_quit)
+ quit ();
+#endif
+ }
+ }
+ in_x_event = 0;
+}
+
+/* VARARGS */
+static void
+#ifdef ANSI_PROTOTYPES
+gdbtk_readline_begin (char *format, ...)
+#else
+gdbtk_readline_begin (va_alist)
+ va_dcl
+#endif
+{
+ va_list args;
+ char buf[200], *merge[2];
+ char *command;
+
+#ifdef ANSI_PROTOTYPES
+ va_start (args, format);
+#else
+ char *format;
+ va_start (args);
+ format = va_arg (args, char *);
+#endif
+
+ vsprintf (buf, format, args);
+ gdbtk_two_elem_cmd ("gdbtk_tcl_readline_begin", buf);
+
+}
+
+static char *
+gdbtk_readline (prompt)
+ char *prompt;
+{
+ int result;
+
+#ifdef _WIN32
+ close_bfds ();
+#endif
+
+ result = gdbtk_two_elem_cmd ("gdbtk_tcl_readline", prompt);
+
+ if (result == TCL_OK)
+ {
+ return (strdup (gdbtk_interp -> result));
+ }
+ else
+ {
+ gdbtk_fputs (gdbtk_interp -> result, gdb_stdout);
+ gdbtk_fputs ("\n", gdb_stdout);
+ return (NULL);
+ }
+}
+
+static void
+gdbtk_readline_end ()
+{
+ Tcl_Eval (gdbtk_interp, "gdbtk_tcl_readline_end");
+}
+
+static void
+gdbtk_call_command (cmdblk, arg, from_tty)
+ struct cmd_list_element *cmdblk;
+ char *arg;
+ int from_tty;
+{
+ running_now = 0;
+ if (cmdblk->class == class_run || cmdblk->class == class_trace)
+ {
+
+/* HACK! HACK! This is to get the gui to update the tstart/tstop
+ button only incase of tstart/tstop commands issued from the console
+ We don't want to update the src window, so we need to have specific
+ procedures to do tstart and tstop
+ Unfortunately this will not display errors from tstart or tstop in the
+ console window itself, but as dialogs.*/
+
+ if (!strcmp(cmdblk->name, "tstart") && !No_Update)
+ {
+ Tcl_Eval (gdbtk_interp, "gdbtk_tcl_tstart");
+ (*cmdblk->function.cfunc)(arg, from_tty);
+ }
+ else if (!strcmp(cmdblk->name, "tstop") && !No_Update)
+ {
+ Tcl_Eval (gdbtk_interp, "gdbtk_tcl_tstop");
+ (*cmdblk->function.cfunc)(arg, from_tty);
+ }
+/* end of hack */
+ else
+ {
+ running_now = 1;
+ if (!No_Update)
+ Tcl_Eval (gdbtk_interp, "gdbtk_tcl_busy");
+ (*cmdblk->function.cfunc)(arg, from_tty);
+ running_now = 0;
+ if (!No_Update)
+ Tcl_Eval (gdbtk_interp, "gdbtk_tcl_idle");
+ }
+ }
+ else
+ (*cmdblk->function.cfunc)(arg, from_tty);
+}
+
+/* The next three functions use breakpoint_notify to allow the GUI
+ * to handle creating, deleting and modifying breakpoints. These three
+ * functions are put into the appropriate gdb hooks in gdbtk_init.
+ */
+
+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_modify_breakpoint(b)
+ struct breakpoint *b;
+{
+ breakpoint_notify (b, "modify");
+}
+
+/* This is the generic function for handling changes in
+ * a breakpoint. It routes the information to the Tcl
+ * command "gdbtk_tcl_breakpoint" in the form:
+ * gdbtk_tcl_breakpoint action b_number b_address b_line b_file
+ * On error, the error string is written to gdb_stdout.
+ */
+
+static void
+breakpoint_notify(b, action)
+ struct breakpoint *b;
+ const char *action;
+{
+ char buf[256];
+ int v;
+ struct symtab_and_line sal;
+ char *filename;
+
+ if (b->type != bp_breakpoint)
+ return;
+
+ /* We ensure that ACTION contains no special Tcl characters, so we
+ can do this. */
+ sal = find_pc_line (b->address, 0);
+ filename = symtab_to_filename (sal.symtab);
+ if (filename == NULL)
+ filename = "";
+
+ sprintf (buf, "gdbtk_tcl_breakpoint %s %d 0x%lx %d {%s}", action, b->number,
+ (long)b->address, b->line_number, filename);
+
+ v = Tcl_Eval (gdbtk_interp, buf);
+
+ if (v != TCL_OK)
+ {
+ gdbtk_fputs (Tcl_GetStringResult (gdbtk_interp), gdb_stdout);
+ gdbtk_fputs ("\n", gdb_stdout);
+ }
+}
+
+int
+gdbtk_load_hash (section, num)
+ char *section;
+ unsigned long num;
+{
+ char buf[128];
+ sprintf (buf, "download_hash %s %ld", section, num);
+ Tcl_Eval (gdbtk_interp, buf);
+ return atoi (gdbtk_interp->result);
+}
+
+
+/* This hook is called whenever we are ready to load a symbol file so that
+ the UI can notify the user... */
+static void
+gdbtk_pre_add_symbol (name)
+ char *name;
+{
+
+ gdbtk_two_elem_cmd("gdbtk_tcl_pre_add_symbol", name);
+
+}
+
+/* This hook is called whenever we finish loading a symbol file. */
+static void
+gdbtk_post_add_symbol ()
+{
+ Tcl_Eval (gdbtk_interp, "gdbtk_tcl_post_add_symbol");
+}
+
+/* This hook function is called whenever we want to wait for the
+ target. */
+
+static int
+gdbtk_wait (pid, ourstatus)
+ int pid;
+ struct target_waitstatus *ourstatus;
+{
+ gdbtk_start_timer ();
+ pid = target_wait (pid, ourstatus);
+ gdbtk_stop_timer ();
+ return pid;
+}
+
+/*
+ * This handles all queries from gdb.
+ * The first argument is a printf style format statement, the rest are its
+ * arguments. The resultant formatted string is passed to the Tcl function
+ * "gdbtk_tcl_query".
+ * It returns the users response to the query, as well as putting the value
+ * in the result field of the Tcl interpreter.
+ */
+
+static int
+gdbtk_query (query, args)
+ const char *query;
+ va_list args;
+{
+ char buf[200];
+ long val;
+
+ vsprintf (buf, query, args);
+ gdbtk_two_elem_cmd ("gdbtk_tcl_query", buf);
+
+ val = atol (gdbtk_interp->result);
+ return val;
+}
+
+
+static void
+gdbtk_print_frame_info (s, line, stopline, noerror)
+ struct symtab *s;
+ int line;
+ int stopline;
+ int noerror;
+{
+ current_source_symtab = s;
+ current_source_line = line;
+}
+
+static void
+gdbtk_create_tracepoint (tp)
+ struct tracepoint *tp;
+{
+ tracepoint_notify (tp, "create");
+}
+
+static void
+gdbtk_delete_tracepoint (tp)
+ struct tracepoint *tp;
+{
+ tracepoint_notify (tp, "delete");
+}
+
+static void
+gdbtk_modify_tracepoint (tp)
+ struct tracepoint *tp;
+{
+ tracepoint_notify (tp, "modify");
+}
+
+static void
+tracepoint_notify(tp, action)
+ struct tracepoint *tp;
+ const char *action;
+{
+ char buf[256];
+ int v;
+ struct symtab_and_line sal;
+ char *filename;
+
+ /* We ensure that ACTION contains no special Tcl characters, so we
+ can do this. */
+ sal = find_pc_line (tp->address, 0);
+
+ filename = symtab_to_filename (sal.symtab);
+ if (filename == NULL)
+ filename = "N/A";
+ sprintf (buf, "gdbtk_tcl_tracepoint %s %d 0x%lx %d {%s}", action, tp->number,
+ (long)tp->address, sal.line, filename, tp->pass_count);
+
+ v = Tcl_Eval (gdbtk_interp, buf);
+
+ if (v != TCL_OK)
+ {
+ gdbtk_fputs (gdbtk_interp->result, gdb_stdout);
+ gdbtk_fputs ("\n", gdb_stdout);
+ }
+}
+
+