diff options
author | Jason Molenda <jmolenda@apple.com> | 1999-07-05 17:58:44 +0000 |
---|---|---|
committer | Jason Molenda <jmolenda@apple.com> | 1999-07-05 17:58:44 +0000 |
commit | 43ff13b4182f3853e19e9100c84313a6e9302b70 (patch) | |
tree | a546b011131cdb9e4d6200dd1f2b9432ffa01539 /gdb | |
parent | f11523b01363bac4f0b7384c30fee355e9943b99 (diff) | |
download | fsf-binutils-gdb-43ff13b4182f3853e19e9100c84313a6e9302b70.zip fsf-binutils-gdb-43ff13b4182f3853e19e9100c84313a6e9302b70.tar.gz fsf-binutils-gdb-43ff13b4182f3853e19e9100c84313a6e9302b70.tar.bz2 |
import gdb-1999-07-05 snapshot
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 201 | ||||
-rw-r--r-- | gdb/Makefile.in | 7 | ||||
-rw-r--r-- | gdb/blockframe.c | 14 | ||||
-rw-r--r-- | gdb/breakpoint.c | 76 | ||||
-rw-r--r-- | gdb/config/mn10300/tm-mn10300.h | 3 | ||||
-rw-r--r-- | gdb/configure.host | 2 | ||||
-rw-r--r-- | gdb/defs.h | 39 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 4 | ||||
-rw-r--r-- | gdb/doc/gdbint.texinfo | 6 | ||||
-rw-r--r-- | gdb/event-loop.c | 16 | ||||
-rw-r--r-- | gdb/event-loop.h | 5 | ||||
-rw-r--r-- | gdb/event-top.c | 103 | ||||
-rw-r--r-- | gdb/frame.h | 1 | ||||
-rw-r--r-- | gdb/infcmd.c | 377 | ||||
-rw-r--r-- | gdb/inferior.h | 13 | ||||
-rw-r--r-- | gdb/infrun.c | 123 | ||||
-rw-r--r-- | gdb/main.c | 3 | ||||
-rw-r--r-- | gdb/mn10300-tdep.c | 4 | ||||
-rw-r--r-- | gdb/remote-os9k.c | 9 | ||||
-rw-r--r-- | gdb/remote-sim.c | 10 | ||||
-rw-r--r-- | gdb/remote-st.c | 9 | ||||
-rw-r--r-- | gdb/remote.c | 676 | ||||
-rw-r--r-- | gdb/ser-tcp.c | 6 | ||||
-rw-r--r-- | gdb/ser-unix.c | 6 | ||||
-rw-r--r-- | gdb/source.c | 2 | ||||
-rw-r--r-- | gdb/sparcl-tdep.c | 6 | ||||
-rw-r--r-- | gdb/target.c | 1 | ||||
-rw-r--r-- | gdb/target.h | 5 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/lib/gdb.exp | 50 | ||||
-rw-r--r-- | gdb/top.c | 23 | ||||
-rw-r--r-- | gdb/top.h | 1 | ||||
-rw-r--r-- | gdb/utils.c | 54 | ||||
-rw-r--r-- | gdb/valops.c | 4 |
34 files changed, 1715 insertions, 149 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f41bc52..ac6d4d2 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,203 @@ +1999-07-05 Jason Molenda (jsm@bugshack.cygnus.com) + + * remote.c: Include <sys/select.h> if it exists in order to pick up + FD_SET et al defns. + * remote-os9k.c: Same. + * remote-st.c: Same. + * ser-tcp.c: Same. + * ser-unix.c: Same. + * sparcl-tdep.c: Same. + +Fri Jul 2 19:38:43 1999 Andrew Cagney <cagney@b1.cygnus.com> + + * top.c (target_output_hook): Delete definition. + * defs.h (target_output_hook): Delete declaration. + + * remote.c (remote_console_output): Delete call to + target_output_hook(). Send target output to gdb_stdtarg using an + unfiltered write. Make more robust. + + * remote-sim.c (gdb_os_write_stdout, gdb_os_write_stderr): + Ditto. For moment, do not try to separate target stdout and stderr + streams. + + * defs.h (gdb_stdtarg): New global. Output from target and + simulators. + +1999-07-02 Elena Zannoni <ezannoni@kwikemart.cygnus.com> + + * top.c (return_to_top_level): Do all the exec_cleanups too. + + * event-top.c (command_handler): Set up for a continuation, if we + are in the middle of running an execution command which will + finish later on. Do cleanups, an display of time/space only if not + running with an async target or not running an execution command. + (command_line_handler_continuation): New function. Continuation + for command_line_handler. + + * utils.c (exec_cleanup_chain): New cleanup chain to be used in + async mode for the execution commands. + (make_exec_cleanup): New function. Add a cleanup to the + exec_cleanup_chain. + (do_exec_cleanups): New Function. Do cleanups on the + exec_cleanup_chain. + (add_continuation): New function. Add a new continuation to the + cmd_continuation list. + (do_all_continuations): New function. Do all the continuations on + the cmd_continuation list. + + * top.h (ALL_CLEANUPS): Move from here to defs.h. + + * defs.h (struct continuation_arg): New structure. Arg to pass to + the call to a command continuation. + (struct continuation): New structure. Continuation for an + execution command. + (ALL_CLEANUPS): Move here from top.h. + + * remote.c (remote_async_open_1): Set things up for telling the + target we are running the extended protocol, only after the target + has stopped. + (set_extended_protocol): New function. Tell the target we are + using the extended protocol. + (remote_async_resume): Set things up for sync execution only if + this is the first time we are called. + + * breakpoint.c (until_break_command_continuation): New function. + Stuff to be done after the target stops during the 'until' + command. + (until_break_command): Set things up for completing the 'until' + command later on. Do the final cleanups only if not running + asynchronously or async execution is not supported by the target. + + * infcmd.c (until_command): Recognize '&' at end of command and + handle it properly. + (finish_command_continuation): New function. Do whatever is needed + after the target has stopped. + (finish_command): Recognize '&' at end of command and handle it + properly. Don't do stuff needed after target has stopped if + running asynchronously and target has async. Use exec_cleanup_chain + if running asynchronously and target is asynchronous. + + * infrun.c (cmd_continuation): New gloabl variable. Used to + coplete execution commands in async mode, after the target has + stoped. + (fetch_inferior_event): Use exec_cleanup_chain, instead of + cleanup_chain. Do all the exec cleanups at the end. Do all the + continuations at the end. Call complete_execution from here, + instead of normal_stop. + (complete_execution): Cleanup the signals handlers for SIGINT + before displaying the prompt. + (start_remote): Set target_executing to 1. + (normal_stop): Don't call complete_execution from here. + +Thu Jul 1 19:14:30 1999 Andrew Cagney <cagney@b1.cygnus.com> + + * blockframe.c (struct dummy_frame): Add member ``top''. + (generic_push_dummy_frame): Initialize top to sp. + (generic_save_dummy_frame_tos): New function. Initialize top. + (generic_find_dummy_frame): Check for the top of the frame. + + * blockframe.c (generic_push_dummy_frame): Free the dummy_frame + registers. + + * config/mn10300/tm-mn10300.h (SAVE_DUMMY_FRAME_TOS): Define. + (TARGET_READ_FP): Return the SP as a best guess. + +Wed Jun 30 15:45:48 1999 Jeffrey A Law (law@cygnus.com) + + * configure.host (hppa*-*-hpux11*): Accept any version of hpux11 + instead of hpux11.0*. + +1999-06-30 Fernando Nasser <fnasser@totem.to.cygnus.com> + + * source.c (directory_command): Add missing test for from_tty. + +1999-06-29 Elena Zannoni <ezannoni@kwikemart.cygnus.com> + + * remote.c: Include event-loop.h. + (remote_async_ops, extended_async_remote_ops): Define new target + vector structures for asynchronous debugging. + (remote_async_open): New function. Asynchronous version of + remote_open. + (extended_remote_async_open): New function. Asynchronous version + of extended_remote_open. + (remote_async_open_1): New function. Async version of + remote_open_1. + (remote_async_detach): New function. Async version of + remote_detach. + (remote_async_resume): New function. Async version of + remote_resume. + (initialize_sigint_signal_handler, handle_remote_sigint, + handle_remote_sigint_twice, async_remote_interrupt, + async_remote_interrupt_twice, cleanup_sigint_signal_handler): New + functions. Used for handling ^C while target is running. + (remote_async_wait): New function. Async version of remote_wait. + (remote_async_kill): New function. Async version of remote_kill. + (extended_remote_async_create_inferior): New function. Async + version of extended_remote_create_inferior. + (init_remote_async_ops): New function. Initialize target vector + for target async. + (init_extended_async_remote_ops): New function. Initialize target + vector for target extended-async. + (_initialize_remote): Initialize remote_async_ops and + extended_async_remote_ops. + + * infrun.c: Include "event-loop.h". + (sync_execution): new global variable. + (proceed): Invoke wait_for_inferior and normal_stop only if not + running in async mode or if target doesn't support async + execution. + (start_remote): Don't call wait_for_inferior and normal_stop if + not running in async mode or if target not async. If running async + and target is async, start the target in simulated synchronous + mode. + (async_ecss, async_ecs): New global vars, for inferior state. + (fetch_inferior_event): New function. Async version of + wait_for_inferior. + (complete_execution): New function. Reset of gdb prompt and stdin, + after inferior execution has completed. + (normal_stop): Call complete_execution at end of asynchronous + execution. + + * infcmd.c (strip_bg_char): New function to detect the background + execution char '&'. + (run_command): Modify to support background and foreground + execution in async mode. + (continue_command): Ditto. + (step_1): Ditto. + (jump_command): Ditto. + (interrupt_target_command): New function. Interrupt the + target execution. + (_initialize_infcmd): Add new command 'interrupt'. + + * top.c (target_executing): New global variable. + (execute_command): Reject commands that cannot be executed while + the target is running asynchronously. + + * event-top.c (push_prompt): Make non static. + (pop_prompt): Make non static. If the current prompt is empty, + don't try to copy it over the previous one. + (handle_sigint): Make non static. + (command_handler): Do the cleanups only when not executing with an + asynchronous target. + + * event-loop.c (delete_async_signal_handler): Pass a pointer to a + pointer to a signal handler, so that is can be freed at the end. + + * target.c (update_current_target): Inherit to_has_async_exec. + + * inferior.h: Add global variables target_executing, and + sync_execution. Export function fetch_inferior_event. + + * event-loop.h: Add push_prompt, pop_prompt, handle_sigint to the + exported functions. Update prototype for delete_signal_handler. + + * target.h (struct target_ops): New target op: to_has_async_exec. + (target_has_async): New macro. + + * Makefile.in (infrun.o): Add dependency on event-loop.h. + (remote.o): Ditto. + 1999-06-28 Jim Blandy <jimb@zwingli.cygnus.com> * solib.c (clear_solib): Don't disable breakpoints if we're @@ -136,6 +336,7 @@ Wed Jun 23 15:30:46 1999 Andrew Cagney <cagney@b1.cygnus.com> * Makefile.in (top_h): Define. (event-loop.o): Add dependencies on top.h and defs.h. (event-top.o): Add dependency on terminal.h. + * event-loop.c: Get rid of #include <readline.h>. * event-loop.h: Get rid of nested #include's. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 177333e..b13fa01 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -224,7 +224,7 @@ CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE) \ ADD_FILES = $(REGEX) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES) ADD_DEPS = $(REGEX1) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES) -VERSION = 19990628 +VERSION = 19990705 DIST=gdb LINT=/usr/5bin/lint @@ -1206,7 +1206,7 @@ infptrace.o: infptrace.c $(defs_h) $(gdbcore_h) $(inferior_h) target.h \ gdb_string.h $(wait_h) $(command_h) infrun.o: infrun.c $(wait_h) $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ - $(inferior_h) target.h gdbthread.h gdb_string.h + $(inferior_h) target.h gdbthread.h gdb_string.h $(event_loop_h) inftarg.o: inftarg.c $(wait_h) $(defs_h) $(gdbcore_h) $(inferior_h) \ target.h terminal.h $(command_h) @@ -1462,7 +1462,8 @@ remote-utils.o: remote-utils.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ $(inferior_h) $(remote_utils_h) gdb_string.h remote.o: remote.c $(bfd_h) $(wait_h) $(defs_h) $(gdbcmd_h) \ - $(inferior_h) $(remote_utils_h) symfile.h terminal.h gdb_string.h + $(inferior_h) $(remote_utils_h) symfile.h terminal.h gdb_string.h \ + $(event_loop_h) remote-nrom.o: remote-nrom.c $(bfd_h) $(wait_h) $(defs_h) $(gdbcmd_h) \ $(inferior_h) $(remote_utils_h) symfile.h terminal.h diff --git a/gdb/blockframe.c b/gdb/blockframe.c index 8f93d6e..87ce8bf 100644 --- a/gdb/blockframe.c +++ b/gdb/blockframe.c @@ -1121,6 +1121,7 @@ struct dummy_frame CORE_ADDR pc; CORE_ADDR fp; CORE_ADDR sp; + CORE_ADDR top; char *registers; }; @@ -1142,7 +1143,9 @@ generic_find_dummy_frame (pc, fp) for (dummyframe = dummy_frame_stack; dummyframe != NULL; dummyframe = dummyframe->next) - if (fp == dummyframe->fp || fp == dummyframe->sp) + if (fp == dummyframe->fp + || fp == dummyframe->sp + || fp == dummyframe->top) /* The frame in question lies between the saved fp and sp, inclusive */ return dummyframe->registers; @@ -1203,6 +1206,7 @@ generic_push_dummy_frame () if (INNER_THAN (dummy_frame->fp, fp)) /* stale -- destroy! */ { dummy_frame_stack = dummy_frame->next; + free (dummy_frame->registers); free (dummy_frame); dummy_frame = dummy_frame_stack; } @@ -1214,12 +1218,20 @@ generic_push_dummy_frame () dummy_frame->pc = read_register (PC_REGNUM); dummy_frame->sp = read_register (SP_REGNUM); + dummy_frame->top = dummy_frame->sp; dummy_frame->fp = fp; read_register_bytes (0, dummy_frame->registers, REGISTER_BYTES); dummy_frame->next = dummy_frame_stack; dummy_frame_stack = dummy_frame; } +void +generic_save_dummy_frame_tos (sp) + CORE_ADDR sp; +{ + dummy_frame_stack->top = sp; +} + /* Function: pop_frame Restore the machine state from either the saved dummy stack or a real stack frame. */ diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 11caae0..16a3ad6 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -2418,7 +2418,33 @@ bpstat_what (bs) after stopping, the check for whether to step over a breakpoint (BPSTAT_WHAT_SINGLE type stuff) is handled in proceed() without reference to how we stopped. We retain separate wp_silent and bp_silent - codes in case we want to change that someday. */ + codes in case we want to change that someday. + + Another possibly interesting property of this table is that + there's a partial ordering, priority-like, of the actions. Once + you've decided that some action is appropriate, you'll never go + back and decide something of a lower priority is better. The + ordering is: + + kc < clr sgl shl slr sn sr ss ts + sgl < clrs shl shlr slr sn sr ss ts + slr < err shl shlr sn sr ss ts + clr < clrs err shl shlr sn sr ss ts + clrs < err shl shlr sn sr ss ts + ss < shl shlr sn sr ts + sn < shl shlr sr ts + sr < shl shlr ts + shl < shlr + ts < + shlr < + + What I think this means is that we don't need a damned table + here. If you just put the rows and columns in the right order, + it'd look awfully regular. We could simply walk the bpstat list + and choose the highest priority action we find, with a little + logic to handle the 'err' cases, and the CLEAR_LONGJMP_RESUME/ + CLEAR_LONGJMP_RESUME_SINGLE distinction (which breakpoint.h says + is messy anyway). */ /* step_resume entries: a step resume breakpoint overrides another breakpoint of signal handling (see comment in wait_for_inferior @@ -4480,9 +4506,23 @@ static void awatch_command (arg, from_tty) } -/* Helper routine for the until_command routine in infcmd.c. Here +/* Helper routines for the until_command routine in infcmd.c. Here because it uses the mechanisms of breakpoints. */ +/* This function is called by fetch_inferior_event via the + cmd_continuation pointer, to complete the until command. It takes + care of cleaning up the temporary breakpoints set up by the until + command. */ +void +until_break_command_continuation (arg) + struct continuation_arg *arg; +{ + /* Do all the exec cleanups, which at this point should only be the + one set up in the first part of the until_break_command + function. */ + do_exec_cleanups (ALL_CLEANUPS); +} + /* ARGSUSED */ void until_break_command (arg, from_tty) @@ -4494,6 +4534,7 @@ until_break_command (arg, from_tty) struct frame_info *prev_frame = get_prev_frame (selected_frame); struct breakpoint *breakpoint; struct cleanup *old_chain; + struct continuation_arg *arg1, *arg2; clear_proceed_status (); @@ -4519,7 +4560,26 @@ until_break_command (arg, from_tty) breakpoint = set_momentary_breakpoint (sal, selected_frame, bp_until); - old_chain = make_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint); + if (!async_p || !target_has_async) + old_chain = make_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint); + else + make_exec_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint); + + /* If we are running asynchronously, and the target supports async + execution, we are not waiting for the target to stop, in the call + tp proceed, below. This means that we cannot delete the + brekpoints until the target has actually stopped. The only place + where we get a chance to do that is in fetch_inferior_event, so + we must set things up for that. */ + + if (async_p && target_has_async) + { + /* In this case we don't need args for the continuation, because + all it needs to do is do the cleanups in the + exec_cleanup_chain, which will be only those inserted by this + function. We can get away by using ALL_CLEANUPS. */ + add_continuation (until_break_command_continuation, NULL); + } /* Keep within the current frame */ @@ -4528,11 +4588,17 @@ until_break_command (arg, from_tty) sal = find_pc_line (prev_frame->pc, 0); sal.pc = prev_frame->pc; breakpoint = set_momentary_breakpoint (sal, prev_frame, bp_until); - make_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint); + if (!async_p || !target_has_async) + make_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint); + else + make_exec_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint); } proceed (-1, TARGET_SIGNAL_DEFAULT, 0); - do_cleanups(old_chain); + /* Do the cleanups now, anly if we are not running asynchronously, + of if we are, but the target is still synchronous. */ + if (!async_p || !target_has_async) + do_cleanups(old_chain); } #if 0 diff --git a/gdb/config/mn10300/tm-mn10300.h b/gdb/config/mn10300/tm-mn10300.h index eb47fec..20f93f4 100644 --- a/gdb/config/mn10300/tm-mn10300.h +++ b/gdb/config/mn10300/tm-mn10300.h @@ -128,10 +128,13 @@ extern void mn10300_pop_frame PARAMS ((struct frame_info *)); #define FIX_CALL_DUMMY(DUMMY, START, FUNADDR, NARGS, ARGS, TYPE, GCCP) #define CALL_DUMMY_ADDRESS() entry_point_address () +#define TARGET_READ_FP() read_sp () + extern CORE_ADDR mn10300_push_return_address PARAMS ((CORE_ADDR, CORE_ADDR)); #define PUSH_RETURN_ADDRESS(PC, SP) mn10300_push_return_address (PC, SP) #define PUSH_DUMMY_FRAME generic_push_dummy_frame () +#define SAVE_DUMMY_FRAME_TOS(SP) generic_save_dummy_frame_tos (SP) extern CORE_ADDR mn10300_push_arguments PARAMS ((int, struct value **, CORE_ADDR, diff --git a/gdb/configure.host b/gdb/configure.host index 50e4f6b..84df8fa 100644 --- a/gdb/configure.host +++ b/gdb/configure.host @@ -42,7 +42,7 @@ arm-*-*) gdb_host=arm ;; hppa*-*-bsd*) gdb_host=hppabsd ;; hppa*-*-hiux*) gdb_host=hppahpux ;; hppa*-*-hpux10.20) gdb_host=hpux1020 ;; -hppa*-*-hpux11.0*) gdb_host=hpux1100 ;; +hppa*-*-hpux11*) gdb_host=hpux1100 ;; hppa*-*-hpux*) gdb_host=hppahpux ;; hppa*-*-osf*) gdb_host=hppaosf ;; @@ -272,6 +272,7 @@ extern void do_cleanups PARAMS ((struct cleanup *)); extern void do_final_cleanups PARAMS ((struct cleanup *)); extern void do_my_cleanups PARAMS ((struct cleanup **, struct cleanup *)); extern void do_run_cleanups PARAMS ((struct cleanup *)); +extern void do_exec_cleanups PARAMS ((struct cleanup *)); extern void discard_cleanups PARAMS ((struct cleanup *)); extern void discard_final_cleanups PARAMS ((struct cleanup *)); @@ -290,6 +291,8 @@ extern struct cleanup *make_my_cleanup PARAMS ((struct cleanup **, extern struct cleanup *make_run_cleanup PARAMS ((make_cleanup_func, void *)); +extern struct cleanup *make_exec_cleanup PARAMS ((make_cleanup_func, void *)); + extern struct cleanup *save_cleanups PARAMS ((void)); extern struct cleanup *save_final_cleanups PARAMS ((void)); extern struct cleanup *save_my_cleanups PARAMS ((struct cleanup **)); @@ -368,6 +371,11 @@ extern GDB_FILE *gdb_stderr; *_unfiltered. In the very near future that restriction shall be removed - either call shall be unfiltered. (cagney 1999-06-13). */ extern GDB_FILE *gdb_stdlog; +/* Target output that should bypass normal stdout/stderr filtering. + For momement, always call this stream using *_unfiltered. In the + very near future that restriction shall be removed - either call + shall be unfiltered. (cagney 1999-07-02). */ +extern GDB_FILE *gdb_stdtarg; #if defined(TUI) #include "tui.h" @@ -613,6 +621,34 @@ extern struct command_line *read_command_lines PARAMS ((char *, int)); extern void free_command_lines PARAMS ((struct command_line **)); +/* To continue the execution commands when running gdb asynchronously. + A continuation structure contains a pointer to a function to be called + to finish the command, once the target has stopped. Such mechanism is + used bt the finish and until commands, and in the remote protocol + when opening an extended-remote connection. */ + +struct continuation_arg +{ + struct continuation_arg *next; + PTR data; +}; + +struct continuation +{ + void (*continuation_hook) PARAMS ((struct continuation_arg *)); + struct continuation_arg *arg_list; + struct continuation *next; +} +continuation; + +/* In infrun.c. */ +extern struct continuation *cmd_continuation; + +/* From utils.c */ +void add_continuation PARAMS ((void (*) PARAMS ((struct continuation_arg *)), + struct continuation_arg *)); +void do_all_continuations PARAMS ((void)); + /* String containing the current directory (what getwd would return). */ extern char *current_directory; @@ -794,6 +830,8 @@ enum return_reason { RETURN_ERROR }; +#define ALL_CLEANUPS ((struct cleanup *)0) + #define RETURN_MASK_QUIT (1 << (int)RETURN_QUIT) #define RETURN_MASK_ERROR (1 << (int)RETURN_ERROR) #define RETURN_MASK_ALL (RETURN_MASK_QUIT | RETURN_MASK_ERROR) @@ -1109,7 +1147,6 @@ extern void (*flush_hook) PARAMS ((GDB_FILE *stream)); extern void (*create_breakpoint_hook) PARAMS ((struct breakpoint *b)); extern void (*delete_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); extern void (*modify_breakpoint_hook) PARAMS ((struct breakpoint *bpt)); -extern void (*target_output_hook) PARAMS ((char *)); extern void (*interactive_hook) PARAMS ((void)); extern void (*registers_changed_hook) PARAMS ((void)); extern void (*readline_begin_hook) PARAMS ((char *, ...)); diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 10e4ef7..bc9e6aa 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,7 @@ +Tue Jun 29 11:43:55 1999 Andrew Cagney <cagney@b1.cygnus.com> + + * gdbint.texinfo (SAVE_DUMMY_FRAME_TOS): Define. + Fri Jun 25 11:47:06 1999 Andrew Cagney <cagney@b1.cygnus.com> * remote.texi (Communication Protocol): ``v'' is in use. Fix diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo index 4db5212..40a43a0 100644 --- a/gdb/doc/gdbint.texinfo +++ b/gdb/doc/gdbint.texinfo @@ -1573,6 +1573,12 @@ Deprecated in favor of @var{REGISTER_NAME}. Define this to return 1 if the given type will be passed by pointer rather than directly. +@item SAVE_DUMMY_FRAME_TOS (sp) +Used in @samp{call_function_by_hand} to notify the target dependent code +of the top-of-stack value that will be passed to the the inferior code. +This is the value of the @var{SP} after both the dummy frame and space +for parameters/results have been allocated on the stack. + @item SDB_REG_TO_REGNUM Define this to convert sdb register numbers into GDB regnums. If not defined, no conversion will be done. diff --git a/gdb/event-loop.c b/gdb/event-loop.c index 1e22e06..3f15da5 100644 --- a/gdb/event-loop.c +++ b/gdb/event-loop.c @@ -290,6 +290,7 @@ gdb_do_one_event () } return result; } + /* Start up the event loop. This is the entry point to the event loop from the command loop. */ @@ -752,26 +753,27 @@ invoke_async_signal_handler () Free the space allocated for it. */ void delete_async_signal_handler (async_handler_ptr) - async_signal_handler *async_handler_ptr; + async_signal_handler **async_handler_ptr; { async_signal_handler *prev_ptr; - if (sighandler_list.first_handler == async_handler_ptr) + if (sighandler_list.first_handler == (*async_handler_ptr)) { - sighandler_list.first_handler = async_handler_ptr->next_handler; + sighandler_list.first_handler = (*async_handler_ptr)->next_handler; if (sighandler_list.first_handler == NULL) sighandler_list.last_handler = NULL; } else { prev_ptr = sighandler_list.first_handler; - while (prev_ptr->next_handler != async_handler_ptr) + while (prev_ptr->next_handler != (*async_handler_ptr) && prev_ptr) prev_ptr = prev_ptr->next_handler; - prev_ptr->next_handler = async_handler_ptr->next_handler; - if (sighandler_list.last_handler == async_handler_ptr) + prev_ptr->next_handler = (*async_handler_ptr)->next_handler; + if (sighandler_list.last_handler == (*async_handler_ptr)) sighandler_list.last_handler = prev_ptr; } - free ((char *) async_handler_ptr); + free ((char *) (*async_handler_ptr)); + (*async_handler_ptr) = NULL; } /* Is it necessary to call invoke_async_signal_handler? */ diff --git a/gdb/event-loop.h b/gdb/event-loop.h index e06fb8c..b53f8e2 100644 --- a/gdb/event-loop.h +++ b/gdb/event-loop.h @@ -230,7 +230,7 @@ extern void add_file_handler PARAMS ((int, file_handler_func, gdb_client_data)); extern void mark_async_signal_handler PARAMS ((async_signal_handler *)); extern async_signal_handler * create_async_signal_handler PARAMS ((async_handler_func *, gdb_client_data)); -extern void delete_async_signal_handler PARAMS ((async_signal_handler *async_handler_ptr)); +extern void delete_async_signal_handler PARAMS ((async_signal_handler **async_handler_ptr)); /* Exported functions from event-top.c. FIXME: these should really go into top.h. */ @@ -241,6 +241,9 @@ extern void set_async_editing_command PARAMS ((char *, int, struct cmd_list_elem extern void set_async_annotation_level PARAMS ((char *, int, struct cmd_list_element *)); extern void set_async_prompt PARAMS ((char *, int, struct cmd_list_element *)); extern void handle_stop_sig PARAMS ((int)); +extern void handle_sigint PARAMS ((int)); +extern void pop_prompt PARAMS ((void)); +extern void push_prompt PARAMS ((char *, char *, char *)); extern void gdb_readline2 PARAMS ((void)); /* Exported variables from event-top.c. diff --git a/gdb/event-top.c b/gdb/event-top.c index 223e670..91b6389 100644 --- a/gdb/event-top.c +++ b/gdb/event-top.c @@ -35,15 +35,16 @@ extern void _initialize_event_loop PARAMS ((void)); static void command_line_handler PARAMS ((char *)); +static void command_line_handler_continuation PARAMS ((struct continuation_arg *)); void gdb_readline2 PARAMS ((void)); -static void pop_prompt PARAMS ((void)); -static void push_prompt PARAMS ((char *, char *, char *)); +void pop_prompt PARAMS ((void)); +void push_prompt PARAMS ((char *, char *, char *)); static void change_line_handler PARAMS ((void)); static void change_annotation_level PARAMS ((void)); static void command_handler PARAMS ((char *)); /* Signal handlers. */ -static void handle_sigint PARAMS ((int)); +void handle_sigint PARAMS ((int)); static void handle_sigquit PARAMS ((int)); static void handle_sighup PARAMS ((int)); static void handle_sigfpe PARAMS ((int)); @@ -331,7 +332,7 @@ change_annotation_level () parts: prefix, prompt, suffix. Usually prefix and suffix are empty strings, except when the annotation level is 2. Memory is allocated within savestring for the new prompt. */ -static void +void push_prompt (prefix, prompt, suffix) char *prefix; char *prompt; @@ -340,6 +341,9 @@ push_prompt (prefix, prompt, suffix) the_prompts.top++; PREFIX (0) = savestring (prefix, strlen (prefix)); + /* Note that this function is used by the set annotate 2 + command. This is why we take care of saving the old prompt + in case a new one is not specified. */ if (prompt) PROMPT (0) = savestring (prompt, strlen (prompt)); else @@ -349,14 +353,21 @@ push_prompt (prefix, prompt, suffix) } /* Pops the top of the prompt stack, and frees the memory allocated for it. */ -static void +void pop_prompt () { - if (strcmp (PROMPT (0), PROMPT (-1))) - { - free (PROMPT (-1)); - PROMPT (-1) = savestring (PROMPT (0), strlen (PROMPT (0))); - } + /* If we are not during a 'synchronous' execution command, in which + case, the top prompt would be empty. */ + if (strcmp (PROMPT (0), "")) + /* This is for the case in which the prompt is set while the + annotation level is 2. The top prompt will be changed, but when + we return to annotation level < 2, we want that new prompt to be + in effect, until the user does another 'set prompt'. */ + if (strcmp (PROMPT (0), PROMPT (-1))) + { + free (PROMPT (-1)); + PROMPT (-1) = savestring (PROMPT (0), strlen (PROMPT (0))); + } free (PREFIX (0)); free (PROMPT (0)); @@ -376,6 +387,8 @@ command_handler (command) { struct cleanup *old_chain; int stdin_is_tty = ISATTY (stdin); + struct continuation_arg *arg1; + struct continuation_arg *arg2; long time_at_cmd_start; #ifdef HAVE_SBRK long space_at_cmd_start = 0; @@ -416,11 +429,72 @@ command_handler (command) } execute_command (command, instream == stdin); + + /* Set things up for this function to be compete later, once the + executin has completed, if we are doing an execution command, + otherwise, just go ahead and finish. */ + if (target_has_async && target_executing) + { + arg1 = + (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); + arg2 = + (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); + arg1->next = arg2; + arg2->next = NULL; + arg1->data = (PTR) time_at_cmd_start; + arg2->data = (PTR) space_at_cmd_start; + add_continuation (command_line_handler_continuation, arg1); + } - /* Do any commands attached to breakpoint we stopped at. */ - bpstat_do_actions (&stop_bpstat); - do_cleanups (old_chain); + /* Do any commands attached to breakpoint we stopped at. Only if we + are always running synchronously. Or if we have just executed a + command that doesn't start the target. */ + if (!target_has_async || !target_executing) + { + bpstat_do_actions (&stop_bpstat); + do_cleanups (old_chain); + + if (display_time) + { + long cmd_time = get_run_time () - time_at_cmd_start; + printf_unfiltered ("Command execution time: %ld.%06ld\n", + cmd_time / 1000000, cmd_time % 1000000); + } + + if (display_space) + { +#ifdef HAVE_SBRK + extern char **environ; + char *lim = (char *) sbrk (0); + long space_now = lim - (char *) &environ; + long space_diff = space_now - space_at_cmd_start; + + printf_unfiltered ("Space used: %ld (%c%ld for this command)\n", + space_now, + (space_diff >= 0 ? '+' : '-'), + space_diff); +#endif + } + } +} + +/* Do any commands attached to breakpoint we stopped at. Only if we + are always running synchronously. Or if we have just executed a + command that doesn't start the target. */ +void +command_line_handler_continuation (arg) + struct continuation_arg *arg; +{ + extern int display_time; + extern int display_space; + + long time_at_cmd_start = (long) arg->data; + long space_at_cmd_start = (long) arg->next->data; + + bpstat_do_actions (&stop_bpstat); + /*do_cleanups (old_chain);*/ /*?????FIXME?????*/ + if (display_time) { long cmd_time = get_run_time () - time_at_cmd_start; @@ -428,7 +502,6 @@ command_handler (command) printf_unfiltered ("Command execution time: %ld.%06ld\n", cmd_time / 1000000, cmd_time % 1000000); } - if (display_space) { #ifdef HAVE_SBRK @@ -797,7 +870,7 @@ mark_async_signal_handler_wrapper (token) /* Tell the event loop what to do if SIGINT is received. See event-signal.c. */ -static void +void handle_sigint (sig) int sig; { diff --git a/gdb/frame.h b/gdb/frame.h index b00d8f1..77cc491 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -134,6 +134,7 @@ extern int default_frame_chain_valid PARAMS ((CORE_ADDR, struct frame_info *)); extern int alternate_frame_chain_valid PARAMS ((CORE_ADDR, struct frame_info *)); extern int nonnull_frame_chain_valid PARAMS ((CORE_ADDR, struct frame_info *)); extern int generic_frame_chain_valid PARAMS ((CORE_ADDR, struct frame_info *)); +extern void generic_save_dummy_frame_tos PARAMS ((CORE_ADDR sp)); #if !defined (FRAME_CHAIN_VALID) #if !defined (FRAME_CHAIN_VALID_ALTERNATE) diff --git a/gdb/infcmd.c b/gdb/infcmd.c index eb11169..ba4e798 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -33,6 +33,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "language.h" #include "symfile.h" #include "objfiles.h" +#include "event-loop.h" /* Functions exported for general use: */ @@ -46,6 +47,8 @@ void registers_info PARAMS ((char *, int)); void continue_command PARAMS ((char *, int)); +static void finish_command_continuation PARAMS ((struct continuation_arg *)); + static void until_next_command PARAMS ((int)); static void until_command PARAMS ((char *, int)); @@ -94,6 +97,8 @@ static void run_no_args_command PARAMS ((char *args, int from_tty)); static void go_command PARAMS ((char *line_no, int from_tty)); +static int strip_bg_char PARAMS ((char **)); + void _initialize_infcmd PARAMS ((void)); #define GO_USAGE "Usage: go <location>\n" @@ -184,6 +189,35 @@ int step_multi; struct environ *inferior_environ; +/* This function detects whether or not a '&' character (indicating + background execution) has been added as *the last* of the arguments ARGS + of a command. If it has, it removes it and returns 1. Otherwise it + does nothing and returns 0. */ +static int +strip_bg_char (args) + char **args; +{ + char *p = NULL; + + if (p = strchr (*args, '&')) + { + if (p == (*args + strlen (*args) - 1)) + { + if (strlen (*args) >1) + { + do + p--; + while (*p == ' ' || *p == '\t'); + *(p + 1) = '\0'; + } + else + *args = 0; + return 1; + } + } + return 0; +} + /* ARGSUSED */ void tty_command (file, from_tty) @@ -239,12 +273,33 @@ Start it from the beginning? ")) the user has to manually nuke all symbols between runs if they want them to go away (PR 2207). This is probably reasonable. */ - if (args) + if (!args) + sync_execution = 1; + else { char *cmd; - cmd = concat ("set args ", args, NULL); - make_cleanup (free, cmd); - execute_command (cmd, from_tty); + int async_exec = strip_bg_char (&args); + + /* If we get a request for running in the bg but the target + doesn't support it, error out. */ + if (async_p && async_exec && !target_has_async) + error ("Asynchronous execution not supported on this target."); + + /* If we don't get a request of running in the bg, then we need + to simulate synchronous (fg) execution. */ + if (async_p && !async_exec && target_has_async) + { + /* Simulate synchronous execution */ + sync_execution = 1; + } + + /* If there were other args, beside '&', process them. */ + if (args) + { + cmd = concat ("set args ", args, NULL); + make_cleanup (free, cmd); + execute_command (cmd, from_tty); + } } if (from_tty) @@ -278,10 +333,28 @@ continue_command (proc_count_exp, from_tty) char *proc_count_exp; int from_tty; { + int async_exec = 0; ERROR_NO_INFERIOR; - /* If have argument, set proceed count of breakpoint we stopped at. */ + /* Find out whether we must run in the background. */ + if (proc_count_exp != NULL) + async_exec = strip_bg_char (&proc_count_exp); + + /* If we must run in the background, but the target can't do it, + error out. */ + if (async_p && async_exec && !target_has_async) + error ("Asynchronous execution not supported on this target."); + + /* If we are not asked to run in the bg, then prepare to run in the + foreground, synchronously. */ + if (async_p && !async_exec && target_has_async) + { + /* Simulate synchronous execution */ + sync_execution = 1; + } + /* If have argument (besides '&'), set proceed count of breakpoint + we stopped at. */ if (proc_count_exp != NULL) { bpstat bs = stop_bpstat; @@ -363,8 +436,26 @@ step_1 (skip_subroutines, single_inst, count_string) register int count = 1; struct frame_info *frame; struct cleanup *cleanups = 0; - + int async_exec = 0; + ERROR_NO_INFERIOR; + + if (count_string) + async_exec = strip_bg_char (&count_string); + + /* If we get a request for running in the bg but the target + doesn't support it, error out. */ + if (async_p && async_exec && !target_has_async) + error ("Asynchronous execution not supported on this target."); + + /* If we don't get a request of running in the bg, then we need + to simulate synchronous (fg) execution. */ + if (async_p && !async_exec && target_has_async) + { + /* Simulate synchronous execution */ + sync_execution = 1; + } + count = count_string ? parse_and_eval_address (count_string) : 1; if (!single_inst || skip_subroutines) /* leave si command alone */ @@ -443,9 +534,27 @@ jump_command (arg, from_tty) struct symtab_and_line sal; struct symbol *fn; struct symbol *sfn; - + int async_exec = 0; + ERROR_NO_INFERIOR; + /* Find out whether we must run in the background. */ + if (arg != NULL) + async_exec = strip_bg_char (&arg); + + /* If we must run in the background, but the target can't do it, + error out. */ + if (async_p && async_exec && !target_has_async) + error ("Asynchronous execution not supported on this target."); + + /* If we are not asked to run in the bg, then prepare to run in the + foreground, synchronously. */ + if (async_p && !async_exec && target_has_async) + { + /* Simulate synchronous execution */ + sync_execution = 1; + } + if (!arg) error_no_arg ("starting address"); @@ -490,7 +599,6 @@ jump_command (arg, from_tty) } } - addr = sal.pc; if (from_tty) @@ -731,14 +839,110 @@ until_command (arg, from_tty) char *arg; int from_tty; { + int async_exec = 0; + if (!target_has_execution) error ("The program is not running."); + + /* Find out whether we must run in the background. */ + if (arg != NULL) + async_exec = strip_bg_char (&arg); + + /* If we must run in the background, but the target can't do it, + error out. */ + if (async_p && async_exec && !target_has_async) + error ("Asynchronous execution not supported on this target."); + + /* If we are not asked to run in the bg, then prepare to run in the + foreground, synchronously. */ + if (async_p && !async_exec && target_has_async) + { + /* Simulate synchronous execution */ + sync_execution = 1; + } + if (arg) until_break_command (arg, from_tty); else until_next_command (from_tty); } + +/* Stuff that needs to be done by the finish command after the target + has stopped. In asynchronous mode, we wait for the target to stop in + the call to poll or select in the event loop, so it is impossible to + do all the stuff as part of the finish_command function itself. The + only chance we have to complete this command is in + fetch_inferior_event, which is called by the event loop as soon as it + detects that the target has stopped. This function is called via the + cmd_continaution pointer. */ +void +finish_command_continuation (arg) + struct continuation_arg *arg; +{ + register struct symbol *function; + struct breakpoint *breakpoint; + + breakpoint = (struct breakpoint *) arg->data; + function = (struct symbol *) (arg->next)->data; + + if (bpstat_find_breakpoint(stop_bpstat, breakpoint) != NULL + && function != 0) + { + struct type *value_type; + register value_ptr val; + CORE_ADDR funcaddr; + int struct_return; + + value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function)); + if (!value_type) + fatal ("internal: finish_command: function has no target type"); + + if (TYPE_CODE (value_type) == TYPE_CODE_VOID) + { + do_exec_cleanups (ALL_CLEANUPS); + return; + } + + funcaddr = BLOCK_START (SYMBOL_BLOCK_VALUE (function)); + + struct_return = using_struct_return (value_of_variable (function, NULL), + + funcaddr, + check_typedef (value_type), + BLOCK_GCC_COMPILED (SYMBOL_BLOCK_VALUE (function))); + + if (!struct_return) + { + val = value_being_returned (value_type, stop_registers, struct_return); + printf_filtered ("Value returned is $%d = ", record_latest_value (val)); + value_print (val, gdb_stdout, 0, Val_no_prettyprint); + printf_filtered ("\n"); + } + else + { + /* We cannot determine the contents of the structure because + it is on the stack, and we don't know where, since we did not + initiate the call, as opposed to the call_function_by_hand case */ +#ifdef VALUE_RETURNED_FROM_STACK + val = 0; + printf_filtered ("Value returned has type: %s.", + TYPE_NAME (value_type)); + printf_filtered (" Cannot determine contents\n"); +#else + val = value_being_returned (value_type, stop_registers, + struct_return); + printf_filtered ("Value returned is $%d = ", + record_latest_value (val)); + value_print (val, gdb_stdout, 0, Val_no_prettyprint); + printf_filtered ("\n"); +#endif + + } + } + do_exec_cleanups (ALL_CLEANUPS); +} + /* "finish": Set a temporary breakpoint at the place the selected frame will return to, then continue. */ @@ -752,6 +956,26 @@ finish_command (arg, from_tty) register struct symbol *function; struct breakpoint *breakpoint; struct cleanup *old_chain; + struct continuation_arg *arg1, *arg2; + + int async_exec = 0; + + /* Find out whether we must run in the background. */ + if (arg != NULL) + async_exec = strip_bg_char (&arg); + + /* If we must run in the background, but the target can't do it, + error out. */ + if (async_p && async_exec && !target_has_async) + error ("Asynchronous execution not supported on this target."); + + /* If we are not asked to run in the bg, then prepare to run in the + foreground, synchronously. */ + if (async_p && !async_exec && target_has_async) + { + /* Simulate synchronous execution */ + sync_execution = 1; + } if (arg) error ("The \"finish\" command does not take any arguments."); @@ -771,7 +995,10 @@ finish_command (arg, from_tty) breakpoint = set_momentary_breakpoint (sal, frame, bp_finish); - old_chain = make_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint); + if (!async_p || !target_has_async) + old_chain = make_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint); + else + make_exec_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint); /* Find the function we will return from. */ @@ -785,62 +1012,89 @@ finish_command (arg, from_tty) print_stack_frame (selected_frame, selected_frame_level, 0); } + /* If running asynchronously and the target support asynchronous + execution, set things up for the rest of the finish command to be + completed later on, when gdb has detected that the target has + stopped, in fetch_inferior_event. */ + if (async_p && target_has_async) + { + arg1 = + (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); + arg2 = + (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg)); + arg1->next = arg2; + arg2->next = NULL; + arg1->data = (PTR) breakpoint; + arg2->data = (PTR) function; + add_continuation (finish_command_continuation, arg1); + } + proceed_to_finish = 1; /* We want stop_registers, please... */ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0); - /* Did we stop at our breakpoint? */ - if (bpstat_find_breakpoint(stop_bpstat, breakpoint) != NULL - && function != 0) - { - struct type *value_type; - register value_ptr val; - CORE_ADDR funcaddr; - int struct_return; + /* Do this only if not running asynchronously or if the target + cannot do async execution. Otherwise, complete this command when + the target actually stops, in fetch_inferior_event.*/ + if (!async_p || !target_has_async) + { - value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function)); - if (!value_type) - fatal ("internal: finish_command: function has no target type"); - - if (TYPE_CODE (value_type) == TYPE_CODE_VOID) - return; + /* Did we stop at our breakpoint? */ + if (bpstat_find_breakpoint(stop_bpstat, breakpoint) != NULL + && function != 0) + { + struct type *value_type; + register value_ptr val; + CORE_ADDR funcaddr; + int struct_return; - funcaddr = BLOCK_START (SYMBOL_BLOCK_VALUE (function)); + value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function)); + if (!value_type) + fatal ("internal: finish_command: function has no target type"); - struct_return = using_struct_return (value_of_variable (function, NULL), + /* FIXME: Shouldn't we do the cleanups before returning? */ + if (TYPE_CODE (value_type) == TYPE_CODE_VOID) + return; + + funcaddr = BLOCK_START (SYMBOL_BLOCK_VALUE (function)); + struct_return = + using_struct_return (value_of_variable (function, NULL), funcaddr, check_typedef (value_type), - BLOCK_GCC_COMPILED (SYMBOL_BLOCK_VALUE (function))); - - if (!struct_return) - { - val = value_being_returned (value_type, stop_registers, struct_return); - printf_filtered ("Value returned is $%d = ", record_latest_value (val)); - value_print (val, gdb_stdout, 0, Val_no_prettyprint); - printf_filtered ("\n"); - } - else - { - /* elz: we cannot determine the contents of the structure because - it is on the stack, and we don't know where, since we did not - initiate the call, as opposed to the call_function_by_hand case */ + BLOCK_GCC_COMPILED (SYMBOL_BLOCK_VALUE (function))); + + if (!struct_return) + { + val = + value_being_returned (value_type, stop_registers, struct_return); + printf_filtered ("Value returned is $%d = ", + record_latest_value (val)); + value_print (val, gdb_stdout, 0, Val_no_prettyprint); + printf_filtered ("\n"); + } + else + { + /* We cannot determine the contents of the structure + because it is on the stack, and we don't know + where, since we did not initiate the call, as + opposed to the call_function_by_hand case */ #ifdef VALUE_RETURNED_FROM_STACK - val = 0; - printf_filtered ("Value returned has type: %s.", - TYPE_NAME (value_type)); - printf_filtered (" Cannot determine contents\n"); + val = 0; + printf_filtered ("Value returned has type: %s.", + TYPE_NAME (value_type)); + printf_filtered (" Cannot determine contents\n"); #else - val = value_being_returned (value_type, stop_registers, - struct_return); - printf_filtered ("Value returned is $%d = ", - record_latest_value (val)); - value_print (val, gdb_stdout, 0, Val_no_prettyprint); - printf_filtered ("\n"); -#endif - + val = value_being_returned (value_type, stop_registers, + struct_return); + printf_filtered ("Value returned is $%d = ", + record_latest_value (val)); + value_print (val, gdb_stdout, 0, Val_no_prettyprint); + printf_filtered ("\n"); +#endif + } + } + do_cleanups(old_chain); } - } - do_cleanups(old_chain); } /* ARGSUSED */ @@ -1355,6 +1609,20 @@ detach_command (args, from_tty) #endif } +/* Stop the execution of the target while running in async mode, in + the backgound. */ +static void +interrupt_target_command (args, from_tty) + char *args; + int from_tty; +{ + if (async_p && target_has_async) + { + dont_repeat (); /* Not for the faint of heart */ + target_stop (); + } +} + /* ARGSUSED */ static void float_info (addr_exp, from_tty) @@ -1530,6 +1798,9 @@ use \"set args\" without arguments."); add_com ("R", class_run, run_no_args_command, "Start debugged program with no arguments."); + add_com ("interrupt", class_run, interrupt_target_command, + "Interrupt the execution of the debugged program."); + add_info ("registers", nofp_registers_info, "List of integer registers and their contents, for selected stack frame.\n\ Register name as argument means describe only that register."); diff --git a/gdb/inferior.h b/gdb/inferior.h index b87bca9..9ba86c7 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -71,6 +71,17 @@ extern char *inferior_io_terminal; extern int inferior_pid; +/* Is the inferior running right now, as a result of a 'run&', + 'continue&' etc command? This is used in asycn gdb to determine + whether a command that the user enters while the target is running + is allowed or not. */ +extern int target_executing; + +/* Are we simulating synchronous execution? This is used in async gdb + to implement the 'run', 'continue' etc commands, which will not + redisplay the prompt until the execution is actually over. */ +extern int sync_execution; + /* This is only valid when inferior_pid is non-zero. If this is 0, then exec events should be noticed and responded to @@ -148,6 +159,8 @@ extern void generic_target_write_fp PARAMS ((CORE_ADDR)); extern void wait_for_inferior PARAMS ((void)); +extern void fetch_inferior_event PARAMS ((void)); + extern void init_wait_for_inferior PARAMS ((void)); extern void close_exec_file PARAMS ((void)); diff --git a/gdb/infrun.c b/gdb/infrun.c index 339acf8..80cc891 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -32,8 +32,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "annotate.h" #include "symfile.h" /* for overlay functions */ #include "top.h" - #include <signal.h> +#include "event-loop.h" /* Prototypes for local functions */ @@ -53,9 +53,14 @@ static void delete_breakpoint_current_contents PARAMS ((PTR)); static void set_follow_fork_mode_command PARAMS ((char *arg, int from_tty, struct cmd_list_element *c)); +static void complete_execution PARAMS ((void)); + int inferior_ignoring_startup_exec_events = 0; int inferior_ignoring_leading_exec_events = 0; +/* In asynchronous mode, but simulating synchronous execution. */ +int sync_execution = 0; + /* wait_for_inferior and normal_stop use this to notify the user when the inferior stopped in a different thread than it had been running in. */ @@ -1006,9 +1011,13 @@ The same program may be running in another process."); /* Wait for it to stop (if not standalone) and in any case decode why it stopped, and act accordingly. */ - - wait_for_inferior (); - normal_stop (); + /* Do this only if we are not using the event loop, or if the target + does not support asynchronous execution. */ + if (!async_p || !target_has_async) + { + wait_for_inferior (); + normal_stop (); + } } /* Record the pc and sp of the program the last time it stopped. @@ -1021,7 +1030,6 @@ static char *prev_func_name; /* Start remote-debugging of a machine over a serial link. */ - void start_remote () { @@ -1029,8 +1037,24 @@ start_remote () init_wait_for_inferior (); stop_soon_quietly = 1; trap_expected = 0; - wait_for_inferior (); - normal_stop (); + + /* Go on waiting only in case gdb is not started in async mode, or + in case the target doesn't support async execution. */ + if (!async_p || !target_has_async) + { + wait_for_inferior (); + normal_stop (); + } + else + { + /* The 'tar rem' command should always look synchronous, + i.e. display the prompt only once it has connected and + started the target. */ + sync_execution = 1; + push_prompt ("", "", ""); + delete_file_handler (input_fd); + target_executing = 1; + } } /* Initialize static vars when a new inferior begins. */ @@ -1179,6 +1203,72 @@ wait_for_inferior () do_cleanups (old_cleanups); } +/* Asynchronous version of wait_for_inferior. It is called by the + event loop whenever a change of state is detected on the file + descriptor corresponding to the target. It can be called more than + once to complete a single execution command. In such cases we need + to keep the state in a global variable ASYNC_ECSS. If it is the + last time that this function is called for a single execution + command, then report to the user that the inferior has stopped, and + do the necessary cleanups. */ + +struct execution_control_state async_ecss; +struct execution_control_state *async_ecs; + +void +fetch_inferior_event () +{ + static struct cleanup *old_cleanups; + + async_ecs = &async_ecss; + + if (!async_ecs->wait_some_more) + { + old_cleanups = make_exec_cleanup (delete_breakpoint_current_contents, + &step_resume_breakpoint); + make_exec_cleanup (delete_breakpoint_current_contents, + &through_sigtramp_breakpoint); + + /* Fill in with reasonable starting values. */ + init_execution_control_state (async_ecs); + + thread_step_needed = 0; + + /* We'll update this if & when we switch to a new thread. */ + if (may_switch_from_inferior_pid) + switched_from_inferior_pid = inferior_pid; + + overlay_cache_invalid = 1; + + /* We have to invalidate the registers BEFORE calling target_wait + because they can be loaded from the target while in target_wait. + This makes remote debugging a bit more efficient for those + targets that provide critical registers as part of their normal + status mechanism. */ + + registers_changed (); + } + + if (target_wait_hook) + async_ecs->pid = target_wait_hook (async_ecs->waiton_pid, async_ecs->wp); + else + async_ecs->pid = target_wait (async_ecs->waiton_pid, async_ecs->wp); + + /* Now figure out what to do with the result of the result. */ + handle_inferior_event (async_ecs); + + if (!async_ecs->wait_some_more) + { + do_exec_cleanups (old_cleanups); + normal_stop (); + /* Is there anything left to do for the command issued to + complete? */ + do_all_continuations (); + /* Reset things after target has stopped for the async commands. */ + complete_execution (); + } +} + /* Prepare an execution control state for looping through a wait_for_inferior-type loop. */ @@ -3011,6 +3101,25 @@ stopped_for_shlib_catchpoint (bs, cp_p) } +/* Reset proper settings after an asynchronous command has finished. + If the execution command was in synchronous mode, register stdin + with the event loop, and reset the prompt. */ +static void +complete_execution () +{ +extern cleanup_sigint_signal_handler PARAMS ((void)); + + if (sync_execution) + { + add_file_handler (input_fd, (file_handler_func *) call_readline, 0); + pop_prompt (); + sync_execution = 0; + cleanup_sigint_signal_handler (); + display_gdb_prompt (0); + } + target_executing = 0; +} + /* Here to return control to GDB when the inferior stops for real. Print appropriate messages, remove breakpoints, give terminal our modes. @@ -62,6 +62,7 @@ int dbx_commands = 0; GDB_FILE *gdb_stdout; GDB_FILE *gdb_stderr; GDB_FILE *gdb_stdlog; +GDB_FILE *gdb_stdtarg; /* Whether to enable writing into executable and core files */ extern int write_files; @@ -163,10 +164,12 @@ main (argc, argv) gdb_stdout = stdio_fileopen (stdout); gdb_stderr = stdio_fileopen (stderr); gdb_stdlog = gdb_stderr; /* for moment */ + gdb_stdtarg = gdb_stderr; /* for moment */ #else gdb_stdout = tui_fileopen (stdout); gdb_stderr = tui_fileopen (stderr); gdb_stdlog = gdb_stdout; /* for moment */ + gdb_stdtarg = gdb_stderr; /* for moment */ #endif /* Parse arguments and options. */ diff --git a/gdb/mn10300-tdep.c b/gdb/mn10300-tdep.c index a0113ed..c758d77 100644 --- a/gdb/mn10300-tdep.c +++ b/gdb/mn10300-tdep.c @@ -275,7 +275,9 @@ mn10300_analyze_prologue (fi, pc) /* Do nothing if we couldn't find the start of this function or if we're stopped at the first instruction in the prologue. */ if (status == 0) - return pc; + { + return pc; + } /* If we're in start, then give up. */ if (strcmp (name, "start") == 0) diff --git a/gdb/remote-os9k.c b/gdb/remote-os9k.c index 2abfa83..714400f 100644 --- a/gdb/remote-os9k.c +++ b/gdb/remote-os9k.c @@ -1,5 +1,5 @@ /* Remote debugging interface for boot monitors, for GDB. - Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Copyright 1990, 1991, 1992, 1993, 1999 Free Software Foundation, Inc. This file is part of GDB. @@ -40,14 +40,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gdbcore.h" #include "target.h" #include "wait.h" + #ifdef ANSI_PROTOTYPES #include <stdarg.h> #else #include <varargs.h> #endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif #include <signal.h> -#include "gdb_string.h" #include <sys/types.h> + +#include "gdb_string.h" #include "command.h" #include "serial.h" #include "monitor.h" diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c index b8ced91..8923aec 100644 --- a/gdb/remote-sim.c +++ b/gdb/remote-sim.c @@ -197,10 +197,7 @@ gdb_os_write_stdout (p, buf, len) { b[0] = buf[i]; b[1] = 0; - if (target_output_hook) - target_output_hook (b); - else - fputs_filtered (b, gdb_stdout); + fputs_unfiltered (b, gdb_stdtarg); } return len; } @@ -229,10 +226,7 @@ gdb_os_write_stderr (p, buf, len) { b[0] = buf[i]; b[1] = 0; - if (target_output_hook) - target_output_hook (b); - else - fputs_filtered (b, gdb_stderr); + fputs_unfiltered (b, gdb_stdtarg); } return len; } diff --git a/gdb/remote-st.c b/gdb/remote-st.c index 1efdbfa..108fa96 100644 --- a/gdb/remote-st.c +++ b/gdb/remote-st.c @@ -1,5 +1,5 @@ /* Remote debugging interface for Tandem ST2000 phone switch, for GDB. - Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Copyright 1990, 1991, 1992, 1999 Free Software Foundation, Inc. Contributed by Cygnus Support. Written by Jim Kingdon for Cygnus. This file is part of GDB. @@ -38,14 +38,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gdbcore.h" #include "target.h" #include "wait.h" + #ifdef ANSI_PROTOTYPES #include <stdarg.h> #else #include <varargs.h> #endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif #include <signal.h> -#include "gdb_string.h" #include <sys/types.h> + +#include "gdb_string.h" #include "serial.h" extern struct target_ops st2000_ops; /* Forward declaration */ diff --git a/gdb/remote.c b/gdb/remote.c index 8fadca8..a88194c 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1,5 +1,5 @@ /* Remote target communications for serial-line targets in custom GDB protocol - Copyright 1988, 91, 92, 93, 94, 95, 96, 97, 1998 + Copyright 1988, 91, 92, 93, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. This file is part of GDB. @@ -219,10 +219,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <sys/types.h> #endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#include "event-loop.h" + #include <signal.h> #include "serial.h" /* Prototypes for local functions */ +static void initialize_sigint_signal_handler PARAMS ((void)); +static void handle_remote_sigint PARAMS ((int)); +static void handle_remote_sigint_twice PARAMS ((int)); +static void async_remote_interrupt PARAMS ((gdb_client_data)); +static void async_remote_interrupt_twice PARAMS ((gdb_client_data)); + +static void set_extended_protocol PARAMS ((struct continuation_arg *)); static void build_remote_gdbarch_data PARAMS ((void)); @@ -244,15 +257,21 @@ static void remote_fetch_registers PARAMS ((int regno)); static void remote_resume PARAMS ((int pid, int step, enum target_signal siggnal)); +static void remote_async_resume PARAMS ((int pid, int step, + enum target_signal siggnal)); static int remote_start_remote PARAMS ((PTR)); static void remote_open PARAMS ((char *name, int from_tty)); +static void remote_async_open PARAMS ((char *name, int from_tty)); static void extended_remote_open PARAMS ((char *name, int from_tty)); +static void extended_remote_async_open PARAMS ((char *name, int from_tty)); static void remote_open_1 PARAMS ((char *, int, struct target_ops *, int extended_p)); +static void remote_async_open_1 PARAMS ((char *, int, struct target_ops *, + int extended_p)); static void remote_close PARAMS ((int quitting)); @@ -265,6 +284,7 @@ static void extended_remote_restart PARAMS ((void)); static void extended_remote_mourn PARAMS ((void)); static void extended_remote_create_inferior PARAMS ((char *, char *, char **)); +static void extended_remote_async_create_inferior PARAMS ((char *, char *, char **)); static void remote_mourn_1 PARAMS ((struct target_ops *)); @@ -273,12 +293,15 @@ static void remote_send PARAMS ((char *buf)); static int readchar PARAMS ((int timeout)); static int remote_wait PARAMS ((int pid, struct target_waitstatus * status)); +static int remote_async_wait PARAMS ((int pid, struct target_waitstatus * status)); static void remote_kill PARAMS ((void)); +static void remote_async_kill PARAMS ((void)); static int tohex PARAMS ((int nib)); static void remote_detach PARAMS ((char *args, int from_tty)); +static void remote_async_detach PARAMS ((char *args, int from_tty)); static void remote_interrupt PARAMS ((int signo)); @@ -362,6 +385,12 @@ static struct target_ops remote_ops; static struct target_ops extended_remote_ops; +/* Temporary target ops. Just like the remote_ops and + extended_remote_ops, but with asynchronous support. */ +static struct target_ops remote_async_ops; + +static struct target_ops extended_async_remote_ops; + /* This was 5 seconds, which is a long time to sit and wait. Unless this is going though some terminal server or multiplexer or other form of hairy serial connection, I would think 2 seconds would @@ -444,6 +473,10 @@ static int remote_register_buf_size = 0; doesn't support 'P', the only consequence is some unnecessary traffic. */ static int stub_supports_P = 1; +/* Tokens for use by the asynchronous signal handlers for SIGINT */ +PTR sigint_remote_twice_token; +PTR sigint_remote_token; + /* These are pointers to hook functions that may be set in order to modify resume/wait behavior for a particular architecture. */ @@ -1604,6 +1637,15 @@ remote_open (name, from_tty) remote_open_1 (name, from_tty, &remote_ops, 0); } +/* Just like remote_open, but with asynchronous support. */ +static void +remote_async_open (name, from_tty) + char *name; + int from_tty; +{ + remote_async_open_1 (name, from_tty, &remote_async_ops, 0); +} + /* Open a connection to a remote debugger using the extended remote gdb protocol. NAME is the filename used for communication. */ @@ -1615,6 +1657,15 @@ extended_remote_open (name, from_tty) remote_open_1 (name, from_tty, &extended_remote_ops, 1/*extended_p*/); } +/* Just like extended_remote_open, but with asynchronous support. */ +static void +extended_remote_async_open (name, from_tty) + char *name; + int from_tty; +{ + remote_async_open_1 (name, from_tty, &extended_async_remote_ops, 1/*extended_p*/); +} + /* Generic code for opening a connection to a remote target. */ static DCACHE *remote_dcache; @@ -1649,7 +1700,6 @@ serial device is attached to the remote system (e.g. /dev/ttya)."); } } - SERIAL_RAW (remote_desc); /* If there is something sitting in the buffer we might take it as a @@ -1705,6 +1755,124 @@ serial device is attached to the remote system (e.g. /dev/ttya)."); } } +/* Just like remote_open but with asynchronous support. */ +static void +remote_async_open_1 (name, from_tty, target, extended_p) + char *name; + int from_tty; + struct target_ops *target; + int extended_p; +{ + if (name == 0) + error ("To open a remote debug connection, you need to specify what\n\ +serial device is attached to the remote system (e.g. /dev/ttya)."); + + target_preopen (from_tty); + + unpush_target (target); + + remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes); + + remote_desc = SERIAL_OPEN (name); + if (!remote_desc) + perror_with_name (name); + + if (baud_rate != -1) + { + if (SERIAL_SETBAUDRATE (remote_desc, baud_rate)) + { + SERIAL_CLOSE (remote_desc); + perror_with_name (name); + } + } + + SERIAL_RAW (remote_desc); + + /* If there is something sitting in the buffer we might take it as a + response to a command, which would be bad. */ + SERIAL_FLUSH_INPUT (remote_desc); + + if (from_tty) + { + puts_filtered ("Remote debugging using "); + puts_filtered (name); + puts_filtered ("\n"); + } + + /* If running in asynchronous mode, register the target with the + event loop. Set things up so that when there is an event on the + file descriptor, the event loop will call fetch_inferior_event, + which will do the proper analysis to determine what happened. */ + if (async_p) + add_file_handler (remote_desc->fd, (file_handler_func *) fetch_inferior_event, 0); + + push_target (target); /* Switch to using remote target now */ + + /* Start out by trying the 'P' request to set registers. We set + this each time that we open a new target so that if the user + switches from one stub to another, we can (if the target is + closed and reopened) cope. */ + stub_supports_P = 1; + + general_thread = -2; + continue_thread = -2; + + /* Force remote_write_bytes to check whether target supports + binary downloading. */ + remote_binary_checked = 0; + + /* If running asynchronously, set things up for telling the target + to use the extended protocol. This will happen only after the + target has been connected to, in fetch_inferior_event. */ + if (extended_p && async_p) + add_continuation (set_extended_protocol, NULL); + + /* Without this, some commands which require an active target (such + as kill) won't work. This variable serves (at least) double duty + as both the pid of the target process (if it has such), and as a + flag indicating that a target is active. These functions should + be split out into seperate variables, especially since GDB will + someday have a notion of debugging several processes. */ + + inferior_pid = MAGIC_NULL_PID; + /* Start the remote connection; if error (0), discard this target. + In particular, if the user quits, be sure to discard it + (we'd be in an inconsistent state otherwise). */ + if (!catch_errors (remote_start_remote, NULL, + "Couldn't establish connection to remote target\n", + RETURN_MASK_ALL)) + { + /* Unregister the file descriptor from the event loop. */ + if (async_p) + delete_file_handler (remote_desc->fd); + pop_target (); + return; + } + + if (!async_p) + { + if (extended_p) + { + /* tell the remote that we're using the extended protocol. */ + char *buf = alloca (PBUFSIZ); + putpkt ("!"); + getpkt (buf, 0); + } + } +} + +/* This will be called by fetch_inferior_event, via the + cmd_continuation pointer, only after the target has stopped. */ +static void +set_extended_protocol (arg) + struct continuation_arg * arg; +{ + /* tell the remote that we're using the extended protocol. */ + char *buf = alloca (PBUFSIZ); + putpkt ("!"); + getpkt (buf, 0); +} + /* This takes a program previously attached to and detaches it. After this is done, GDB can be used to debug some other program. We better not have left any breakpoints in the target program or it'll @@ -1729,6 +1897,30 @@ remote_detach (args, from_tty) puts_filtered ("Ending remote debugging.\n"); } +/* Same as remote_detach, but with async support. */ +static void +remote_async_detach (args, from_tty) + char *args; + int from_tty; +{ + char *buf = alloca (PBUFSIZ); + + if (args) + error ("Argument given to \"detach\" when remotely debugging."); + + /* Tell the remote target to detach. */ + strcpy (buf, "D"); + remote_send (buf); + + /* Unregister the file descriptor from the event loop. */ + if (async_p) + delete_file_handler (remote_desc->fd); + + pop_target (); + if (from_tty) + puts_filtered ("Ending remote debugging.\n"); +} + /* Convert hex digit A to a number. */ int @@ -1797,10 +1989,134 @@ remote_resume (pid, step, siggnal) putpkt (buf); } + +/* Same as remote_resume, but with async support. */ +static void +remote_async_resume (pid, step, siggnal) + int pid, step; + enum target_signal siggnal; +{ + char *buf = alloca (PBUFSIZ); + + if (pid == -1) + set_thread (0, 0); /* run any thread */ + else + set_thread (pid, 0); /* run this thread */ + + dcache_flush (remote_dcache); + + last_sent_signal = siggnal; + last_sent_step = step; + + /* A hook for when we need to do something at the last moment before + resumption. */ + if (target_resume_hook) + (*target_resume_hook) (); + + /* Set things up before execution starts for async commands. */ + /* This function can be entered more than once for the same execution + command, because it is also called by handle_inferior_event. So + we make sure that we don't do the initialization for sync + execution more than once. */ + if (async_p && !target_executing) + { + target_executing = 1; + + /* If the command must look synchronous, fake it, by making gdb + display an empty prompt after the command has completed. Also + disable input. */ + if (sync_execution) + { + push_prompt ("", "", ""); + delete_file_handler (input_fd); + initialize_sigint_signal_handler (); + } + } + + if (siggnal != TARGET_SIGNAL_0) + { + buf[0] = step ? 'S' : 'C'; + buf[1] = tohex (((int)siggnal >> 4) & 0xf); + buf[2] = tohex ((int)siggnal & 0xf); + buf[3] = '\0'; + } + else + strcpy (buf, step ? "s": "c"); + + putpkt (buf); +} + +/* Set up the signal handler for SIGINT, while the target is + executing, ovewriting the 'regular' SIGINT signal handler. */ +static void +initialize_sigint_signal_handler () +{ + sigint_remote_token = + create_async_signal_handler (async_remote_interrupt, NULL); + signal (SIGINT, handle_remote_sigint); +} + +/* Signal handler for SIGINT, while the target is executing. */ +static void +handle_remote_sigint (sig) + int sig; +{ + signal (sig, handle_remote_sigint_twice); + sigint_remote_twice_token = + create_async_signal_handler (async_remote_interrupt_twice, NULL); + mark_async_signal_handler_wrapper (sigint_remote_token); +} + +/* Signal handler for SIGINT, installed after SIGINT has already been + sent once. It will take effect the second time that the user sends + a ^C. */ +static void +handle_remote_sigint_twice (sig) + int sig; +{ + signal (sig, handle_sigint); + sigint_remote_twice_token = + create_async_signal_handler (async_remote_interrupt, NULL); + mark_async_signal_handler_wrapper (sigint_remote_twice_token); +} + +/* Perform the real interruption of hte target execution, in response + to a ^C. */ +static void +async_remote_interrupt (arg) + gdb_client_data arg; +{ + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n"); + + target_stop (); +} + +/* Perform interrupt, if the first attempt did not succeed. Just give + up on the target alltogether. */ +static void +async_remote_interrupt_twice (arg) + gdb_client_data arg; +{ + interrupt_query (); + signal (SIGINT, handle_remote_sigint); +} + +/* Reinstall the usual SIGINT handlers, after the target has + stopped. */ +void +cleanup_sigint_signal_handler () +{ + signal (SIGINT, handle_sigint); + if (sigint_remote_twice_token) + delete_async_signal_handler ((async_signal_handler**) &sigint_remote_twice_token); + if (sigint_remote_token) + delete_async_signal_handler ((async_signal_handler**) &sigint_remote_token); +} + /* Send ^C to target to halt it. Target will respond, and send us a packet. */ - static void (*ofunc) PARAMS ((int)); /* The command line interface's stop routine. This function is installed @@ -1875,16 +2191,13 @@ remote_console_output (msg) { char *p; - for (p = msg; *p; p +=2) + for (p = msg; p[0] && p[1]; p +=2) { char tb[2]; char c = fromhex (p[0]) * 16 + fromhex (p[1]); tb[0] = c; tb[1] = 0; - if (target_output_hook) - target_output_hook (tb); - else - fputs_filtered (tb, gdb_stdout); + fputs_unfiltered (tb, gdb_stdtarg); } } @@ -2109,6 +2422,225 @@ Packet Dropped"); return inferior_pid; } +/* Async version of remote_wait. */ +static int +remote_async_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + unsigned char *buf = alloca (PBUFSIZ); + int thread_num = -1; + + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = 0; + + while (1) + { + unsigned char *p; + + if (!async_p) + ofunc = signal (SIGINT, remote_interrupt); + getpkt ((char *) buf, 1); + if (!async_p) + signal (SIGINT, ofunc); + + /* This is a hook for when we need to do something (perhaps the + collection of trace data) every time the target stops. */ + if (target_wait_loop_hook) + (*target_wait_loop_hook) (); + + switch (buf[0]) + { + case 'E': /* Error of some sort */ + warning ("Remote failure reply: %s", buf); + continue; + case 'T': /* Status with PC, SP, FP, ... */ + { + int i; + long regno; + char regs[MAX_REGISTER_RAW_SIZE]; + + /* Expedited reply, containing Signal, {regno, reg} repeat */ + /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where + ss = signal number + n... = register number + r... = register contents + */ + p = &buf[3]; /* after Txx */ + + while (*p) + { + unsigned char *p1; + char *p_temp; + + /* Read the register number */ + regno = strtol ((const char *) p, &p_temp, 16); + p1 = (unsigned char *)p_temp; + + if (p1 == p) /* No register number present here */ + { + p1 = (unsigned char *) strchr ((const char *) p, ':'); + if (p1 == NULL) + warning ("Malformed packet(a) (missing colon): %s\n\ +Packet: '%s'\n", + p, buf); + if (strncmp ((const char *) p, "thread", p1 - p) == 0) + { + p_temp = unpack_varlen_hex (++p1, &thread_num); + record_currthread (thread_num); + p = (unsigned char *) p_temp; + } + } + else + { + p = p1; + + if (*p++ != ':') + warning ("Malformed packet(b) (missing colon): %s\n\ +Packet: '%s'\n", + p, buf); + + if (regno >= NUM_REGS) + warning ("Remote sent bad register number %ld: %s\n\ +Packet: '%s'\n", + regno, p, buf); + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i++) + { + if (p[0] == 0 || p[1] == 0) + warning ("Remote reply is too short: %s", buf); + regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } + supply_register (regno, regs); + } + + if (*p++ != ';') + { + warning ("Remote register badly formatted: %s", buf); + warning (" here: %s",p); + } + } + } + /* fall through */ + case 'S': /* Old style status, just signal only */ + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = (enum target_signal) + (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))); + + if (buf[3] == 'p') + { + /* Export Cisco kernel mode as a convenience variable + (so that it can be used in the GDB prompt if desired). */ + + if (cisco_kernel_mode == 1) + set_internalvar (lookup_internalvar ("cisco_kernel_mode"), + value_from_string ("PDEBUG-")); + cisco_kernel_mode = 0; + thread_num = strtol ((const char *) &buf[4], NULL, 16); + record_currthread (thread_num); + } + else if (buf[3] == 'k') + { + /* Export Cisco kernel mode as a convenience variable + (so that it can be used in the GDB prompt if desired). */ + + if (cisco_kernel_mode == 1) + set_internalvar (lookup_internalvar ("cisco_kernel_mode"), + value_from_string ("KDEBUG-")); + cisco_kernel_mode = 1; + } + goto got_status; + case 'N': /* Cisco special: status and offsets */ + { + bfd_vma text_addr, data_addr, bss_addr; + bfd_signed_vma text_off, data_off, bss_off; + unsigned char *p1; + + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = (enum target_signal) + (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))); + + if (symfile_objfile == NULL) + { + warning ("Relocation packet recieved with no symbol file. \ +Packet Dropped"); + goto got_status; + } + + /* Relocate object file. Buffer format is NAATT;DD;BB + * where AA is the signal number, TT is the new text + * address, DD * is the new data address, and BB is the + * new bss address. */ + + p = &buf[3]; + text_addr = strtoul (p, (char **) &p1, 16); + if (p1 == p || *p1 != ';') + warning ("Malformed relocation packet: Packet '%s'", buf); + p = p1 + 1; + data_addr = strtoul (p, (char **) &p1, 16); + if (p1 == p || *p1 != ';') + warning ("Malformed relocation packet: Packet '%s'", buf); + p = p1 + 1; + bss_addr = strtoul (p, (char **) &p1, 16); + if (p1 == p) + warning ("Malformed relocation packet: Packet '%s'", buf); + + if (remote_cisco_section_offsets (text_addr, data_addr, bss_addr, + &text_off, &data_off, &bss_off) + == 0) + if (text_off != 0 || data_off != 0 || bss_off != 0) + remote_cisco_objfile_relocate (text_off, data_off, bss_off); + + goto got_status; + } + case 'W': /* Target exited */ + { + /* The remote process exited. */ + status->kind = TARGET_WAITKIND_EXITED; + status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]); + goto got_status; + } + case 'X': + status->kind = TARGET_WAITKIND_SIGNALLED; + status->value.sig = (enum target_signal) + (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))); + kill_kludge = 1; + + goto got_status; + case 'O': /* Console output */ + remote_console_output (buf + 1); + continue; + case '\0': + if (last_sent_signal != TARGET_SIGNAL_0) + { + /* Zero length reply means that we tried 'S' or 'C' and + the remote system doesn't support it. */ + target_terminal_ours_for_output (); + printf_filtered + ("Can't send signals to this remote system. %s not sent.\n", + target_signal_to_name (last_sent_signal)); + last_sent_signal = TARGET_SIGNAL_0; + target_terminal_inferior (); + + strcpy ((char *) buf, last_sent_step ? "s" : "c"); + putpkt ((char *) buf); + continue; + } + /* else fallthrough */ + default: + warning ("Invalid remote reply: %s", buf); + continue; + } + } + got_status: + if (thread_num != -1) + { + return thread_num; + } + return inferior_pid; +} + /* Number of bytes of registers this stub implements. */ static int register_bytes_found; @@ -2792,7 +3324,7 @@ putpkt_binary (buf, cnt) /* Copy the packet into buffer BUF2, encapsulating it and giving it a checksum. */ - if (cnt > (int) sizeof (buf2) - 5) /* Prosanity check */ + if (cnt > BUFSIZ - 5) /* Prosanity check */ abort (); p = buf2; @@ -3116,6 +3648,32 @@ remote_kill () target_mourn_inferior (); } +/* Async version of remote_kill. */ +static void +remote_async_kill () +{ + /* Unregister the file descriptor from the event loop. */ + if (async_p) + delete_file_handler (remote_desc->fd); + + /* For some mysterious reason, wait_for_inferior calls kill instead of + mourn after it gets TARGET_WAITKIND_SIGNALLED. Work around it. */ + if (kill_kludge) + { + kill_kludge = 0; + target_mourn_inferior (); + return; + } + + /* Use catch_errors so the user can quit from gdb even when we aren't on + speaking terms with the remote system. */ + catch_errors ((catch_errors_ftype*) putpkt, "k", "", RETURN_MASK_ERROR); + + /* Don't wait for it to die. I'm not really sure it matters whether + we do or not. For the existing stubs, kill is a noop. */ + target_mourn_inferior (); +} + static void remote_mourn () { @@ -3175,6 +3733,36 @@ extended_remote_create_inferior (exec_file, args, env) proceed (-1, TARGET_SIGNAL_0, 0); } +/* Async version of extended_remote_create_inferior. */ +static void +extended_remote_async_create_inferior (exec_file, args, env) + char *exec_file; + char *args; + char **env; +{ + /* Rip out the breakpoints; we'll reinsert them after restarting + the remote server. */ + remove_breakpoints (); + + /* If running asynchronously, register the target file descriptor + with the event loop. */ + if (async_p) + add_file_handler (remote_desc->fd, (file_handler_func *) fetch_inferior_event, 0); + + /* Now restart the remote server. */ + extended_remote_restart (); + + /* Now put the breakpoints back in. This way we're safe if the + restart function works via a unix fork on the remote side. */ + insert_breakpoints (); + + /* Clean up from the last time we were running. */ + clear_proceed_status (); + + /* Let the remote process run. */ + proceed (-1, TARGET_SIGNAL_0, 0); +} + /* On some machines, e.g. 68k, we may use a different breakpoint instruction than other targets; in those use REMOTE_BREAKPOINT instead of just @@ -4103,13 +4691,75 @@ Specify the serial device it is connected to (e.g. host:2020)."; remote_cisco_ops.to_magic = OPS_MAGIC; } +/* Target async and target extended-async. + + This are temporary targets, until it is all tested. Eventually + async support will be incorporated int the usual 'remote' + target. */ + +static void +init_remote_async_ops () +{ + remote_async_ops.to_shortname = "async"; + remote_async_ops.to_longname = "Remote serial target in async version of the gdb-specific protocol"; + remote_async_ops.to_doc = + "Use a remote computer via a serial line, using a gdb-specific protocol.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya)."; + remote_async_ops.to_open = remote_async_open; + remote_async_ops.to_close = remote_close; + remote_async_ops.to_detach = remote_async_detach; + remote_async_ops.to_resume = remote_async_resume; + remote_async_ops.to_wait = remote_async_wait; + remote_async_ops.to_fetch_registers = remote_fetch_registers; + remote_async_ops.to_store_registers = remote_store_registers; + remote_async_ops.to_prepare_to_store = remote_prepare_to_store; + remote_async_ops.to_xfer_memory = remote_xfer_memory; + remote_async_ops.to_files_info = remote_files_info; + remote_async_ops.to_insert_breakpoint = remote_insert_breakpoint; + remote_async_ops.to_remove_breakpoint = remote_remove_breakpoint; + remote_async_ops.to_kill = remote_async_kill; + remote_async_ops.to_load = generic_load; + remote_async_ops.to_mourn_inferior = remote_mourn; + remote_async_ops.to_thread_alive = remote_thread_alive; + remote_async_ops.to_find_new_threads = remote_threads_info; + remote_async_ops.to_stop = remote_stop; + remote_async_ops.to_query = remote_query; + remote_async_ops.to_stratum = process_stratum; + remote_async_ops.to_has_all_memory = 1; + remote_async_ops.to_has_memory = 1; + remote_async_ops.to_has_stack = 1; + remote_async_ops.to_has_registers = 1; + remote_async_ops.to_has_execution = 1; + remote_async_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */ + remote_async_ops.to_has_async_exec = 1; + remote_async_ops.to_magic = OPS_MAGIC; +} + +/* Set up the async extended remote vector by making a copy of the standard + remote vector and adding to it. */ + +static void +init_extended_async_remote_ops () +{ + extended_async_remote_ops = remote_async_ops; + + extended_async_remote_ops.to_shortname = "extended-async"; + extended_async_remote_ops.to_longname = + "Extended remote serial target in async gdb-specific protocol"; + extended_async_remote_ops.to_doc = + "Use a remote computer via a serial line, using an async gdb-specific protocol.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya).", + extended_async_remote_ops.to_open = extended_remote_async_open; + extended_async_remote_ops.to_create_inferior = extended_remote_async_create_inferior; + extended_async_remote_ops.to_mourn_inferior = extended_remote_mourn; +} + static void build_remote_gdbarch_data () { tty_input = xmalloc (PBUFSIZ); } - void _initialize_remote () { @@ -4128,6 +4778,12 @@ _initialize_remote () init_extended_remote_ops (); add_target (&extended_remote_ops); + init_remote_async_ops (); + add_target (&remote_async_ops); + + init_extended_async_remote_ops (); + add_target (&extended_async_remote_ops); + init_remote_cisco_ops (); add_target (&remote_cisco_ops); diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c index e6443a0..86c7f5a 100644 --- a/gdb/ser-tcp.c +++ b/gdb/ser-tcp.c @@ -1,5 +1,5 @@ /* Serial interface for raw TCP connections on Un*x like systems - Copyright 1992, 1993, 1998 Free Software Foundation, Inc. + Copyright 1992, 1993, 1998, 1999 Free Software Foundation, Inc. This file is part of GDB. @@ -33,6 +33,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <netinet/tcp.h> #endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + #include "signals.h" #include "gdb_string.h" diff --git a/gdb/ser-unix.c b/gdb/ser-unix.c index dc5236f..50f2806 100644 --- a/gdb/ser-unix.c +++ b/gdb/ser-unix.c @@ -1,5 +1,5 @@ /* Serial interface for local (hardwired) serial ports on Un*x like systems - Copyright 1992, 1993, 1994, 1998 Free Software Foundation, Inc. + Copyright 1992, 1993, 1994, 1998, 1999 Free Software Foundation, Inc. This file is part of GDB. @@ -26,6 +26,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <unistd.h> #endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + #ifdef HAVE_TERMIOS struct hardwire_ttystate diff --git a/gdb/source.c b/gdb/source.c index 2d80b77..ae5a9d0 100644 --- a/gdb/source.c +++ b/gdb/source.c @@ -276,7 +276,7 @@ directory_command (dirname, from_tty) /* FIXME, this goes to "delete dir"... */ if (dirname == 0) { - if (query ("Reinitialize source path to empty? ")) + if (from_tty && query ("Reinitialize source path to empty? ")) { free (source_path); init_source_path (); diff --git a/gdb/sparcl-tdep.c b/gdb/sparcl-tdep.c index e39bf30..4c8ff97 100644 --- a/gdb/sparcl-tdep.c +++ b/gdb/sparcl-tdep.c @@ -1,5 +1,5 @@ /* Target dependent code for the Fujitsu SPARClite for GDB, the GNU debugger. - Copyright 1994, 1995, 1996 Free Software Foundation, Inc. + Copyright 1994, 1995, 1996, 1999 Free Software Foundation, Inc. This file is part of GDB. @@ -24,6 +24,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "serial.h" #include <sys/types.h> +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + #if (!defined(__GO32__) && !defined(_WIN32)) || defined(__CYGWIN32__) #define HAVE_SOCKETS #include <sys/time.h> diff --git a/gdb/target.c b/gdb/target.c index d889943..a9217d8 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -535,6 +535,7 @@ update_current_target () INHERIT (to_has_registers, t); INHERIT (to_has_execution, t); INHERIT (to_has_thread_control, t); + INHERIT (to_has_async_exec, t); INHERIT (to_sections, t); INHERIT (to_sections_end, t); INHERIT (to_magic, t); diff --git a/gdb/target.h b/gdb/target.h index 30d33a2..16b2517 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -381,6 +381,7 @@ struct target_ops int to_has_registers; int to_has_execution; int to_has_thread_control; /* control thread execution */ + int to_has_async_exec; struct section_table *to_sections; struct section_table @@ -984,6 +985,10 @@ print_section_info PARAMS ((struct target_ops *, bfd *)); #define target_can_switch_threads \ (current_target.to_has_thread_control & tc_switch) +/* Does the target support asynchronous execution? */ +#define target_has_async \ + (current_target.to_has_async_exec) + extern void target_link PARAMS ((char *, CORE_ADDR *)); /* Converts a process id to a string. Usually, the string just contains diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 376c575..6e53b67 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +Tue Jun 29 11:56:06 1999 Andrew Cagney <cagney@b1.cygnus.com> + + * lib/gdb.exp (gdb_expect_list): Output one message per pattern in + a consistent format. + 1999-06-25 Stan Shebs <shebs@andros.cygnus.com> From Jimmy Guo <guo@cup.hp.com> and others at HP: diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index cb277be..3e71adc 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -1105,38 +1105,44 @@ proc gdb_expect { args } { proc gdb_expect_list {test sentinal list} { global gdb_prompt set index 0 - while { ${index} >= 0 && ${index} < [llength ${list}] } { + set ok 1 + while { ${index} < [llength ${list}] } { set pattern [lindex ${list} ${index}] set index [expr ${index} + 1] if { ${index} == [llength ${list}] } { - gdb_expect { - -re "${pattern}${sentinal}" { - pass "${test} (sentinal)" - } - timeout { - fail "(timeout on sentinal) ${test}" - set index -1 + if { ${ok} } { + gdb_expect { + -re "${pattern}${sentinal}" { + pass "${test}, pattern ${index} + sentinal" + } + timeout { + fail "${test}, pattern ${index} + sentinal (timeout)" + set ok 0 + } } + } else { + fail "${test}, pattern ${index} + sentinal" } } else { - gdb_expect { - -re "${pattern}" { - pass "${test} (line ${index})" - } - -re "${sentinal}" { - fail "${test} (line ${index})" - set index -1 - } - timeout { - fail "(timeout on line ${index}) ${test}" - set index -1 + if { ${ok} } { + gdb_expect { + -re "${pattern}" { + pass "${test}, pattern ${index}" + } + -re "${sentinal}" { + fail "${test}, pattern ${index}" + set ok 0 + } + timeout { + fail "${test}, pattern ${index} (timeout)" + set ok 0 + } } + } else { + fail "${test}, pattern ${index}" } } } - if { ${index} >= 0 } { - pass "${test}" - } } # @@ -322,6 +322,12 @@ int remote_timeout = 20; /* Set default to 20 */ int remote_debug = 0; +/* Non-zero means the target is running. Note: this is different from + saying that there is an active target and we are stopped at a + breakpoint, for instance. This is a real indicator whether the + target is off and running, which gdb is doing something else. */ +int target_executing = 0; + /* Level of control structure. */ static int control_level; @@ -383,11 +389,6 @@ void (*command_loop_hook) PARAMS ((void)); void (*fputs_unfiltered_hook) PARAMS ((const char *linebuffer, GDB_FILE *stream)); -/* Called when the target says something to the host, which may - want to appear in a different window. */ - -void (*target_output_hook) PARAMS ((char *)); - /* Called from print_frame_info to list the line we stopped in. */ void (*print_frame_info_listing_hook) PARAMS ((struct symtab *s, int line, @@ -486,6 +487,8 @@ return_to_top_level (reason) disable_current_display (); do_cleanups (ALL_CLEANUPS); + if (async_p && target_has_async) + do_exec_cleanups (ALL_CLEANUPS); if (annotation_level > 1) switch (reason) @@ -1266,6 +1269,16 @@ execute_command (p, from_tty) char *arg; c = lookup_cmd (&p, cmdlist, "", 0, 1); + + /* If the target is running, we allow only a limited set of + commands. */ + if (async_p && target_has_async && target_executing) + if (!strcmp (c->name, "help") + && !strcmp (c->name, "pwd") + && !strcmp (c->name, "show") + && !strcmp (c->name, "stop")) + error ("Cannot execute this command while the target is running."); + /* Pass null arg rather than an empty one. */ arg = *p ? p : 0; @@ -82,7 +82,6 @@ extern void set_prompt PARAMS ((char *)); /* From random places. */ extern int mapped_symbol_files; extern int readnow_symbol_files; -#define ALL_CLEANUPS ((struct cleanup *)0) /* Perform _initialize initialization */ extern void gdb_init PARAMS ((char *)); diff --git a/gdb/utils.c b/gdb/utils.c index 03f0aa4..26f05a7 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -92,6 +92,13 @@ set_width PARAMS ((void)); static struct cleanup *cleanup_chain; /* cleaned up after a failed command */ static struct cleanup *final_cleanup_chain; /* cleaned up when gdb exits */ static struct cleanup *run_cleanup_chain; /* cleaned up on each 'run' */ +static struct cleanup *exec_cleanup_chain; /* cleaned up on each execution command */ + +/* Pointer to what is left to do for an execution command after the + target stops. Used only in asynchronous mode, by targets that + support async execution. The finish and until commands use it. So + does the target extended-remote command. */ +struct continuation *cmd_continuation; /* Nonzero if we have job control. */ @@ -175,6 +182,14 @@ make_run_cleanup (function, arg) return make_my_cleanup (&run_cleanup_chain, function, arg); } +struct cleanup * +make_exec_cleanup (function, arg) + void (*function) PARAMS ((PTR)); + PTR arg; +{ + return make_my_cleanup (&exec_cleanup_chain, function, arg); +} + static void do_freeargv (arg) void *arg; @@ -232,6 +247,13 @@ do_run_cleanups (old_chain) } void +do_exec_cleanups (old_chain) + register struct cleanup *old_chain; +{ + do_my_cleanups (&exec_cleanup_chain, old_chain); +} + +void do_my_cleanups (pmy_chain, old_chain) register struct cleanup **pmy_chain; register struct cleanup *old_chain; @@ -350,6 +372,38 @@ null_cleanup (arg) { } +/* Add a continuation to the continuation list, the gloabl list + cmd_continuation. */ +void +add_continuation (continuation_hook, arg_list) + void (*continuation_hook) PARAMS ((struct continuation_arg *)); + struct continuation_arg *arg_list; +{ + struct continuation *continuation_ptr; + + continuation_ptr = (struct continuation *) xmalloc (sizeof (struct continuation)); + continuation_ptr->continuation_hook = continuation_hook; + continuation_ptr->arg_list = arg_list; + continuation_ptr->next = cmd_continuation; + cmd_continuation = continuation_ptr; +} + +/* Walk down the cmd_continuation list, and execute all the + continuations. */ +void +do_all_continuations () +{ + struct continuation *continuation_ptr; + + while (cmd_continuation) + { + (cmd_continuation->continuation_hook) (cmd_continuation->arg_list); + continuation_ptr = cmd_continuation; + cmd_continuation = continuation_ptr->next; + free (continuation_ptr); + } +} + /* Print a warning message. Way to use this is to call warning_begin, output the warning message (use unfiltered output to gdb_stderr), diff --git a/gdb/valops.c b/gdb/valops.c index 74dae8d..c7db836 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -1636,6 +1636,10 @@ You must use a pointer to function type variable. Command ignored.", arg_name); wouldn't happen. (See store_inferior_registers in sparc-nat.c.) */ write_sp (sp); +#ifdef SAVE_DUMMY_FRAME_TOS + SAVE_DUMMY_FRAME_TOS (sp); +#endif + { char retbuf[REGISTER_BYTES]; char *name; |