diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a8e98c6ab4..70c689b0de 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,20 @@ +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 * breakpoint.c, infrun.c, printcmd.c: Change long command help diff --git a/gdb/defs.h b/gdb/defs.h index a0721ef263..835f877a51 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -33,6 +33,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* 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" @@ -138,28 +140,6 @@ extern int inside_main_func PARAMS ((CORE_ADDR pc)); 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 *)); @@ -544,19 +524,9 @@ extern PTR xmmalloc PARAMS ((PTR, long)); 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. */ @@ -862,7 +832,7 @@ extern CORE_ADDR push_word PARAMS ((CORE_ADDR, unsigned LONGEST)); 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 (()); @@ -884,6 +854,8 @@ extern int (*target_wait_hook) PARAMS ((int pid, 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; diff --git a/gdb/gdbtk.c b/gdb/gdbtk.c index 290ed644f1..4acf0f4aea 100644 --- a/gdb/gdbtk.c +++ b/gdb/gdbtk.c @@ -31,6 +31,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include +#include +#include "top.h" /* Non-zero means that we're doing the gdbtk interface. */ int gdbtk = 0; @@ -53,6 +55,70 @@ null_routine(arg) { } +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; +} /* This routine redirects the output of fputs_unfiltered so that the user can see what's going on in his debugger window. */ @@ -76,17 +142,37 @@ static void 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) @@ -122,43 +208,6 @@ gdbtk_query (args) return val; } -#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 - static void breakpoint_notify(b, action) struct breakpoint *b; @@ -420,22 +469,6 @@ gdb_regnames (clientData, interp, argc, argv) 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 @@ -462,9 +495,7 @@ get_register (regnum, fp) 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. */ @@ -479,10 +510,9 @@ get_register (regnum, fp) 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 @@ -552,15 +582,6 @@ gdb_changed_register_list (clientData, interp, argc, argv) return map_arg_registers (argc, argv, register_changed_p, NULL); } -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. */ @@ -571,40 +592,72 @@ gdb_cmd (clientData, interp, argc, argv) 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; @@ -740,16 +793,18 @@ gdbtk_init () 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_changed_register_list", - gdb_changed_register_list, NULL, NULL); + Tcl_CreateCommand (interp, "gdb_listfiles", call_wrapper, gdb_listfiles, + 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) diff --git a/gdb/gdbtk.tcl b/gdb/gdbtk.tcl index 97fec0eba0..f8ce86c8ec 100644 --- a/gdb/gdbtk.tcl +++ b/gdb/gdbtk.tcl @@ -8,6 +8,8 @@ set screen_top 0 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 @@ -46,6 +48,11 @@ proc gdbtk_tcl_fputs {arg} { $current_output_win yview -pickplace end } +proc gdbtk_tcl_fputs_error {arg} { + .cmd.text insert end "$arg" + .cmd.text yview -pickplace end +} + # # GDB Callback: # @@ -354,43 +361,52 @@ proc delete_breakpoint_tag {win line} { } 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 + } } # @@ -732,6 +748,7 @@ proc display_expression {expression} { 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. @@ -767,25 +784,32 @@ proc create_file_win {filename debug_file} { bind $win <1> do_nothing bind $win 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 @@ -873,12 +897,12 @@ proc create_asm_win {funcname pc} { bind $win {focus %W} bind $win <1> {asm_window_button_1 %W %X %Y %x %y} bind $win 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 @@ -1090,23 +1114,23 @@ proc create_asm_window {} { 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 @@ -1127,9 +1151,23 @@ proc reg_config_menu {} { set regnames [gdb_regnames] set num_regs [llength $regnames] - button .reg.config.done -text Done -command {destroy .reg.config} + frame .reg.config.buts - pack .reg.config.done -side bottom -fill x + 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 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. @@ -1151,10 +1189,7 @@ proc reg_config_menu {} { 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 @@ -1199,44 +1234,38 @@ proc create_registers_window {} { 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 @@ -1534,7 +1563,7 @@ proc build_framework {win {title GDBtk} {label {}}} { ${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 @@ -1598,36 +1627,53 @@ proc create_source_window {} { 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 \ @@ -1667,7 +1713,7 @@ proc create_command_window {} { %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) " diff --git a/gdb/main.c b/gdb/main.c index e7c8070a1c..228d62ce0c 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -41,6 +41,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #endif /* Temporary variable for SET_TOP_LEVEL. */ + static int top_level_val; /* Do a setjmp on error_return and quit_return. catch_errors is @@ -52,6 +53,14 @@ static int top_level_val; ? (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 @@ -93,6 +102,8 @@ main (argc, argv) 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. */ @@ -174,13 +185,16 @@ main (argc, argv) {"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) @@ -212,6 +226,11 @@ main (argc, argv) /* 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; @@ -522,6 +541,25 @@ GDB manual (available as on-line info or a printed manual).\n", gdb_stdout); 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) @@ -570,7 +608,12 @@ fputs_unfiltered (linebuffer, stream) { 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; } diff --git a/gdb/top.c b/gdb/top.c index 17e85c0236..8109f51606 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -354,7 +354,7 @@ void (*command_loop_hook) PARAMS ((void)); /* 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. */ @@ -391,6 +391,12 @@ int (*target_wait_hook) PARAMS ((int pid, struct target_waitstatus *status)); 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 (()); + /* Where to go for return_to_top_level (RETURN_ERROR). */ jmp_buf error_return;