+Sun Dec 18 23:31:20 1994 Stu Grossman (grossman@cygnus.com)
+
+ * gdbtk.c (gdbtk_wait gdbtk_init): Use different method of
+ enabling I/O interrupts for SVR4 (streams).
+ * (start_saving_output save_output get_saved_output
+ finish_saving_output flush_holdbuf gdbtk_flush gdbtk_fputs
+ gdbtk_init):
+ Totally revamp to use TCLs dynamic string functions. Also, quote
+ all data passed back to TCL to prevent errors with unmatched
+ braces, odd characters, etc... This fixes several wierd problems
+ with outputting strings containing unmatched braces.
+ * (breakpoint_notify gdb_loc): Use long hex format to output
+ addresses of breakpoints and PCs. This fixes some Alpha problems.
+ * (breakpoint_notify): Add stream arg to call to gdbtk_fputs.
+ * (gdb_listfiles): Also, go through the symtabs when looking for
+ files. This makes xcoff work (sort of), but probably breaks
+ something else.
+ * (gdb_stop): Return TCL_OK instead of nothing. This fixes odd
+ TCL errors when hitting stop button.
+ * (tk_command): Don't pass interp->result on to Tcl_{Var}Eval, as
+ that will trash the result. strdup the result instead and pass
+ that on. Improve error handling as well.
+
+ * gdbtk.tcl (gdbtk_tcl_flush): Use global def of
+ current_output_win. Makes flushing actually work!
+ * (asm_win_name create_asm_win update_assembly): Bunch of fixes
+ to make assembly windows stop flashing when loading a new file.
+ * (gdbtk_tcl_busy gdbtk_tcl_idle): Use catch to prevent gdb_cmd
+ errors from losing control.
+ * (create_source_window): Add source file selection to View menu.
+ * (create_command_window (<Key-Return> binding): Quote text fed
+ into gdb_cmd to prevent eval errors.
+
Sun Dec 18 11:52:58 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
* sparc-tdep.c (sparc_pop_frame): Remove erroneous extra argument
#include <unistd.h>
#include <setjmp.h>
#include "top.h"
+#ifndef FASYNC
+#include <sys/stropts.h>
+#endif
+#include <string.h>
/* Non-zero means that we're doing the gdbtk interface. */
int gdbtk = 0;
{
}
-static char *saved_output_buf = NULL; /* Start of output buffer */
-static char *saved_output_data_end = NULL; /* Ptr to nul at end of data */
-static int saved_output_buf_free = 0; /* Amount of free space in buffer */
-static char saved_output_static_buf[200]; /* Default buffer */
-
-static void
-start_saving_output ()
-{
- if (saved_output_buf)
- abort (); /* Should always be zero at this point */
-
- saved_output_buf = saved_output_static_buf;
- saved_output_data_end = saved_output_buf;
- *saved_output_data_end = '\000';
- saved_output_buf_free = sizeof saved_output_static_buf - 1;
-}
-
-static void
-save_output (ptr)
- const char *ptr;
-{
- int len;
- int needed, data_len;
-
- len = strlen (ptr);
+/* The following routines deal with stdout/stderr data, 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.
+ Normally they present their data to tcl via callbacks to the following tcl
+ routines: gdbtk_tcl_fputs, gdbtk_tcl_fputs_error, and gdbtk_flush. These
+ in turn call tk routines to update the display.
- if (len <= saved_output_buf_free)
- {
- strcpy (saved_output_data_end, ptr);
- saved_output_data_end += len;
- saved_output_buf_free -= len;
- return;
- }
+ Under some circumstances, you may want to collect the output so that it can
+ be returned as the value of a tcl procedure. This can be done by
+ surrounding the output routines with calls to start_saving_output and
+ finish_saving_output. The saved data can then be retrieved with
+ get_saved_output (but this must be done before the call to
+ finish_saving_output). */
- data_len = saved_output_data_end - saved_output_buf;
- needed = (data_len + len + 1) * 2;
+/* Dynamic string header for stdout. */
- if (saved_output_buf == saved_output_static_buf)
- {
- char *tmp;
+static Tcl_DString stdout_buffer;
- tmp = xmalloc (needed);
- strcpy (tmp, saved_output_buf);
- saved_output_buf = tmp;
- }
- else
- saved_output_buf = xrealloc (saved_output_buf, needed);
+/* Use this to collect stdout output that will be returned as the result of a
+ tcl command. */
- saved_output_data_end = saved_output_buf + data_len;
- saved_output_buf_free = (needed - data_len) - 1;
+static int saving_output = 0;
- save_output (ptr);
+static void
+start_saving_output ()
+{
+ saving_output = 1;
}
-#define get_saved_output() saved_output_buf
+#define get_saved_output() (Tcl_DStringValue (&stdout_buffer))
static void
finish_saving_output ()
{
- if (saved_output_buf != saved_output_static_buf)
- free (saved_output_buf);
+ saving_output = 0;
- saved_output_buf = NULL;
+ Tcl_DStringFree (&stdout_buffer);
}
\f
/* This routine redirects the output of fputs_unfiltered so that
the user can see what's going on in his debugger window. */
-static char holdbuf[200];
-static char *holdbufp = holdbuf;
-static int holdfree = sizeof (holdbuf);
-
static void
flush_holdbuf ()
{
- if (holdbufp == holdbuf)
- return;
+ char *s, *argv[1];
+
+ /* We use Tcl_Merge to quote braces and funny characters as necessary. */
+
+ argv[0] = Tcl_DStringValue (&stdout_buffer);
+ s = Tcl_Merge (1, argv);
- Tcl_VarEval (interp, "gdbtk_tcl_fputs ", "{", holdbuf, "}", NULL);
- holdbufp = holdbuf;
- holdfree = sizeof (holdbuf);
+ Tcl_DStringFree (&stdout_buffer);
+
+ Tcl_VarEval (interp, "gdbtk_tcl_fputs ", s, NULL);
+
+ free (s);
}
static void
gdbtk_flush (stream)
FILE *stream;
{
- if (stream != gdb_stdout || saved_output_buf)
+ if (stream != gdb_stdout || saving_output)
return;
/* Flush output from C to tcl land. */
return;
}
- if (saved_output_buf)
- {
- save_output (ptr);
- return;
- }
-
- len = strlen (ptr) + 1;
+ Tcl_DStringAppend (&stdout_buffer, ptr, -1);
- if (len > holdfree)
- {
- flush_holdbuf ();
-
- if (len > sizeof (holdbuf))
- {
- Tcl_VarEval (interp, "gdbtk_tcl_fputs ", "{", ptr, "}", NULL);
- return;
- }
- }
+ if (saving_output)
+ return;
- strncpy (holdbufp, ptr, len);
- holdbufp += len - 1;
- holdfree -= len - 1;
+ if (Tcl_DStringLength (&stdout_buffer) > 1000)
+ flush_holdbuf ();
}
static int
sprintf (bpnum, "%d", b->number);
sprintf (line, "%d", sal.line);
- sprintf (pc, "0x%x", b->address);
+ sprintf (pc, "0x%lx", b->address);
v = Tcl_VarEval (interp,
"gdbtk_tcl_breakpoint ",
if (v != TCL_OK)
{
- gdbtk_fputs (interp->result);
- gdbtk_fputs ("\n");
+ gdbtk_fputs (interp->result, gdb_stdout);
+ gdbtk_fputs ("\n", gdb_stdout);
}
}
sprintf (buf, "%d", sal.line);
Tcl_AppendElement (interp, buf); /* line number */
- sprintf (buf, "0x%x", pc);
+ sprintf (buf, "0x%lx", pc);
Tcl_AppendElement (interp, buf); /* PC */
return TCL_OK;
int val;
struct objfile *objfile;
struct partial_symtab *psymtab;
+ struct symtab *symtab;
ALL_PSYMTABS (objfile, psymtab)
Tcl_AppendElement (interp, psymtab->filename);
+ ALL_SYMTABS (objfile, symtab)
+ Tcl_AppendElement (interp, symtab->filename);
+
return TCL_OK;
}
char *argv[];
{
target_stop ();
+
+ return TCL_OK;
}
\f
char *cmd;
int from_tty;
{
- Tcl_VarEval (interp, cmd, NULL);
+ int retval;
+ char *result;
+ struct cleanup *old_chain;
+
+ retval = Tcl_Eval (interp, cmd);
+
+ result = strdup (interp->result);
- gdbtk_fputs (interp->result);
- gdbtk_fputs ("\n");
+ old_chain = make_cleanup (free, result);
+
+ if (retval != TCL_OK)
+ error (result);
+
+ printf_unfiltered ("%s\n", result);
+
+ do_cleanups (old_chain);
}
static void
int pid;
struct target_waitstatus *ourstatus;
{
+#ifdef FASYNC
signal (SIGIO, x_event);
+#else
+#if 1
+ sigset (SIGIO, x_event);
+#else
+ /* This is possibly needed for SVR4... */
+ {
+ struct sigaction action;
+ static sigset_t nullsigmask = {0};
+
+ action.sa_handler = iosig;
+ action.sa_mask = nullsigmask;
+ action.sa_flags = SA_RESTART;
+ sigaction(SIGIO, &action, NULL);
+ }
+#endif
+#endif
pid = target_wait (pid, ourstatus);
if (!interp)
error ("Tcl_CreateInterp failed");
+ Tcl_DStringInit (&stdout_buffer); /* Setup stdout buffer */
+
mainWindow = Tk_CreateMainWindow (interp, NULL, "gdb", "Gdb");
if (!mainWindow)
signal (SIGIO, SIG_IGN);
+#ifdef FASYNC
i = fcntl (x_fd, F_GETFL, 0);
fcntl (x_fd, F_SETFL, i|FASYNC);
fcntl (x_fd, F_SETOWN, getpid());
+#else
+ if (ioctl (x_fd, I_SETSIG, S_INPUT|S_RDNORM) < 0)
+ perror ("gdbtk_init: ioctl I_SETSIG failed");
+#endif /* ifndef FASYNC */
command_loop_hook = Tk_MainLoop;
fputs_unfiltered_hook = gdbtk_fputs;
set current_output_win .cmd.text
set cfunc NIL
set line_numbers 1
+set breakpoint_file(-1) {[garbage]}
#option add *Foreground Black
#option add *Background White
#
proc gdbtk_tcl_flush {} {
+ global current_output_win
+
$current_output_win yview -pickplace end
update idletasks
}
}
proc asm_win_name {funcname} {
+ if {$funcname == "*None*"} {return .asm.text}
+
regsub -all {\.} $funcname _ temp
return .asm.func_${temp}
proc gdbtk_tcl_busy {} {
if [winfo exists .src] {
- .src.start configure -state disabled
- .src.stop configure -state normal
- .src.step configure -state disabled
- .src.next configure -state disabled
- .src.continue configure -state disabled
- .src.finish configure -state disabled
- .src.up configure -state disabled
- .src.down configure -state disabled
- .src.bottom configure -state disabled
+ catch {.src.start configure -state disabled}
+ catch {.src.stop configure -state normal}
+ catch {.src.step configure -state disabled}
+ catch {.src.next configure -state disabled}
+ catch {.src.continue configure -state disabled}
+ catch {.src.finish configure -state disabled}
+ catch {.src.up configure -state disabled}
+ catch {.src.down configure -state disabled}
+ catch {.src.bottom configure -state disabled}
}
if [winfo exists .asm] {
- .asm.stepi configure -state disabled
- .asm.nexti configure -state disabled
- .asm.continue configure -state disabled
- .asm.finish configure -state disabled
- .asm.up configure -state disabled
- .asm.down configure -state disabled
- .asm.bottom configure -state disabled
- .asm.close configure -state disabled
+ catch {.asm.stepi configure -state disabled}
+ catch {.asm.nexti configure -state disabled}
+ catch {.asm.continue configure -state disabled}
+ catch {.asm.finish configure -state disabled}
+ catch {.asm.up configure -state disabled}
+ catch {.asm.down configure -state disabled}
+ catch {.asm.bottom configure -state disabled}
+ catch {.asm.close configure -state disabled}
}
}
proc gdbtk_tcl_idle {} {
if [winfo exists .src] {
- .src.start configure -state normal
- .src.stop configure -state disabled
- .src.step configure -state normal
- .src.next configure -state normal
- .src.continue configure -state normal
- .src.finish configure -state normal
- .src.up configure -state normal
- .src.down configure -state normal
- .src.bottom configure -state normal
+ catch {.src.start configure -state normal}
+ catch {.src.stop configure -state disabled}
+ catch {.src.step configure -state normal}
+ catch {.src.next configure -state normal}
+ catch {.src.continue configure -state normal}
+ catch {.src.finish configure -state normal}
+ catch {.src.up configure -state normal}
+ catch {.src.down configure -state normal}
+ catch {.src.bottom configure -state normal}
}
if [winfo exists .asm] {
- .asm.stepi configure -state normal
- .asm.nexti configure -state normal
- .asm.continue configure -state normal
- .asm.finish configure -state normal
- .asm.up configure -state normal
- .asm.down configure -state normal
- .asm.bottom configure -state normal
- .asm.close configure -state normal
+ catch {.asm.stepi configure -state normal}
+ catch {.asm.nexti configure -state normal}
+ catch {.asm.continue configure -state normal}
+ catch {.asm.finish configure -state normal}
+ catch {.asm.up configure -state normal}
+ catch {.asm.down configure -state normal}
+ catch {.asm.bottom configure -state normal}
+ catch {.asm.close configure -state normal}
}
}
update
- pack forget .asm.text
-
update_assembly [gdb_loc]
}
}
proc reg_config_menu {} {
- global reg_format
-
catch {destroy .reg.config}
toplevel .reg.config
wm geometry .reg.config +300+300
# stick in the new one.
if {$funcname != $cfunc } {
- pack forget $win
+ set oldwin $win
set cfunc $funcname
set win [asm_win_name $cfunc]
# Pack the text widget, and scroll to the right place
+ pack forget $oldwin
pack $win -side left -expand yes -fill both \
-after .asm.scroll
.asm.scroll configure -command "$win yview"
if {$current_asm_label != "$pc $funcname"} then {
set .asm.label "$pc $funcname"
-# .asm.label configure -text "$pc $funcname"
set current_asm_label "$pc $funcname"
}
$win yview [expr $line - $asm_screen_height / 2]
}
-# echo "Picking line $line"
-# $win yview -pickplace $line
-
$win configure -state disabled
}
}
.src.menubar.view.menu delete 0 last
+# Source file selection
+ .src.menubar.view.menu add command -label "Select source file" \
+ -command files_command
+
# Line numbers enable/disable menu item
.src.menubar.view.menu add checkbutton -variable line_numbers \
-label "Line numbers" -onvalue 1 -offvalue 0 -command {
%W insert end \n
%W yview -pickplace end
- catch "gdb_cmd {$command_line}"
+ catch "gdb_cmd [list $command_line]"
set command_line {}
update_ptr
%W insert end "(gdb) "