/* Tcl/Tk interface routines.
- Copyright 1994, 1995 Free Software Foundation, Inc.
+ Copyright 1994, 1995, 1996 Free Software Foundation, Inc.
Written by Stu Grossman <grossman@cygnus.com> of Cygnus Support.
#include <sys/stropts.h>
#endif
+/* Some versions (1.3.79, 1.3.81) of Linux don't support SIOCSPGRP the way
+ gdbtk wants to use it... */
+#ifdef __linux__
+#undef SIOCSPGRP
+#endif
+
+static void null_routine PARAMS ((int));
+static void gdbtk_flush PARAMS ((FILE *));
+static void gdbtk_fputs PARAMS ((const char *, FILE *));
+static int gdbtk_query PARAMS ((const char *, va_list));
+static char *gdbtk_readline PARAMS ((char *));
+static void gdbtk_init PARAMS ((void));
+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 *));
+static void x_event PARAMS ((int));
+static void gdbtk_interactive PARAMS ((void));
+static void cleanup_init PARAMS ((int));
+static void tk_command PARAMS ((char *, int));
+static int gdb_disassemble PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static int compare_lines PARAMS ((const PTR, const PTR));
+static int gdbtk_dis_asm_read_memory PARAMS ((bfd_vma, bfd_byte *, int, disassemble_info *));
+static int gdb_stop PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static int gdb_listfiles PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static int call_wrapper PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static int gdb_cmd PARAMS ((ClientData, Tcl_Interp *, int, char *argv[]));
+static int gdb_fetch_registers PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static void gdbtk_readline_end PARAMS ((void));
+static int gdb_changed_register_list PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static void register_changed_p PARAMS ((int, void *));
+static int gdb_get_breakpoint_list PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static int gdb_get_breakpoint_info PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static void breakpoint_notify PARAMS ((struct breakpoint *, const char *));
+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 int gdb_loc PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static int gdb_eval PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static int gdb_sourcelines PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static int map_arg_registers PARAMS ((int, char *[], void (*) (int, void *), void *));
+static void get_register_name PARAMS ((int, void *));
+static int gdb_regnames PARAMS ((ClientData, Tcl_Interp *, int, char *[]));
+static void get_register PARAMS ((int, void *));
+
/* Handle for TCL interpreter */
+
static Tcl_Interp *interp = NULL;
/* Handle for TK main window */
+
static Tk_Window mainWindow = NULL;
static int x_fd; /* X network socket */
-/* This variable determines where memory used for disassembly is read from.
+/* This variable is true when the inferior is running. Although it's
+ possible to disable most input from widgets and thus prevent
+ attempts to do anything while the inferior is running, any commands
+ that get through - even a simple memory read - are Very Bad, and
+ may cause GDB to crash or behave strangely. So, this variable
+ provides an extra layer of defense. */
- If > 0, then disassembly comes from the exec file rather than the target
- (which might be at the other end of a slow serial link). If == 0 then
- disassembly comes from target. If < 0 disassembly is automatically switched
- to the target if it's an inferior process, otherwise the exec file is
- used.
- */
+static int running_now;
+
+/* This variable determines where memory used for disassembly is read from.
+ If > 0, then disassembly comes from the exec file rather than the
+ target (which might be at the other end of a slow serial link). If
+ == 0 then disassembly comes from target. If < 0 disassembly is
+ automatically switched to the target if it's an inferior process,
+ otherwise the exec file is used. */
static int disassemble_from_exec = -1;
const char *ptr;
FILE *stream;
{
+
if (result_ptr)
Tcl_DStringAppend (result_ptr, (char *)ptr, -1);
else
static int
gdbtk_query (query, args)
- char *query;
+ const char *query;
va_list args;
{
- char buf[200];
+ char buf[200], *merge[2];
+ char *command;
long val;
vsprintf (buf, query, args);
- Tcl_VarEval (interp, "gdbtk_tcl_query ", "{", buf, "}", NULL);
+ merge[0] = "gdbtk_tcl_query";
+ merge[1] = buf;
+ command = Tcl_Merge (2, merge);
+ Tcl_Eval (interp, command);
+ free (command);
val = atol (interp->result);
return val;
}
+
+/* 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);
+ merge[0] = "gdbtk_tcl_readline_begin";
+ merge[1] = buf;
+ command = Tcl_Merge (2, merge);
+ Tcl_Eval (interp, command);
+ free (command);
+}
+
+static char *
+gdbtk_readline (prompt)
+ char *prompt;
+{
+ char *merge[2];
+ char *command;
+
+ merge[0] = "gdbtk_tcl_readline";
+ merge[1] = prompt;
+ command = Tcl_Merge (2, merge);
+ if (Tcl_Eval (interp, command) == TCL_OK)
+ {
+ return (strdup (interp -> result));
+ }
+ else
+ {
+ gdbtk_fputs (interp -> result, gdb_stdout);
+ gdbtk_fputs ("\n", gdb_stdout);
+ return (NULL);
+ }
+}
+
+static void
+gdbtk_readline_end ()
+{
+ Tcl_Eval (interp, "gdbtk_tcl_readline_end");
+}
+
\f
static void
#ifdef ANSI_PROTOTYPES
if (b->type != bp_breakpoint)
return;
+ /* We ensure that ACTION contains no special Tcl characters, so we
+ can do this. */
sprintf (buf, "gdbtk_tcl_breakpoint %s %d", action, b->number);
v = Tcl_Eval (interp, buf);
argc--;
argv++;
- return map_arg_registers (argc, argv, get_register_name, 0);
+ return map_arg_registers (argc, argv, get_register_name, NULL);
}
#ifndef REGISTER_CONVERTIBLE
else
memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum));
- val_print (REGISTER_VIRTUAL_TYPE (regnum), virtual_buffer, 0,
- gdb_stdout, format, 1, 0, Val_pretty_default);
+ if (format == 'r')
+ {
+ int j;
+ printf_filtered ("0x");
+ for (j = 0; j < REGISTER_RAW_SIZE (regnum); j++)
+ {
+ register int idx = TARGET_BYTE_ORDER == BIG_ENDIAN ? j
+ : REGISTER_RAW_SIZE (regnum) - 1 - j;
+ printf_filtered ("%02x", (unsigned char)raw_buffer[idx]);
+ }
+ }
+ else
+ val_print (REGISTER_VIRTUAL_TYPE (regnum), virtual_buffer, 0,
+ gdb_stdout, format, 1, 0, Val_pretty_default);
Tcl_DStringAppend (result_ptr, " ", -1);
}
argc--;
format = **argv++;
- return map_arg_registers (argc, argv, get_register, format);
+ return map_arg_registers (argc, argv, get_register, (void *) format);
}
/* This contains the previous values of the registers, since the last call to
void *argp; /* Ignored */
{
char raw_buffer[MAX_REGISTER_RAW_SIZE];
- char buf[100];
if (read_relative_register_raw_bytes (regnum, raw_buffer))
return;
REGISTER_RAW_SIZE (regnum)) == 0)
return;
- /* Found a changed register. Save new value and return it's number. */
+ /* Found a changed register. Save new value and return its number. */
memcpy (&old_regs[REGISTER_BYTE (regnum)], raw_buffer,
REGISTER_RAW_SIZE (regnum));
return map_arg_registers (argc, argv, register_changed_p, NULL);
}
\f
-/* This implements the TCL command `gdb_cmd', which sends it's argument into
+/* This implements the TCL command `gdb_cmd', which sends its argument into
the GDB command scanner. */
static int
if (argc != 2)
error ("wrong # args");
+ if (running_now)
+ return TCL_OK;
+
execute_command (argv[1], 1);
bpstat_do_actions (&stop_bpstat);
gdb_flush (gdb_stdout); /* Sometimes error output comes here as well */
-/* In case of an error, we may need to force the GUI into idle mode because
- gdbtk_call_command may have bombed out while in the command routine. */
+ /* In case of an error, we may need to force the GUI into idle
+ mode because gdbtk_call_command may have bombed out while in
+ the command routine. */
- Tcl_VarEval (interp, "gdbtk_tcl_idle", NULL);
+ Tcl_Eval (interp, "gdbtk_tcl_idle");
}
do_cleanups (ALL_CLEANUPS);
if (! di_initialized)
{
- INIT_DISASSEMBLE_INFO (di, gdb_stdout);
- di.fprintf_func = (fprintf_ftype) fprintf_unfiltered;
+ INIT_DISASSEMBLE_INFO_NO_ARCH (di, gdb_stdout,
+ (fprintf_ftype) fprintf_unfiltered);
+ di.flavour = bfd_target_unknown_flavour;
di.memory_error_func = dis_asm_memory_error;
di.print_address_func = dis_asm_print_address;
di_initialized = 1;
}
+ di.mach = tm_print_insn_info.mach;
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ tm_print_insn_info.endian = BFD_ENDIAN_BIG;
+ else
+ tm_print_insn_info.endian = BFD_ENDIAN_LITTLE;
+
if (argc != 3 && argc != 4)
error ("wrong # args");
correctly.
Else, we're debugging a remote process, and should disassemble from the
- exec file for speed. However, this is no good if the target modifies it's
+ exec file for speed. However, this is no good if the target modifies its
code (for relocation, or whatever).
*/
char *result;
struct cleanup *old_chain;
+ /* Catch case of no argument, since this will make the tcl interpreter dump core. */
+ if (cmd == NULL)
+ error_no_arg ("tcl command to interpret");
+
retval = Tcl_Eval (interp, cmd);
result = strdup (interp->result);
char *arg;
int from_tty;
{
+ running_now = 0;
if (cmdblk->class == class_run)
{
- Tcl_VarEval (interp, "gdbtk_tcl_busy", NULL);
+ running_now = 1;
+ Tcl_Eval (interp, "gdbtk_tcl_busy");
(*cmdblk->function.cfunc)(arg, from_tty);
- Tcl_VarEval (interp, "gdbtk_tcl_idle", NULL);
+ Tcl_Eval (interp, "gdbtk_tcl_idle");
+ running_now = 0;
}
else
(*cmdblk->function.cfunc)(arg, from_tty);
}
+/* 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. */
+
+static void
+tk_command_loop ()
+{
+ extern GDB_FILE *instream;
+
+ /* We no longer want to use stdin as the command input stream */
+ instream = NULL;
+ Tcl_Eval (interp, "gdbtk_tcl_preloop");
+ Tk_MainLoop ();
+}
+
static void
gdbtk_init ()
{
Tcl_CreateCommand (interp, "gdb_get_breakpoint_info", call_wrapper,
gdb_get_breakpoint_info, NULL);
- command_loop_hook = Tk_MainLoop;
- print_frame_info_listing_hook = null_routine;
+ command_loop_hook = tk_command_loop;
+ print_frame_info_listing_hook =
+ (void (*) PARAMS ((struct symtab *, int, int, int))) null_routine;
query_hook = gdbtk_query;
flush_hook = gdbtk_flush;
create_breakpoint_hook = gdbtk_create_breakpoint;
interactive_hook = gdbtk_interactive;
target_wait_hook = gdbtk_wait;
call_command_hook = gdbtk_call_command;
+ readline_begin_hook = gdbtk_readline_begin;
+ readline_hook = gdbtk_readline;
+ readline_end_hook = gdbtk_readline_end;
/* Get the file descriptor for the X server */
discard_cleanups (old_chain);
}
-/* Come here during initialze_all_files () */
+/* Come here during initialize_all_files () */
void
_initialize_gdbtk ()