diff options
author | Jim Ingham <jingham@apple.com> | 1998-07-01 20:17:31 +0000 |
---|---|---|
committer | Jim Ingham <jingham@apple.com> | 1998-07-01 20:17:31 +0000 |
commit | f3b86a30f914d3a74e4f167bd4a97170f21a9776 (patch) | |
tree | c3d026f7147ca17b2f561a501611b6c99b0135d7 /gdb/gdbtk-hooks.c | |
parent | a57fc6b9c04a78607b8f929f771f04ef82f82684 (diff) | |
download | gdb-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.c | 689 |
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); + } +} + + |