diff --git a/gdb/ChangeLog b/gdb/ChangeLog index aabc9712b57..55931d563fb 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,33 @@ +Thu Oct 20 17:35:45 1994 Stu Grossman (grossman@cygnus.com) + + * defs.h, infrun.c (wait_for_inferior), top.c: Call + target_wait_hook to allow GUI to handle blocking for inferior. Call + call_command_hook in execute_command to provide means for wrapping + commands with GUI state change updates. + * gdbtk.c (gdb_cmd): Force GUI into idle mode when errors occur. + * (gdb_stop): New tcl command to stop the target process. + * (x_event, gdbtk_wait): Allow GUI to interrupt gdb out of target + waits. + * (gdbtk_call_command): Wrapper around command processing to + alert GUI of target state changes. + * (gdbtk_init): Get the fd of X server for doing async + notification of X events (via x_event). Setup new hooks. + * gdbtk.tcl: Add scrollbars to assembly and command windows. + * Change window foreground & background colors. + * Create margin tag for breakpoints in source and assembly windows. + * Add new routines to be invoked when target state changes to/from + idle. + * Add start of expression window. + * Change bindings of mouse button 1 in assembly and source window + to just set or clear breakpoints when in the margin tag. + * Change shape of register window to be more vertical to better + reflect it's contents. + * Add stop button. + * Cleanup some code around command window bindings. + + * infrun.c (wait_for_inferior): Make sure + through_sigtramp_breakpoint is non-null before deleting. + Thu Oct 20 10:26:43 1994 J.T. Conklin (jtc@phishhead.cygnus.com) * config/powerpc/ppc-nw.mt (TDEPFILES): Removed exec.o. diff --git a/gdb/defs.h b/gdb/defs.h index ada622338f6..1bba0bdbc6f 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -689,7 +689,7 @@ extern char *strerror PARAMS ((int)); /* 4.11.6.2 */ # endif /* Not GNU C */ #endif /* alloca not defined */ -/* TARGET_BYTE_ORDER and HOST_BYTE_ORDER must be defined to one of these. */ +/* HOST_BYTE_ORDER must be defined to one of these. */ #if !defined (BIG_ENDIAN) #define BIG_ENDIAN 4321 @@ -706,6 +706,17 @@ extern char *strerror PARAMS ((int)); /* 4.11.6.2 */ #include "tm.h" +#ifdef TARGET_BYTE_ORDER_SELECTABLE +/* The target endianness is selectable at runtime. Define + TARGET_BYTE_ORDER to be a variable. The user can use the `set + endian' command to change it. */ +#undef TARGET_BYTE_ORDER +#define TARGET_BYTE_ORDER target_byte_order +extern int target_byte_order; +#endif + +extern void set_endian_from_file PARAMS ((bfd *)); + /* Number of bits in a char or unsigned char for the target machine. Just like CHAR_BIT in but describes the target machine. */ #if !defined (TARGET_CHAR_BIT) @@ -778,6 +789,8 @@ extern char *strerror PARAMS ((int)); /* 4.11.6.2 */ from byte/word byte order. */ #if !defined (BITS_BIG_ENDIAN) +#ifndef TARGET_BYTE_ORDER_SELECTABLE + #if TARGET_BYTE_ORDER == BIG_ENDIAN #define BITS_BIG_ENDIAN 1 #endif /* Big endian. */ @@ -785,6 +798,12 @@ extern char *strerror PARAMS ((int)); /* 4.11.6.2 */ #if TARGET_BYTE_ORDER == LITTLE_ENDIAN #define BITS_BIG_ENDIAN 0 #endif /* Little endian. */ + +#else /* defined (TARGET_BYTE_ORDER_SELECTABLE) */ + +#define BITS_BIG_ENDIAN (TARGET_BYTE_ORDER == BIG_ENDIAN) + +#endif /* defined (TARGET_BYTE_ORDER_SELECTABLE) */ #endif /* BITS_BIG_ENDIAN not defined. */ /* In findvar.c. */ @@ -854,6 +873,17 @@ extern void (*enable_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); extern void (*disable_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); extern void (*interactive_hook) PARAMS ((void)); +#ifdef __STDC__ +struct target_waitstatus; +struct cmd_list_element; +#endif + +extern int (*target_wait_hook) PARAMS ((int pid, + struct target_waitstatus *status)); + +extern void (*call_command_hook) PARAMS ((struct cmd_list_element *c, + char *cmd, int from_tty)); + /* Inhibit window interface if non-zero. */ extern int no_windows; diff --git a/gdb/gdbtk.c b/gdb/gdbtk.c index 9843b430774..e96ea19d1d5 100644 --- a/gdb/gdbtk.c +++ b/gdb/gdbtk.c @@ -54,6 +54,8 @@ static Tcl_Interp *interp = NULL; /* Handle for TK main window */ static Tk_Window mainWindow = NULL; +static int x_fd; /* X network socket */ + static void null_routine(arg) int arg; @@ -336,6 +338,12 @@ gdb_cmd (clientData, interp, argc, argv) 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); + bpstat_do_actions (&stop_bpstat); do_cleanups (old_chain); @@ -367,6 +375,22 @@ gdb_listfiles (clientData, interp, argc, argv) return TCL_OK; } + +static int +gdb_stop (clientData, interp, argc, argv) + ClientData clientData; + Tcl_Interp *interp; + int argc; + char *argv[]; +{ + extern pid_t inferior_process_group; + + /* XXX - This is WRONG for remote targets. Probably need a target vector + entry to do this right. */ + + kill (-inferior_process_group, SIGINT); +} + static void tk_command (cmd, from_tty) @@ -401,11 +425,59 @@ gdbtk_interactive () /* Tk_DoOneEvent (TK_DONT_WAIT|TK_IDLE_EVENTS); */ } +/* Come here when there is activity on the X file descriptor. */ + +static void +x_event (signo) + int signo; +{ + /* Process pending events */ + + while (Tk_DoOneEvent (TK_DONT_WAIT|TK_ALL_EVENTS) != 0); +} + +static int +gdbtk_wait (pid, ourstatus) + int pid; + struct target_waitstatus *ourstatus; +{ + signal (SIGIO, x_event); + + pid = target_wait (pid, ourstatus); + + signal (SIGIO, SIG_IGN); + + return pid; +} + +/* This is called from execute_command, and provides a wrapper around + various command routines in a place where both protocol messages and + user input both flow through. Mostly this is used for indicating whether + the target process is running or not. +*/ + +static void +gdbtk_call_command (cmdblk, arg, from_tty) + struct cmd_list_element *cmdblk; + char *arg; + int from_tty; +{ + if (cmdblk->class == class_run) + { + Tcl_VarEval (interp, "gdbtk_tcl_busy", NULL); + (*cmdblk->function.cfunc)(arg, from_tty); + Tcl_VarEval (interp, "gdbtk_tcl_idle", NULL); + } + else + (*cmdblk->function.cfunc)(arg, from_tty); +} + static void gdbtk_init () { struct cleanup *old_chain; char *gdbtk_filename; + int i; old_chain = make_cleanup (cleanup_init, 0); @@ -430,6 +502,7 @@ gdbtk_init () Tcl_CreateCommand (interp, "gdb_cmd", gdb_cmd, NULL, NULL); Tcl_CreateCommand (interp, "gdb_loc", gdb_loc, NULL, NULL); Tcl_CreateCommand (interp, "gdb_listfiles", gdb_listfiles, NULL, NULL); + Tcl_CreateCommand (interp, "gdb_stop", gdb_stop, NULL, NULL); gdbtk_filename = getenv ("GDBTK_FILENAME"); if (!gdbtk_filename) @@ -441,6 +514,19 @@ gdbtk_init () if (Tcl_EvalFile (interp, gdbtk_filename) != TCL_OK) error ("Failure reading %s: %s", gdbtk_filename, interp->result); + /* XXX - Get the file descriptor for the network socket. This is not Kosher + as it involves looking at data private to Xlib. */ + + x_fd = Tk_Display (mainWindow) -> fd; + + /* Setup for I/O interrupts */ + + signal (SIGIO, SIG_IGN); + + i = fcntl (x_fd, F_GETFL, 0); + fcntl (x_fd, F_SETFL, i|FASYNC); + fcntl (x_fd, F_SETOWN, getpid()); + command_loop_hook = Tk_MainLoop; fputs_unfiltered_hook = gdbtk_fputs; print_frame_info_listing_hook = null_routine; @@ -451,6 +537,8 @@ gdbtk_init () enable_breakpoint_hook = gdbtk_enable_breakpoint; disable_breakpoint_hook = gdbtk_disable_breakpoint; interactive_hook = gdbtk_interactive; + target_wait_hook = gdbtk_wait; + call_command_hook = gdbtk_call_command; discard_cleanups (old_chain); diff --git a/gdb/gdbtk.tcl b/gdb/gdbtk.tcl index 9f52096e496..08e7c4bc21b 100644 --- a/gdb/gdbtk.tcl +++ b/gdb/gdbtk.tcl @@ -8,10 +8,8 @@ set screen_top 0 set screen_bot 0 set current_output_win .command.text set cfunc NIL - -proc test {} { - update_listing {termcap.c foo /etc/termcap 200} -} +option add *Foreground White +option add *Background Blue proc echo string {puts stdout $string} @@ -322,6 +320,8 @@ proc insert_breakpoint_tag {win line} { $win delete $line.0 $win insert $line.0 "B" $win tag add $line $line.0 + $win tag add delete $line.0 "$line.0 lineend" + $win tag add margin $line.0 "$line.0 lineend" $win configure -state disabled } @@ -342,9 +342,57 @@ proc delete_breakpoint_tag {win line} { $win delete $line.0 $win insert $line.0 " " $win tag delete $line + $win tag add delete $line.0 "$line.0 lineend" + $win tag add margin $line.0 "$line.0 lineend" $win configure -state disabled } +proc gdbtk_tcl_busy {} { + .start configure -state disabled + .stop configure -state normal + .step configure -state disabled + .next configure -state disabled + .continue configure -state disabled + .finish configure -state disabled + .exit configure -state disabled + .up configure -state disabled + .down configure -state disabled + .bottom configure -state disabled + .asm_but configure -state disabled + .registers 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 +} + +proc gdbtk_tcl_idle {} { + .start configure -state normal + .stop configure -state disabled + .step configure -state normal + .next configure -state normal + .continue configure -state normal + .finish configure -state normal + .exit configure -state normal + .up configure -state normal + .down configure -state normal + .bottom configure -state normal + .asm_but configure -state normal + .registers 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 +} + # # Local procedure: # @@ -620,6 +668,49 @@ proc asm_window_button_1 {win x y xrel yrel} { proc do_nothing {} {} +# +# Local procedure: +# +# create_expr_win - Creat expression display window +# +# Description: +# +# Create the expression display window. +# + +proc create_expr_win {} { + toplevel .expr + wm minsize .expr 1 1 + wm title .expr Expression + canvas .expr.c -yscrollcommand {.expr.scroll set} -cursor hand2 \ + -borderwidth 2 -relief groove + scrollbar .expr.scroll -orient vertical -command {.expr.c yview} + entry .expr.entry -borderwidth 2 -relief groove + + pack .expr.entry -side bottom -fill x + pack .expr.c -side left -fill both -expand yes + pack .expr.scroll -side right -fill y + + .expr.c create text 100 0 -text "Text string" + .expr.c create rectangle 245 195 255 205 -outline black -fill white +} + +# +# Local procedure: +# +# display_expression (expression) - Display EXPRESSION in display window +# +# Description: +# +# Display EXPRESSION and it's value in the expression display window. +# + +proc display_expression {expression} { + if ![winfo exists .expr] {create_expr_win} + + +} + # # Local procedure: # @@ -669,8 +760,10 @@ proc create_file_win {filename} { # Setup all the bindings bind $win {focus %W} - bind $win <1> {listing_window_button_1 %W %X %Y %x %y} +# bind $win <1> {listing_window_button_1 %W %X %Y %x %y} + 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} @@ -688,8 +781,36 @@ proc create_file_win {filename} { set numlines [lindex [split $numlines .] 0] for {set i 1} {$i <= $numlines} {incr i} { $win insert $i.0 [format " %4d " $i] + $win tag add margin $i.0 $i.8 + $win tag add source $i.8 "$i.0 lineend" } + $win tag bind margin <1> {listing_window_button_1 %W %X %Y %x %y} + $win tag bind source <1> { + %W mark set anchor "@%x,%y wordstart" + set last [%W index "@%x,%y wordend"] + %W tag remove sel 0.0 anchor + %W tag remove sel $last end + %W tag add sel anchor $last + } +# $win tag bind source { +# %W mark set anchor "@%x,%y wordstart" +# set last [%W index "@%x,%y wordend"] +# %W tag remove sel 0.0 anchor +# %W tag remove sel $last end +# %W tag add sel anchor $last +# echo "Selected [selection get]" +# } + $win tag bind source { + %W tag remove sel 0.0 anchor + %W tag remove sel $last end + %W tag add sel anchor @%x,%y + } + $win tag bind sel <1> do_nothing + $win tag bind sel {display_expression [selection get]} + $win tag raise sel + + # Scan though the breakpoint data base and install any destined for this file foreach bpnum [array names breakpoint_file] { @@ -963,7 +1084,8 @@ proc asm_command {} { text $win -height 25 -width 80 -relief raised -borderwidth 2 \ -setgrid true -cursor hand2 \ -yscrollcommand asmscrollproc - scrollbar .asm.scroll -orient vertical -command {$win yview} + scrollbar .asm.scroll -orient vertical \ + -command {[asm_win_name $cfunc] yview} frame .asm.buts button .asm.stepi -text Stepi \ @@ -1011,7 +1133,7 @@ proc registers_command {} { wm title .reg Registers set win .reg.regs - text $win -height 25 -width 80 -relief raised \ + text $win -height 41 -width 45 -relief raised \ -borderwidth 2 \ -setgrid true -cursor hand2 @@ -1044,7 +1166,7 @@ proc update_registers {} { gdb_cmd "info registers" set current_output_win .command.text - $win yview 1 + $win yview 0 $win configure -state disabled } @@ -1209,6 +1331,7 @@ button .start -text Start -command \ gdb_cmd {enable delete $bpnum} gdb_cmd run update_ptr } +button .stop -text Stop -fg red -activeforeground red -state disabled -command gdb_stop button .step -text Step -command {gdb_cmd step ; update_ptr} button .next -text Next -command {gdb_cmd next ; update_ptr} button .continue -text Continue -command {gdb_cmd continue ; update_ptr} @@ -1243,7 +1366,7 @@ button .files -text Files -command files_command pack .listing -side bottom -fill both -expand yes #pack .test -side bottom -fill x -pack .start .step .next .continue .finish .up .down .bottom .asm_but \ +pack .start .stop .step .next .continue .finish .up .down .bottom .asm_but \ .registers .files .exit -side left toplevel .command wm title .command Command @@ -1251,10 +1374,12 @@ wm title .command Command # Setup command window label .command.label -text "* Command Buffer *" -borderwidth 2 -relief raised -text .command.text -height 25 -width 80 -relief raised -borderwidth 2 -setgrid true -cursor hand2 +text .command.text -height 25 -width 80 -relief raised -borderwidth 2 -setgrid true -cursor hand2 -yscrollcommand {.command.scroll set} +scrollbar .command.scroll -orient vertical -command {.command.text yview} pack .command.label -side top -fill x -pack .command.text -side top -expand yes -fill both +pack .command.text -side left -expand yes -fill both +pack .command.scroll -side right -fill y set command_line {} @@ -1262,6 +1387,10 @@ gdb_cmd {set language c} gdb_cmd {set height 0} gdb_cmd {set width 0} +bind .command.text {focus %W} +bind .command.text {delete_char %W} +bind .command.text {delete_char %W} +bind .command.text {delete_line %W} bind .command.text { global command_line @@ -1280,10 +1409,7 @@ bind .command.text { %W insert end "(gdb) " %W yview -pickplace end } -bind .command.text {focus %W} -bind .command.text {delete_char %W} -bind .command.text {delete_char %W} -bind .command.text {delete_line %W} + proc delete_char {win} { global command_line diff --git a/gdb/infrun.c b/gdb/infrun.c index 9a9e35c7e08..fd3bf0aaad3 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -308,7 +308,7 @@ proceed (addr, siggnal, step) breakpoint to be hit again, but you can always continue, so it's not a big deal.) */ - if (! step && PREPARE_TO_PROCEED && breakpoint_here_p (read_pc ())) + if (! step && PREPARE_TO_PROCEED (1) && breakpoint_here_p (read_pc ())) oneproc = 1; #endif /* PREPARE_TO_PROCEED */ @@ -362,10 +362,8 @@ The same program may be running in another process."); to be preserved over calls to it and cleared when the inferior is started. */ static CORE_ADDR prev_pc; -static CORE_ADDR prev_sp; static CORE_ADDR prev_func_start; static char *prev_func_name; -static CORE_ADDR prev_frame_address; /* Start remote-debugging of a machine over a serial link. */ @@ -388,10 +386,8 @@ init_wait_for_inferior () { /* These are meaningless until the first time through wait_for_inferior. */ prev_pc = 0; - prev_sp = 0; prev_func_start = 0; prev_func_name = NULL; - prev_frame_address = 0; trap_expected_after_continue = 0; breakpoints_inserted = 0; @@ -423,7 +419,6 @@ wait_for_inferior () struct target_waitstatus w; int another_trap; int random_signal; - CORE_ADDR stop_sp = 0; CORE_ADDR stop_func_start; CORE_ADDR stop_func_end; char *stop_func_name; @@ -436,6 +431,7 @@ wait_for_inferior () struct breakpoint *step_resume_breakpoint = NULL; struct breakpoint *through_sigtramp_breakpoint = NULL; int pid; + int update_step_sp = 0; old_cleanups = make_cleanup (delete_breakpoint_current_contents, &step_resume_breakpoint); @@ -462,7 +458,10 @@ wait_for_inferior () registers_changed (); - pid = target_wait (-1, &w); + if (target_wait_hook) + pid = target_wait_hook (-1, &w); + else + pid = target_wait (-1, &w); flush_cached_frames (); @@ -473,6 +472,17 @@ wait_for_inferior () { fprintf_unfiltered (gdb_stderr, "[New %s]\n", target_pid_to_str (pid)); add_thread (pid); + + /* We may want to consider not doing a resume here in order to give + the user a chance to play with the new thread. It might be good + to make that a user-settable option. */ + + /* At this point, all threads are stopped (happens automatically in + either the OS or the native code). Therefore we need to continue + all threads in order to make progress. */ + + target_resume (-1, 0, TARGET_SIGNAL_0); + continue; } switch (w.kind) @@ -498,8 +508,7 @@ wait_for_inferior () printf_filtered ("\nProgram exited with code 0%o.\n", (unsigned int)w.value.integer); else - if (!batch_mode()) - printf_filtered ("\nProgram exited normally.\n"); + printf_filtered ("\nProgram exited normally.\n"); gdb_flush (gdb_stdout); target_mourn_inferior (); #ifdef NO_SINGLE_STEP @@ -559,7 +568,11 @@ wait_for_inferior () target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */ /* FIXME: What if a signal arrives instead of the single-step happening? */ - target_wait (pid, &w); + + if (target_wait_hook) + target_wait_hook (pid, &w); + else + target_wait (pid, &w); insert_breakpoints (); target_resume (pid, 0, TARGET_SIGNAL_0); continue; @@ -630,7 +643,6 @@ wait_for_inferior () through_sigtramp_breakpoint = NULL; } prev_pc = 0; - prev_sp = 0; prev_func_name = NULL; step_range_start = 0; step_range_end = 0; @@ -654,9 +666,6 @@ wait_for_inferior () continue; } - set_current_frame (create_new_frame (read_fp (), stop_pc)); - select_frame (get_current_frame (), 0); - #ifdef HAVE_STEPPABLE_WATCHPOINT /* It may not be necessary to disable the watchpoint to stop over it. For example, the PA can (with some kernel cooperation) @@ -696,8 +705,6 @@ wait_for_inferior () STOPPED_BY_WATCHPOINT (w); #endif - stop_frame_address = FRAME_FP (get_current_frame ()); - stop_sp = read_sp (); stop_func_start = 0; stop_func_name = 0; /* Don't care about return value; stop_func_start and stop_func_name @@ -758,7 +765,7 @@ wait_for_inferior () { /* See if there is a breakpoint at the current PC. */ stop_bpstat = bpstat_stop_status - (&stop_pc, stop_frame_address, + (&stop_pc, #if DECR_PC_AFTER_BREAK /* Notice the case of stepping through a jump that lands just after a breakpoint. @@ -782,7 +789,8 @@ wait_for_inferior () = !(bpstat_explains_signal (stop_bpstat) || trap_expected #ifndef CALL_DUMMY_BREAKPOINT_OFFSET - || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) + || PC_IN_CALL_DUMMY (stop_pc, read_sp (), + FRAME_FP (get_current_frame ())) #endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ || (step_range_end && step_resume_breakpoint == NULL)); else @@ -793,7 +801,8 @@ wait_for_inferior () news) give another signal besides SIGTRAP, so check here as well as above. */ #ifndef CALL_DUMMY_BREAKPOINT_OFFSET - || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) + || PC_IN_CALL_DUMMY (stop_pc, read_sp (), + FRAME_FP (get_current_frame ())) #endif /* No CALL_DUMMY_BREAKPOINT_OFFSET. */ ); if (!random_signal) @@ -904,7 +913,7 @@ wait_for_inferior () #if 0 /* FIXME - Need to implement nested temporary breakpoints */ if (step_over_calls - && (stop_frame_address + && (FRAME_FP (get_current_frame ()) INNER_THAN step_frame_address)) { another_trap = 1; @@ -950,7 +959,8 @@ wait_for_inferior () break; case BPSTAT_WHAT_THROUGH_SIGTRAMP: - delete_breakpoint (through_sigtramp_breakpoint); + if (through_sigtramp_breakpoint) + delete_breakpoint (through_sigtramp_breakpoint); through_sigtramp_breakpoint = NULL; /* If were waiting for a trap, hitting the step_resume_break @@ -983,7 +993,7 @@ wait_for_inferior () just stop silently, unless the user was doing an si/ni, in which case she'd better know what she's doing. */ - if (PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address) + if (PC_IN_CALL_DUMMY (stop_pc, read_sp (), FRAME_FP (get_current_frame ())) && !step_range_end) { stop_print_frame = 0; @@ -1017,17 +1027,21 @@ wait_for_inferior () step range and either the stack or frame pointers just changed, we've stepped outside */ && !(stop_pc == step_range_start - && stop_frame_address - && (stop_sp INNER_THAN prev_sp - || stop_frame_address != step_frame_address))) + && FRAME_FP (get_current_frame ()) + && (read_sp () INNER_THAN step_sp + || FRAME_FP (get_current_frame ()) != step_frame_address))) { /* We might be doing a BPSTAT_WHAT_SINGLE and getting a signal. So definately need to check for sigtramp here. */ goto check_sigtramp2; } - /* We stepped out of the stepping range. See if that was due - to a subroutine call that we should proceed to the end of. */ + /* We stepped out of the stepping range. */ + + /* We can't update step_sp every time through the loop, because + reading the stack pointer would slow down stepping too much. + But we can update it every time we leave the step range. */ + update_step_sp = 1; /* Did we just take a signal? */ if (IN_SIGTRAMP (stop_pc, stop_func_name) @@ -1052,8 +1066,7 @@ wait_for_inferior () sr_sal.symtab = NULL; sr_sal.line = 0; /* We could probably be setting the frame to - prev_frame_address; the reason we don't is that it didn't used - to exist. */ + step_frame_address; I don't think anyone thought to try it. */ step_resume_breakpoint = set_momentary_breakpoint (sr_sal, NULL, bp_step_resume); if (breakpoints_inserted) @@ -1073,6 +1086,9 @@ wait_for_inferior () } #if 1 + /* See if we left the step range due to a subroutine call that + we should proceed to the end of. */ + if (stop_func_start) { struct symtab *s; @@ -1096,7 +1112,7 @@ wait_for_inferior () /* Might be a recursive call if either we have a prologue or the call instruction itself saves the PC on the stack. */ || prologue_pc != stop_func_start - || stop_sp != prev_sp) + || read_sp () != step_sp) && (/* PC is completely out of bounds of any known objfiles. Treat like a subroutine call. */ ! stop_func_start @@ -1112,6 +1128,16 @@ wait_for_inferior () || stop_pc < prologue_pc + /* ...and if it is a leaf function, the prologue might + consist of gp loading only, so the call transfers to + the first instruction after the prologue. */ + || (stop_pc == prologue_pc + + /* Distinguish this from the case where we jump back + to the first instruction after the prologue, + within a function. */ + && stop_func_start != prev_func_start) + /* If we end up in certain places, it means we did a subroutine call. I'm not completely sure this is necessary now that we have the above checks with stop_func_start (and now that @@ -1183,7 +1209,7 @@ step_over_function: step_resume_breakpoint = set_momentary_breakpoint (sr_sal, get_current_frame (), bp_step_resume); - step_resume_breakpoint->frame = prev_frame_address; + step_resume_breakpoint->frame = step_frame_address; if (breakpoints_inserted) insert_breakpoints (); } @@ -1341,8 +1367,10 @@ step_into_function: been at the start of a function. */ prev_func_name = stop_func_name; - prev_sp = stop_sp; - prev_frame_address = stop_frame_address; + + if (update_step_sp) + step_sp = read_sp (); + update_step_sp = 0; /* If we did not do break;, it means we should keep running the inferior and not return to debugger. */ @@ -1417,8 +1445,6 @@ step_into_function: prev_pc = read_pc (); prev_func_start = stop_func_start; prev_func_name = stop_func_name; - prev_sp = stop_sp; - prev_frame_address = stop_frame_address; } do_cleanups (old_cleanups); } @@ -1492,6 +1518,8 @@ Further execution is probably impossible.\n"); if we have one. */ if (!stop_stack_dummy) { + select_frame (get_current_frame (), 0); + if (stop_print_frame) { int source_only; @@ -1499,7 +1527,7 @@ Further execution is probably impossible.\n"); source_only = bpstat_print (stop_bpstat); source_only = source_only || ( stop_step - && step_frame_address == stop_frame_address + && step_frame_address == FRAME_FP (get_current_frame ()) && step_start_function == find_pc_function (stop_pc)); print_stack_frame (selected_frame, -1, source_only? -1: 1); @@ -1828,7 +1856,6 @@ save_inferior_status (inf_status, restore_stack_info) { inf_status->stop_signal = stop_signal; inf_status->stop_pc = stop_pc; - inf_status->stop_frame_address = stop_frame_address; inf_status->stop_step = stop_step; inf_status->stop_stack_dummy = stop_stack_dummy; inf_status->stopped_by_random_signal = stopped_by_random_signal; @@ -1898,7 +1925,6 @@ restore_inferior_status (inf_status) { stop_signal = inf_status->stop_signal; stop_pc = inf_status->stop_pc; - stop_frame_address = inf_status->stop_frame_address; stop_step = inf_status->stop_step; stop_stack_dummy = inf_status->stop_stack_dummy; stopped_by_random_signal = inf_status->stopped_by_random_signal; diff --git a/gdb/top.c b/gdb/top.c index bf185b46343..9679f58962c 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -379,6 +379,16 @@ void (*disable_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); void (*interactive_hook) PARAMS ((void)); +/* Called when going to wait for the target. Usually allows the GUI to run + while waiting for target events. */ + +int (*target_wait_hook) PARAMS ((int pid, struct target_waitstatus *status)); + +/* Used by UI as a wrapper around command execution. May do various things + like enabling/disabling buttons, etc... */ + +void (*call_command_hook) PARAMS ((struct cmd_list_element *c, char *cmd, + int from_tty)); /* Where to go for return_to_top_level (RETURN_ERROR). */ jmp_buf error_return; @@ -858,6 +868,8 @@ execute_command (p, from_tty) do_setshow_command (arg, from_tty & caution, c); else if (c->function.cfunc == NO_FUNCTION) error ("That is not a command, just a help topic."); + else if (call_command_hook) + call_command_hook (c, arg, from_tty & caution); else (*c->function.cfunc) (arg, from_tty & caution); }