+Thu Dec 15 16:40:10 1994 Stu Grossman (grossman@cygnus.com)
+
+ * defs.h, gdbtk.c (gdbtk_fputs), main.c (gdb_fputs), top.c: Add stream arg
+ to fputs_unfiltered_hook. Differentiate stdout from stderr when
+ passing text into tcl land.
+ * defs.h, top.c, utils.c (error): Add error_hook.
+ * gdbtk.c: Improve mechanism for capturing output values.
+ * (full_filename): Remove.
+ * (gdb_cmd call_wrapper gdbtk_init): Protect all calls from tcl
+ land with call_wrapper. This prevents longjmps (usually via
+ error()) from jumping out of tcl/tk and leaving things in an
+ indeterminate state.
+ * gdbtk.tcl: New view option to disable line numbers. Put catch
+ around most uses of gdb_cmd. Add update button to reg config
+ window. Stop doing immediate updates when selecting registers.
+ Change register view values into checkbuttons.
+
Tue Dec 13 15:15:33 1994 Stan Shebs <shebs@andros.cygnus.com>
* breakpoint.c, infrun.c, printcmd.c: Change long command help
/* libiberty.h can't declare this one, but evidently we can. */
extern char *strsignal PARAMS ((int));
+#include "mmalloc.h"
+
/* For BFD64 and bfd_vma. */
#include "bfd.h"
extern char *chill_demangle PARAMS ((const char *));
-/* From libiberty.a */
-
-extern char *cplus_demangle PARAMS ((const char *, int));
-
-extern char *cplus_mangle_opname PARAMS ((char *, int));
-
-/* From libmmalloc.a (memory mapped malloc library) */
-
-extern PTR mmalloc_attach PARAMS ((int, PTR));
-
-extern PTR mmalloc_detach PARAMS ((PTR));
-
-extern PTR mmalloc PARAMS ((PTR, long));
-
-extern PTR mrealloc PARAMS ((PTR, PTR, long));
-
-extern void mfree PARAMS ((PTR, PTR));
-
-extern int mmalloc_setkey PARAMS ((PTR, int, PTR));
-
-extern PTR mmalloc_getkey PARAMS ((PTR, int));
-
/* From utils.c */
extern int strcmp_iw PARAMS ((const char *, const char *));
extern PTR xmrealloc PARAMS ((PTR, PTR, long));
-extern PTR mmalloc PARAMS ((PTR, long));
-
-extern PTR mrealloc PARAMS ((PTR, PTR, long));
-
-extern void mfree PARAMS ((PTR, PTR));
-
-extern int mmcheck PARAMS ((PTR, void (*) (void)));
-
-extern int mmtrace PARAMS ((void));
-
extern int parse_escape PARAMS ((char **));
-extern const char * const reg_names[];
+extern char *reg_names[];
/* Message to be printed before the error message, when an error occurs. */
extern void (*init_ui_hook) PARAMS ((void));
extern void (*command_loop_hook) PARAMS ((void));
-extern void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer));
+extern void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer, FILE *stream));
extern void (*print_frame_info_listing_hook) PARAMS ((struct symtab *s, int line,
int stopline, int noerror));
extern int (*query_hook) PARAMS (());
extern void (*call_command_hook) PARAMS ((struct cmd_list_element *c,
char *cmd, int from_tty));
+extern NORETURN void (*error_hook) PARAMS (());
+
/* Inhibit window interface if non-zero. */
extern int use_windows;
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
+#include <setjmp.h>
+#include "top.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);
+
+ if (len <= saved_output_buf_free)
+ {
+ strcpy (saved_output_data_end, ptr);
+ saved_output_data_end += len;
+ saved_output_buf_free -= len;
+ return;
+ }
+
+ data_len = saved_output_data_end - saved_output_buf;
+ needed = (data_len + len + 1) * 2;
+
+ if (saved_output_buf == saved_output_static_buf)
+ {
+ char *tmp;
+
+ tmp = xmalloc (needed);
+ strcpy (tmp, saved_output_buf);
+ saved_output_buf = tmp;
+ }
+ else
+ saved_output_buf = xrealloc (saved_output_buf, needed);
+
+ saved_output_data_end = saved_output_buf + data_len;
+ saved_output_buf_free = (needed - data_len) - 1;
+
+ save_output (ptr);
+}
+
+#define get_saved_output() saved_output_buf
+
+static void
+finish_saving_output ()
+{
+ if (saved_output_buf != saved_output_static_buf)
+ free (saved_output_buf);
+
+ saved_output_buf = NULL;
+}
\f
/* This routine redirects the output of fputs_unfiltered so that
the user can see what's going on in his debugger window. */
gdbtk_flush (stream)
FILE *stream;
{
+ if (stream != gdb_stdout || saved_output_buf)
+ return;
+
+ /* Flush output from C to tcl land. */
+
flush_holdbuf ();
+ /* Force immediate screen update */
+
Tcl_VarEval (interp, "gdbtk_tcl_flush", NULL);
}
static void
-gdbtk_fputs (ptr)
+gdbtk_fputs (ptr, stream)
const char *ptr;
+ FILE *stream;
{
int len;
+ if (stream != gdb_stdout)
+ {
+ Tcl_VarEval (interp, "gdbtk_tcl_fputs_error ", "{", ptr, "}", NULL);
+ return;
+ }
+
+ if (saved_output_buf)
+ {
+ save_output (ptr);
+ return;
+ }
+
len = strlen (ptr) + 1;
if (len > holdfree)
return val;
}
\f
-#if 0
-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;
-}
-#endif
-\f
static void
breakpoint_notify(b, action)
struct breakpoint *b;
return map_arg_registers (argc, argv, get_register_name, 0);
}
-static char reg_value[200];
-static char *reg_valp = reg_value;
-
-static void
-save_reg_value (ptr)
- const char *ptr;
-{
- int len;
-
- len = strlen (ptr);
-
- strncpy (reg_valp, ptr, len + 1);
-
- reg_valp += len;
-}
-
#ifndef REGISTER_CONVERTIBLE
#define REGISTER_CONVERTIBLE(x) (0 != 0)
#endif
return;
}
- fputs_unfiltered_hook = save_reg_value;
- flush_hook = 0;
- reg_valp = reg_value;
+ start_saving_output (); /* Start collecting stdout */
/* Convert raw data to virtual format if necessary. */
val_print (REGISTER_VIRTUAL_TYPE (regnum), virtual_buffer, 0,
gdb_stdout, format, 1, 0, Val_pretty_default);
- fputs_unfiltered_hook = gdbtk_fputs;
- flush_hook = gdbtk_flush;
+ Tcl_AppendElement (interp, get_saved_output ());
- Tcl_AppendElement (interp, reg_value);
+ finish_saving_output (); /* Set stdout back to normal */
}
static int
return map_arg_registers (argc, argv, register_changed_p, NULL);
}
\f
-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. */
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);
-
- /* 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. */
-
- if (val == 0)
- Tcl_VarEval (interp, "gdbtk_tcl_idle", NULL);
+ execute_command (argv[1], 1);
bpstat_do_actions (&stop_bpstat);
- do_cleanups (old_chain);
/* Drain all buffered command output */
- gdb_flush (gdb_stderr);
gdb_flush (gdb_stdout);
- /* 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;
}
+/* This routine acts as a top-level for all GDB code called by tcl/Tk. It
+ handles cleanups, and calls to return_to_top_level (usually via error).
+ This is necessary in order to prevent a longjmp out of the bowels of Tk,
+ possibly leaving things in a bad state. Since this routine can be called
+ recursively, it needs to save and restore the contents of the jmp_buf as
+ necessary. */
+
+static int
+call_wrapper (clientData, interp, argc, argv)
+ ClientData clientData;
+ Tcl_Interp *interp;
+ int argc;
+ char *argv[];
+{
+ int val;
+ struct cleanup *saved_cleanup_chain;
+ Tcl_CmdProc *func;
+ jmp_buf saved_error_return;
+
+ func = (Tcl_CmdProc *)clientData;
+ memcpy (saved_error_return, error_return, sizeof (jmp_buf));
+
+ saved_cleanup_chain = save_cleanups ();
+
+ if (!setjmp (error_return))
+ val = func (clientData, interp, argc, argv);
+ else
+ {
+ val = TCL_ERROR; /* Flag an error for TCL */
+
+ finish_saving_output (); /* Restore stdout to normal */
+
+ gdb_flush (gdb_stderr); /* Flush error output */
+
+/* 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);
+ }
+
+ do_cleanups (ALL_CLEANUPS);
+
+ restore_cleanups (saved_cleanup_chain);
+
+ memcpy (error_return, saved_error_return, sizeof (jmp_buf));
+
+ return val;
+}
+
static int
gdb_listfiles (clientData, interp, argc, argv)
ClientData clientData;
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_sourcelines", gdb_sourcelines, NULL, NULL);
- Tcl_CreateCommand (interp, "gdb_listfiles", gdb_listfiles, NULL, NULL);
- Tcl_CreateCommand (interp, "gdb_stop", gdb_stop, NULL, NULL);
- Tcl_CreateCommand (interp, "gdb_regnames", gdb_regnames, NULL, NULL);
- Tcl_CreateCommand (interp, "gdb_fetch_registers", gdb_fetch_registers, NULL,
+ Tcl_CreateCommand (interp, "gdb_cmd", call_wrapper, gdb_cmd, NULL);
+ Tcl_CreateCommand (interp, "gdb_loc", call_wrapper, gdb_loc, NULL);
+ Tcl_CreateCommand (interp, "gdb_sourcelines", call_wrapper, gdb_sourcelines,
+ NULL);
+ Tcl_CreateCommand (interp, "gdb_listfiles", call_wrapper, gdb_listfiles,
NULL);
- Tcl_CreateCommand (interp, "gdb_changed_register_list",
- gdb_changed_register_list, NULL, NULL);
+ Tcl_CreateCommand (interp, "gdb_stop", call_wrapper, gdb_stop, NULL);
+ Tcl_CreateCommand (interp, "gdb_regnames", call_wrapper, gdb_regnames, NULL);
+ Tcl_CreateCommand (interp, "gdb_fetch_registers", call_wrapper,
+ gdb_fetch_registers, NULL);
+ Tcl_CreateCommand (interp, "gdb_changed_register_list", call_wrapper,
+ gdb_changed_register_list, NULL);
gdbtk_filename = getenv ("GDBTK_FILENAME");
if (!gdbtk_filename)
set screen_bot 0
set current_output_win .cmd.text
set cfunc NIL
+set line_numbers 1
+
#option add *Foreground Black
#option add *Background White
#option add *Font -*-*-medium-r-normal--18-*-*-*-m-*-*-1
$current_output_win yview -pickplace end
}
+proc gdbtk_tcl_fputs_error {arg} {
+ .cmd.text insert end "$arg"
+ .cmd.text yview -pickplace end
+}
+
#
# GDB Callback:
#
}
proc gdbtk_tcl_busy {} {
- .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
- .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
+ 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
+ }
+ 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
+ }
}
proc gdbtk_tcl_idle {} {
- .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
- .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
+ 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
+ }
+
+ 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
+ }
}
#
proc create_file_win {filename debug_file} {
global breakpoint_file
global breakpoint_line
+ global line_numbers
# Replace all the dirty characters in $filename with clean ones, and generate
# a unique name for the text widget.
bind $win <1> do_nothing
bind $win <B1-Motion> do_nothing
- bind $win n {gdb_cmd next ; update_ptr}
- bind $win s {gdb_cmd step ; update_ptr}
- bind $win c {gdb_cmd continue ; update_ptr}
- bind $win f {gdb_cmd finish ; update_ptr}
- bind $win u {gdb_cmd up ; update_ptr}
- bind $win d {gdb_cmd down ; update_ptr}
+ bind $win n {catch {gdb_cmd next} ; update_ptr}
+ bind $win s {catch {gdb_cmd step} ; update_ptr}
+ bind $win c {catch {gdb_cmd continue} ; update_ptr}
+ bind $win f {catch {gdb_cmd finish} ; update_ptr}
+ bind $win u {catch {gdb_cmd up} ; update_ptr}
+ bind $win d {catch {gdb_cmd down} ; update_ptr}
$win delete 0.0 end
$win insert 0.0 [read $fh]
close $fh
-# Add margins (for annotations) and a line number to each line
+# Add margins (for annotations) and a line number to each line (if requested)
set numlines [$win index end]
set numlines [lindex [split $numlines .] 0]
- for {set i 1} {$i <= $numlines} {incr i} {
- $win insert $i.0 [format " %4d " $i]
- $win tag add source $i.8 "$i.0 lineend"
- }
+ if $line_numbers {
+ for {set i 1} {$i <= $numlines} {incr i} {
+ $win insert $i.0 [format " %4d " $i]
+ $win tag add source $i.8 "$i.0 lineend"
+ }
+ } else {
+ for {set i 1} {$i <= $numlines} {incr i} {
+ $win insert $i.0 " "
+ $win tag add source $i.8 "$i.0 lineend"
+ }
+ }
# Add the breakdots
bind $win <Enter> {focus %W}
bind $win <1> {asm_window_button_1 %W %X %Y %x %y}
bind $win <B1-Motion> do_nothing
- bind $win n {gdb_cmd nexti ; update_ptr}
- bind $win s {gdb_cmd stepi ; update_ptr}
- bind $win c {gdb_cmd continue ; update_ptr}
- bind $win f {gdb_cmd finish ; update_ptr}
- bind $win u {gdb_cmd up ; update_ptr}
- bind $win d {gdb_cmd down ; update_ptr}
+ bind $win n {catch {gdb_cmd nexti} ; update_ptr}
+ bind $win s {catch {gdb_cmd stepi} ; update_ptr}
+ bind $win c {catch {gdb_cmd continue} ; update_ptr}
+ bind $win f {catch {gdb_cmd finish} ; update_ptr}
+ bind $win u {catch {gdb_cmd up} ; update_ptr}
+ bind $win d {catch {gdb_cmd down} ; update_ptr}
# Disassemble the code, and read it into the new text widget
frame .asm.row2
button .asm.stepi -width 6 -text Stepi \
- -command {gdb_cmd stepi ; update_ptr}
+ -command {catch {gdb_cmd stepi} ; update_ptr}
button .asm.nexti -width 6 -text Nexti \
- -command {gdb_cmd nexti ; update_ptr}
+ -command {catch {gdb_cmd nexti} ; update_ptr}
button .asm.continue -width 6 -text Cont \
- -command {gdb_cmd continue ; update_ptr}
+ -command {catch {gdb_cmd continue} ; update_ptr}
button .asm.finish -width 6 -text Finish \
- -command {gdb_cmd finish ; update_ptr}
- button .asm.up -width 6 -text Up -command {gdb_cmd up ; update_ptr}
+ -command {catch {gdb_cmd finish} ; update_ptr}
+ button .asm.up -width 6 -text Up -command {catch {gdb_cmd up} ; update_ptr}
button .asm.down -width 6 -text Down \
- -command {gdb_cmd down ; update_ptr}
+ -command {catch {gdb_cmd down} ; update_ptr}
button .asm.bottom -width 6 -text Bottom \
- -command {gdb_cmd {frame 0} ; update_ptr}
+ -command {catch {gdb_cmd {frame 0}} ; update_ptr}
pack .asm.stepi .asm.continue .asm.up .asm.bottom -side left -padx 3 -pady 5 -in .asm.row1
pack .asm.nexti .asm.finish .asm.down -side left -padx 3 -pady 5 -in .asm.row2
- pack .asm.row1 .asm.row2 -side top -anchor w
+ pack .asm.row2 .asm.row1 -side bottom -anchor w -before .asm.info
update
set regnames [gdb_regnames]
set num_regs [llength $regnames]
- button .reg.config.done -text Done -command {destroy .reg.config}
+ frame .reg.config.buts
+
+ button .reg.config.done -text " Done " -command "
+ recompute_reg_display_list $num_regs
+ populate_reg_window
+ update_registers all
+ destroy .reg.config "
+
+ button .reg.config.update -text Update -command "
+ recompute_reg_display_list $num_regs
+ populate_reg_window
+ update_registers all "
+
+ pack .reg.config.buts -side bottom -fill x
- pack .reg.config.done -side bottom -fill x
+ pack .reg.config.done -side left -fill x -expand yes -in .reg.config.buts
+ pack .reg.config.update -side right -fill x -expand yes -in .reg.config.buts
# Since there can be lots of registers, we build the window with no more than
# 32 rows, and as many columns as needed.
for {set regnum 0} {$regnum < $num_regs} {incr regnum} {
set regname [lindex $regnames $regnum]
checkbutton .reg.config.col$col.$row -text $regname -pady 0 \
- -variable regena($regnum) -relief flat -anchor w -bd 1 \
- -command "recompute_reg_display_list $num_regs
- populate_reg_window
- update_registers all"
+ -variable regena($regnum) -relief flat -anchor w -bd 1
pack .reg.config.col$col.$row -side top -fill both
build_framework .reg Registers
- .reg.menubar.view.menu add command -label Natural
- .reg.menubar.view.menu add command -label Config -command {
- reg_config_menu }
+# First, delete all the old menu entries
+
+ .reg.menubar.view.menu delete 0 last
# Hex menu item
- .reg.menubar.view.menu entryconfigure 0 -command {
- global reg_format
+ .reg.menubar.view.menu add radiobutton -variable reg_format \
+ -label Hex -value x -command {update_registers all}
- set reg_format x
- update_registers all
- }
# Decimal menu item
- .reg.menubar.view.menu entryconfigure 1 -command {
- global reg_format
+ .reg.menubar.view.menu add radiobutton -variable reg_format \
+ -label Decimal -value d -command {update_registers all}
- set reg_format d
- update_registers all
- }
# Octal menu item
- .reg.menubar.view.menu entryconfigure 2 -command {
- global reg_format
+ .reg.menubar.view.menu add radiobutton -variable reg_format \
+ -label Octal -value o -command {update_registers all}
- set reg_format o
- update_registers all
- }
# Natural menu item
- .reg.menubar.view.menu entryconfigure 3 -command {
- global reg_format
+ .reg.menubar.view.menu add radiobutton -variable reg_format \
+ -label Natural -value {} -command {update_registers all}
- set reg_format {}
- update_registers all
- }
+# Config menu item
+ .reg.menubar.view.menu add separator
+
+ .reg.menubar.view.menu add command -label Config -command {
+ reg_config_menu }
destroy .reg.label
# Install the reg names
populate_reg_window
+ update_registers all
}
# Convert regena into a list of the enabled $regnums
${win}.menubar.file.menu add command -label Close \
-command "destroy ${win}"
${win}.menubar.file.menu add command -label Quit \
- -command {gdb_cmd quit}
+ -command {catch {gdb_cmd quit}}
menubutton ${win}.menubar.view -padx 12 -text View \
-menu ${win}.menubar.view.menu -underline 0
build_framework .src Source "*No file*"
+# First, delete all the old view menu entries
+
+ .src.menubar.view.menu delete 0 last
+
+# Line numbers enable/disable menu item
+ .src.menubar.view.menu add checkbutton -variable line_numbers \
+ -label "Line numbers" -onvalue 1 -offvalue 0 -command {
+ foreach source [array names wins] {
+ if {$source == "Blank"} continue
+ destroy $wins($source)
+ unset wins($source)
+ }
+ set cfile Blank
+ update_listing [gdb_loc]
+ }
+
frame .src.row1
frame .src.row2
button .src.start -width 6 -text Start -command \
- {gdb_cmd {break main}
- gdb_cmd {enable delete $bpnum}
- gdb_cmd run
+ {catch {gdb_cmd {break main}}
+ catch {gdb_cmd {enable delete $bpnum}}
+ catch {gdb_cmd run}
update_ptr }
button .src.stop -width 6 -text Stop -fg red -activeforeground red \
-state disabled -command gdb_stop
button .src.step -width 6 -text Step \
- -command {gdb_cmd step ; update_ptr}
+ -command {catch {gdb_cmd step} ; update_ptr}
button .src.next -width 6 -text Next \
- -command {gdb_cmd next ; update_ptr}
+ -command {catch {gdb_cmd next} ; update_ptr}
button .src.continue -width 6 -text Cont \
- -command {gdb_cmd continue ; update_ptr}
+ -command {catch {gdb_cmd continue} ; update_ptr}
button .src.finish -width 6 -text Finish \
- -command {gdb_cmd finish ; update_ptr}
- button .src.up -width 6 -text Up -command {gdb_cmd up ; update_ptr}
+ -command {catch {gdb_cmd finish} ; update_ptr}
+ button .src.up -width 6 -text Up \
+ -command {catch {gdb_cmd up} ; update_ptr}
button .src.down -width 6 -text Down \
- -command {gdb_cmd down ; update_ptr}
+ -command {catch {gdb_cmd down} ; update_ptr}
button .src.bottom -width 6 -text Bottom \
- -command {gdb_cmd {frame 0} ; update_ptr}
+ -command {catch {gdb_cmd {frame 0}} ; update_ptr}
pack .src.start .src.step .src.continue .src.up .src.bottom \
-side left -padx 3 -pady 5 -in .src.row1
pack .src.stop .src.next .src.finish .src.down -side left -padx 3 \
-pady 5 -in .src.row2
- pack .src.row1 .src.row2 -side top -anchor w
+ pack .src.row2 .src.row1 -side bottom -anchor w -before .src.info
$wins($cfile) insert 0.0 " This page intentionally left blank."
$wins($cfile) configure -width 88 -state disabled \
%W insert end \n
%W yview -pickplace end
- gdb_cmd $command_line
+ catch "gdb_cmd {$command_line}"
set command_line {}
update_ptr
%W insert end "(gdb) "
#endif
/* Temporary variable for SET_TOP_LEVEL. */
+
static int top_level_val;
/* Do a setjmp on error_return and quit_return. catch_errors is
? (PTR) 0 : (PTR) memcpy (quit_return, error_return, sizeof (jmp_buf))) \
, top_level_val)
+/* If nonzero, display time usage both at startup and for each command. */
+
+int display_time;
+
+/* If nonzero, display space usage both at startup and for each command. */
+
+int display_space;
+
extern void gdb_init PARAMS ((void));
int
register int i;
+ long time_at_startup = get_run_time ();
+
/* start-sanitize-mpw */
#ifdef MPW
/* Drop into MacsBug, but only if the executable is specially named. */
{"tty", required_argument, 0, 't'},
{"baud", required_argument, 0, 'b'},
{"b", required_argument, 0, 'b'},
- {"nw", no_argument, &no_windows, 1},
- {"nowindows", no_argument, &no_windows, 1},
+ {"nw", no_argument, &use_windows, 0},
+ {"nowindows", no_argument, &use_windows, 0},
+ {"w", no_argument, &use_windows, 1},
+ {"windows", no_argument, &use_windows, 1},
+ {"statistics", no_argument, 0, 13},
/* Allow machine descriptions to add more options... */
#ifdef ADDITIONAL_OPTIONS
ADDITIONAL_OPTIONS
#endif
- {0, no_argument, 0, 0},
+ {0, no_argument, 0, 0}
};
while (1)
/* FIXME: what if the syntax is wrong (e.g. not digits)? */
annotation_level = atoi (optarg);
break;
+ case 13:
+ /* Enable the display of both time and space usage. */
+ display_time = 1;
+ display_space = 1;
+ break;
case 'f':
annotation_level = 1;
break;
BEFORE_MAIN_LOOP_HOOK;
#endif
+ /* Show time and/or space usage. */
+
+ if (display_time)
+ {
+ long init_time = get_run_time () - time_at_startup;
+
+ printf_unfiltered ("Startup time: %ld.%06ld\n",
+ init_time / 1000000, init_time % 1000000);
+ }
+
+ if (display_space)
+ {
+ extern char **environ;
+ char *lim = (char *) sbrk (0);
+
+ printf_unfiltered ("Startup size: data size %ld\n",
+ (long) (lim - (char *) &environ));
+ }
+
/* The command loop. */
while (1)
{
if (fputs_unfiltered_hook)
{
- fputs_unfiltered_hook (linebuffer);
+ /* FIXME: I think we should only be doing this for stdout or stderr.
+ Either that or we should be passing stream to the hook so it can
+ deal with it. If that is cleaned up, this function can go back
+ into utils.c and the fputs_unfiltered_hook can replace the current
+ ability to avoid this function by not linking with main.c. */
+ fputs_unfiltered_hook (linebuffer, stream);
return;
}
/* Called instead of fputs for all output. */
-void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer));
+void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer, FILE *stream));
/* Called from print_frame_info to list the line we stopped in. */
void (*call_command_hook) PARAMS ((struct cmd_list_element *c, char *cmd,
int from_tty));
+
+/* Takes control from error (). Typically used to prevent longjmps out of the
+ middle of the GUI. Usually used in conjunction with a catch routine. */
+
+NORETURN void (*error_hook) PARAMS (());
+
\f
/* Where to go for return_to_top_level (RETURN_ERROR). */
jmp_buf error_return;