+Tue Sep 28 11:08:34 1999 Jeffrey A Law (law@cygnus.com)
+
+ * hppa-tdep.c (hppa_fix_call_dummy): Ignore IMPORT_SHLIB stubs
+ except for hpux11 native. Break out of the loop to find a
+ stub as soon as we find an IMPORT stub.
+ (skip_prologue_hard_way): Also recognize copy %ret1,target and
+ all PA64 argument stores as prologue instructions.
+
+1999-09-28 Elena Zannoni <ezannoni@kwikemart.cygnus.com>
+
+ * breakpoint.c, defs.h, event-top.c, infcmd.c, infrun.c, main.c,
+ remote.c, top.c, tracepoint.c, utils.c (async_p): Change var name
+ to event_loop_p.
+
+1999-09-28 Jim Blandy <jimb@cris.red-bean.com>
+
+ * hppa-tdep.c (skip_prologue_hard_way): Recognize ldo insns
+ which generate pointers into the argument list.
+
+Tue Sep 28 13:56:49 1999 Andrew Cagney <cagney@b1.cygnus.com>
+
+ * remote.h (cleanup_sigint_signal_handler,
+ initialize_sigint_signal_handler): Delete extern declarations.
+ * event-top.c, infrun.c: No longer need to include "remote.h".
+ * remote.c (cleanup_sigint_signal_handler,
+ initialize_sigint_signal_handler): Make static.
+ * Makefile.in (event-top.o): Delete dependency on "remote.h".
+
+ * remote.c (remote_async_terminal_ours_p): New static global. Keep
+ track of who currently owns the terminal.
+ (remote_async_open_1): Initialize.
+ (remote_async_terminal_inferior): Test
+ remote_async_terminal_ours_p. Claim CNTRL-C handler as part of
+ transfering the terminal to the target.
+ (remote_async_terminal_ours): Similar.
+
+Mon Sep 27 12:33:45 1999 Andrew Cagney <cagney@b1.cygnus.com>
+
+ * remote.c (async_interrupt_query): Delete function. Merged into
+ interrupt_query. Async cases handled by target_terminal_ours,
+ target_terminal_inferior and SERIAL_CLOSE.
+ (async_remote_interrupt_twice): Update.
+ (remote_async_terminal_ours, remote_async_terminal_inferior): New
+ functions. Steal STDIN from GDB's CLI.
+ (init_remote_async_ops): Initialize to_terminal_ours and
+ to_terminal_inferior.
+
+ * event-top.c (async_disable_stdin, async_disable_stdin): Use
+ target_terminal_ours / target_terminal_inferior to transfer
+ ownership of the terminal between GDB and the target.
+
+1999-09-27 Elena Zannoni <ezannoni@kwikemart.cygnus.com>
+
+ * infcmd.c (run_command): Call async_disable_stdin() only if
+ dealing with an asynchronous target.
+
+Mon Sep 27 11:48:38 1999 Andrew Cagney <cagney@b1.cygnus.com>
+
+ * target.h (struct target_ops): Add to_can_async_p, to_is_async_p,
+ to_async. Delete to_has_async. These correspond well with
+ SERIAL* async methods.
+ (target_can_async_p, target_is_async_p, target_async): Define.
+ * target.c (update_current_target, cleanup_target): Update.
+
+ * remote.c (remote_async_open_1): Change target to async using
+ target_async.
+ (remote_can_async_p, remote_is_async_p, remote_async): New
+ functions.
+ (remote_async_wait, remote_async_open_1): Add FIXME about how
+ wait_forever_enabled_p can almost be deleted once the client can
+ enable/disable target_async.
+
+ * breakpoint.c (until_break_command), infrun.c (proceed), infcmd.c
+ (run_command, continue_command, step_1, jump_command,
+ until_command, finish_command, interrupt_target_command), top.c
+ (return_to_top_level, execute_command), event-top.c
+ (command_handler): Replace target_has_async with
+ target_can_async_p.
+
+Sun Sep 26 02:10:47 1999 Andrew Cagney <cagney@b1.cygnus.com>
+
+ * remote.c (remote_async_open_1): If we go into async mode, never
+ wait for ever.
+
+ * infcmd.c: Include "event-top.h".
+ (run_command, continue_command, jump_command, until_command,
+ finish_command): Use async_disable_stdin to disable the console
+ for synchronous commands.
+
+ * remote.c (async_interrupt_query): Only disconnect the console
+ from the terminal when sync_execution.
+
+ * remote.c (initialize_sigint_signal_handler): Move declaration
+ from here.
+ * remote.h: To here. Make non-static.
+
+ * remote.c (remote_async_resume, async_interrupt_query): Move
+ prompt code from here.
+ * event-top.c (async_disable_stdin, async_enable_stdin): To
+ here. New function.
+
+ * infrun.c (start_remote): Delete commented out code.
+
+Fri Sep 24 12:38:31 1999 Andrew Cagney <cagney@b1.cygnus.com>
+
+ * remote.c (remote_async_open_1): Perform the initial async_open
+ using only synchronous calls. Only after the target is fully
+ connected, switch to async mode. Include FIXME about now it
+ currently works VS how it should be working.
+ (remote_async_open_1, set_extended_protocol): Delete function
+ set_extended_protocol. All open communication is now done
+ synchronously.
+ (forever_enabled_p): New variable. Determine if remote_async_wait
+ should block FOREVER when fetching target information.
+ (remote_cisco_open, remote_open_1): Set forever_enabled_p.
+
+ * infrun.c (start_remote): During the initial connect, always use
+ a synchronous wait.
+
+Sat Sep 25 18:13:38 1999 Andrew Cagney <cagney@b1.cygnus.com>
+
+ * Makefile.in (event-top.o): Add dependency.
+ * event-top.c: Include "remote.h".
+ * remote.c (async_interrupt_query), event-top.c:
+ (async_enable_stdin): Pass dummy parameter to
+ cleanup_sigint_signal_handler.
+ * remote.c (cleanup_sigint_signal_handler), remote.h
+ (cleanup_sigint_signal_handler), event-top.c (async_enable_stdin),
+ event-top.h (async_enable_stdin): Change signature to match
+ make_exec_error_cleanup handler pararameter.
+
+Thu Sep 23 20:48:22 1999 Andrew Cagney <cagney@b1.cygnus.com>
+
+ * defs.h (enum command_class): Move from here.
+ * command.h (command_class): To here.
+
+1999-09-24 Kevin Buettner <kevinb@cygnus.com>
+ * breakpoint.c (bpstat_stop_status): Use not_a_breakpoint to
+ help properly set bp_addr.
+ * infrun.c (handle_inferior_event): Simplify calls to
+ bp_stop_status.
+
+1999-09-24 Elena Zannoni <ezannoni@kwikemart.cygnus.com>
+
+ * top.c (return_to_top_level): Do exec_error cleanups if are
+ interrupting a simulated synchronous execution command.
+
+ * infrun.c (start_remote): Create a cleanup to enable stdin in
+ case of error from this command.
+ (complete_execution): Do the enabling of stdin via the exec_error
+ cleanups, when needed.
+
+ * remote.c (remote_async_resume): Make sure we re-enable stdin in
+ case of error from the target.
+ (handle_remote_sigint_twice): The handler to be set is
+ async_remote_interrupt_twice, not async_remote_interrupt.
+ (async_remote_interrupt_twice): Don't do anything if the target
+ has been killed already. Call async_interrupt_query, instead of
+ interrupt_query.
+ (async_interrupt_query): New function. Async case of
+ interrupt_query().
+
+ * event-top.c (async_enable_stdin): New function. Reinstate stdin
+ with the event loop.
+ * event-top.h (async_enable_stdin): Export.
+
+ * utils.c (exec_error_cleanup_chain): New cleanup chain.
+ (make_exec_error_cleanup, do_exec_error_cleanups,
+ discard_exec_error_cleanups): New functions.
+ * defs.h (make_exec_error_cleanup, do_exec_error_cleanups,
+ discard_exec_error_cleanups): Export.
+
+1999-09-24 Jim Blandy <jimb@zwingli.cygnus.com>
+
+ * ax-gdb.c (expr_to_agent): Don't forget to pass argument to
+ new_agent_expr.
+
+1999-09-24 Elena Zannoni <ezannoni@kwikemart.cygnus.com>
+
+ * event-loop.c (fetch_inferior_event_wrapper): New
+ function. Wrapper to pass to catch_errors.
+ (inferior_event_handler): Pop the target if things go bad with it.
+ Call fetch_inferior_event() from within catch_errors().
+
+1999-09-24 Jim Blandy <jimb@zwingli.cygnus.com>
+
+ * ax-gdb.c: Use internal_error instead of error, where
+ appropriate.
+
+1999-09-23 James Ingham <jingham@leda.cygnus.com>
+
+ * target.c (target_resize_to_sections): New function. Gather the
+ resizing code for the to_sections field into one place, and make
+ sure you update the other targets that are sharing the to_sections
+ structure.
+ * target.h: Declare the target_resize_to_sections function.
+ * solib.c (solib_add): use target_resize_to_sections.
+ * somsolib.c (som_solib_load_symbols): ditto
+ * rs6000-nat.c (xcoff_relocate_core): ditto
+ * pa64solib.c (pa64_solib_load_symbols): ditto
+ * irix5-nat.c (solib_add):ditto
+
+ * top.c: Define the attach & detach hooks
+ * defs.h: Declare the attach & detach hooks.
+ * infcmd.c (attach_command): call the attach hook if it exists.
+ (detach_command): call the detach hook if it exists.
+
+ * complaints.c (complain): Send the complaints to stderr rather
+ than stdout, so they don't get mixed into the result stream from
+ commands.
+
+1999-09-23 Elena Zannoni <ezannoni@kwikemart.cygnus.com>
+
+ * event-loop.c (poll_timers): Use correct timeval field names,
+ when setting the notifier timeouts, in case of select() used.
+ (gdb_wait_for_event): Pass a pointer to the timeout structure to
+ select(), not the structure.
+
+Wed Sep 22 10:35:32 1999 Andrew Cagney <cagney@b1.cygnus.com>
+
+ * Makefile.in (init.c): Change generated file to include "defs.h"
+ and "call-cmds.h". Use initialize_file_ftype when declaring
+ each initialize functions.
+ (call_cmds_h): Add definition.
+ (init.o): Add target and dependencies.
+ (init.c): Don't grep for _initialize* in init.c.
+
+ * defs.h (initialize_file_ftype): Add function typedef.
+
+1999-09-22 Michael Snyder <msnyder@cleaver.cygnus.com>
+
+ * procfs.c (init_procinfo): move fltset initialization to caller.
+ (do_attach, create_procinfo): initialize fltset.
+
+1999-09-22 Elena Zannoni <ezannoni@kwikemart.cygnus.com>
+
+ * event-loop.c, event-top.c, event-loop.h: Rerun indent.
+
+1999-09-21 Doug Evans <devans@casey.cygnus.com>
+
+ * m32r-stub.c (handle_exception): Fix typo in patch of 1999-08-26.
+
Tue Sep 21 14:55:29 1999 Andrew Cagney <cagney@b1.cygnus.com>
From 1999-08-20 J.T. Conklin <jtc@redback.com>:
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 = 19990921
+VERSION = 19990928
DIST=gdb
LINT=/usr/5bin/lint
command_h = command.h
gdbcmd_h = gdbcmd.h $(command_h)
+call_cmds_h = call-cmds.h
defs_h = defs.h xm.h tm.h nm.h config.status config.h gdbarch.h
top_h = top.h
init.c: $(OBS) $(TSOBS)
@echo Making init.c
- @rm -f init.c-tmp
- @echo '/* Do not modify this file. */' >init.c-tmp
- @echo '/* It is created automatically by the Makefile. */'>>init.c-tmp
- @echo '#include "ansidecl.h"' >>init.c-tmp
- @echo 'extern void initialize_all_files PARAMS ((void));' >>init.c-tmp
- @echo 'void initialize_all_files PARAMS ((void)) {' >>init.c-tmp
+ @rm -f init.c-tmp init.l-tmp
@-echo $(OBS) $(TSOBS) | \
tr ' ' '\012' | \
sed -e '/^Onindy.o/d' \
+ -e '/^init.o/d' \
-e '/^nindy.o/d' \
-e '/ttyflush.o/d' \
-e '/xdr_ld.o/d' \
-e 's/\.o/.c/' \
-e 's|\([^ ][^ ]*\)|$(srcdir)/\1|g' | \
while read f; do grep '^_initialize_[a-z_0-9A-Z]* *(' $$f 2>/dev/null; done | \
- sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 PARAMS ((void)); \1 ();}/' >>init.c-tmp
+ sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/\1/' > init.l-tmp
+ @echo '/* Do not modify this file. */' >>init.c-tmp
+ @echo '/* It is created automatically by the Makefile. */'>>init.c-tmp
+ @echo '#include "defs.h"' >>init.c-tmp
+ @echo '#include "call-cmds.h"' >>init.c-tmp
+ @sed -e 's/\(.*\)/extern initialize_file_ftype \1;/' <init.l-tmp >>init.c-tmp
+ @echo 'void' >>init.c-tmp
+ @echo 'initialize_all_files (void)' >>init.c-tmp
+ @echo '{' >>init.c-tmp
+ @sed -e 's/\(.*\)/ \1 ();/' <init.l-tmp >>init.c-tmp
@echo '}' >>init.c-tmp
+ @rm init.l-tmp
@mv init.c-tmp init.c
.PRECIOUS: init.c
+init.o: init.c $(defs_h) $(call_cmds_h)
+
# Removing the old gdb first works better if it is running, at least on SunOS.
gdb$(EXEEXT): main.o libgdb.a $(ADD_DEPS) $(CDEPS) $(TDEPLIBS)
rm -f gdb$(EXEEXT)
clean mostlyclean:
@$(MAKE) $(FLAGS_TO_PASS) DO=clean "DODIRS=$(SUBDIRS)" subdir_do
- rm -f *.o *.a $(ADD_FILES) *~ init.c-tmp
+ rm -f *.o *.a $(ADD_FILES) *~ init.c-tmp init.l-tmp
rm -f init.c version.c
rm -f gdb$(EXEEXT) core make.log
rm -f gdb[0-9]$(EXEEXT)
event-loop.o: event-loop.c $(defs_h) $(top_h) $(event_loop_h) $(event_top_h)
event-top.o: event-top.c top.h $(readline_headers) \
- $(defs_h) $(inferior_h) $(event_loop_h) $(event_top_h) terminal.h $(gdbcmd_h)
+ $(defs_h) $(inferior_h) $(event_loop_h) $(event_top_h) terminal.h \
+ $(gdbcmd_h)
exec.o: exec.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) $(inferior_h) \
target.h language.h gdb_string.h
gdb-events.o: gdb-events.c gdb-events.h $(defs_h) $(gdbcmd_h)
-
### end of the gdb Makefile.in.
#include "ax.h"
#include "ax-gdb.h"
-/* Probably the best way to read this file is to start with the types
- and enums in ax-gdb.h, and then look at gen_expr, towards the
- bottom; that's the main function that looks at the GDB expressions
- and calls everything else to generate code.
+/* To make sense of this file, you should read doc/agentexpr.texi.
+ Then look at the types and enums in ax-gdb.h. For the code itself,
+ look at gen_expr, towards the bottom; that's the main function that
+ looks at the GDB expressions and calls everything else to generate
+ code.
I'm beginning to wonder whether it wouldn't be nicer to internally
generate trees, with types, and then spit out the bytecode in
implementing something we should be (this code's fault).
In any case, it's a bug the user shouldn't see. */
default:
- error ("GDB bug: ax-gdb.c (gen_fetch): strange size");
+ internal_error ("ax-gdb.c (gen_fetch): strange size");
}
gen_sign_extend (ax, type);
pointer (other code's fault), or we're not implementing
something we should be (this code's fault). In any case,
it's a bug the user shouldn't see. */
- error ("GDB bug: ax-gdb.c (gen_fetch): bad type code");
+ internal_error ("ax-gdb.c (gen_fetch): bad type code");
}
}
break;
case LOC_CONST_BYTES:
- error ("GDB bug: ax-gdb.c (gen_var_ref): LOC_CONST_BYTES symbols are not supported");
+ internal_error ("ax-gdb.c (gen_var_ref): LOC_CONST_BYTES symbols are not supported");
/* Variable at a fixed location in memory. Easy. */
case LOC_STATIC:
/* The caller should check the type, because several operators use
this, and we don't know what error message to generate. */
if (value->type->code != TYPE_CODE_PTR)
- error ("GDB bug: ax-gdb.c (gen_deref): expected a pointer");
+ internal_error ("ax-gdb.c (gen_deref): expected a pointer");
/* We've got an rvalue now, which is a pointer. We want to yield an
lvalue, whose address is exactly that pointer. So we don't
/* Make sure this isn't C++. */
if (TYPE_N_BASECLASSES (type) != 0)
- error ("GDB bug: ax-gdb.c (find_field): derived classes supported");
+ internal_error ("ax-gdb.c (find_field): derived classes supported");
for (i = 0; i < TYPE_NFIELDS (type); i++)
{
return i;
if (this_name[0] == '\0')
- error ("GDB bug: ax-gdb.c (find_field): anonymous unions not supported");
+ internal_error ("ax-gdb.c (find_field): anonymous unions not supported");
}
error ("Couldn't find member named `%s' in struct/union `%s'",
/* Can we fetch the number of bits requested at all? */
if ((end - start) > ((1 << num_ops) * 8))
- error ("GDB bug: ax-gdb.c (gen_bitfield_ref): bitfield too wide");
+ internal_error ("ax-gdb.c (gen_bitfield_ref): bitfield too wide");
/* Note that we know here that we only need to try each opcode once.
That may not be true on machines with weird byte sizes. */
default:
/* We should only list operators in the outer case statement
that we actually handle in the inner case statement. */
- error ("GDB bug: ax-gdb.c (gen_expr): op case sets don't match");
+ internal_error ("ax-gdb.c (gen_expr): op case sets don't match");
}
break;
the given type, and dereference it. */
if (value->kind != axs_rvalue)
/* This would be weird. */
- error ("GDB bug: ax-gdb.c (gen_expr): OP_MEMVAL operand isn't an rvalue???");
+ internal_error ("ax-gdb.c (gen_expr): OP_MEMVAL operand isn't an rvalue???");
value->type = type;
value->kind = axs_lvalue_memory;
}
else
/* If this `if' chain doesn't handle it, then the case list
shouldn't mention it, and we shouldn't be here. */
- error ("GDB bug: ax-gdb.c (gen_expr): unhandled struct case");
+ internal_error ("ax-gdb.c (gen_expr): unhandled struct case");
}
break;
\f
-#if 0 /* not used */
/* Generating bytecode from GDB expressions: driver */
/* Given a GDB expression EXPR, produce a string of agent bytecode
struct axs_value *value;
{
struct cleanup *old_chain = 0;
- struct agent_expr *ax = new_agent_expr ();
+ struct agent_expr *ax = new_agent_expr (0);
union exp_element *pc;
old_chain = make_cleanup ((make_cleanup_func) free_agent_expr, ax);
}
+#if 0 /* not used */
/* Given a GDB expression EXPR denoting an lvalue in memory, produce a
string of agent bytecode which will leave its address and size on
the top of stack. Return the agent expression.
return ax;
}
-#endif /* 0 */
+#endif
/* Given a GDB expression EXPR, return bytecode to trace its value.
The result will use the `trace' and `trace_quick' bytecodes to
struct cleanup *old_chain = 0;
struct expression *expr;
struct agent_expr *agent;
- struct frame_info *fi = get_current_frame (); /* need current scope */
+ struct frame_info *fi = get_current_frame (); /* need current scope */
/* We don't deal with overlay debugging at the moment. We need to
think more carefully about this. If you copy this code into
char message[sizeof (message1) + 30 /* slop */ ];
/* Get the address where the breakpoint would have been. */
- bp_addr = *pc - DECR_PC_AFTER_BREAK;
+ bp_addr = *pc - (not_a_breakpoint && !SOFTWARE_SINGLE_STEP_P ?
+ 0 : DECR_PC_AFTER_BREAK);
ALL_BREAKPOINTS_SAFE (b, temp)
{
&& b->address != (*pc - DECR_PC_AFTER_HW_BREAK))
continue;
- if (b->type != bp_watchpoint
- && b->type != bp_hardware_watchpoint
- && b->type != bp_read_watchpoint
- && b->type != bp_access_watchpoint
- && not_a_breakpoint)
- continue;
-
/* Is this a catchpoint of a load or unload? If so, did we
get a load or unload of the specified library? If not,
ignore it. */
breakpoint = set_momentary_breakpoint (sal, selected_frame, bp_until);
- if (!async_p || !target_has_async)
+ if (!event_loop_p || !target_can_async_p ())
old_chain = make_cleanup ((make_cleanup_func) delete_breakpoint,
breakpoint);
else
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)
+ if (event_loop_p && target_can_async_p ())
{
/* In this case we don't need args for the continuation, because
all it needs to do is do the cleanups in the
sal = find_pc_line (prev_frame->pc, 0);
sal.pc = prev_frame->pc;
breakpoint = set_momentary_breakpoint (sal, prev_frame, bp_until);
- if (!async_p || !target_has_async)
+ if (!event_loop_p || !target_can_async_p ())
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 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)
+ if (!event_loop_p || !target_can_async_p ())
do_cleanups (old_chain);
}
\f
#if !defined (COMMAND_H)
#define COMMAND_H 1
+/* Command classes are top-level categories into which commands are broken
+ down for "help" purposes.
+ Notes on classes: class_alias is for alias commands which are not
+ abbreviations of the original command. class-pseudo is for
+ commands which are not really commands nor help topics ("stop"). */
+
+enum command_class
+{
+ /* Special args to help_list */
+ class_deprecated, all_classes = -2, all_commands = -1,
+ /* Classes of commands */
+ no_class = -1, class_run = 0, class_vars, class_stack,
+ class_files, class_support, class_info, class_breakpoint, class_trace,
+ class_alias, class_obscure, class_user, class_maintenance,
+ class_pseudo, class_tui, class_xdb,
+};
+
/* Not a set/show command. Note that some commands which begin with
"set" or "show" might be in this category, if their syntax does
not fall into one of the following categories. */
/* Isolated messages, must be self-explanatory. */
case 0:
begin_line ();
- puts_filtered ("During symbol reading, ");
+ fputs_filtered ("During symbol reading, ", gdb_stderr);
wrap_here ("");
- vprintf_filtered (complaint->message, args);
- puts_filtered (".\n");
+ vfprintf_filtered (gdb_stderr, complaint->message, args);
+ fputs_filtered (".\n", gdb_stderr);
break;
/* First of a series, without `set verbose'. */
case 1:
begin_line ();
- puts_filtered ("During symbol reading...");
- vprintf_filtered (complaint->message, args);
- puts_filtered ("...");
+ fputs_filtered ("During symbol reading...", gdb_stderr);
+ vfprintf_filtered (gdb_stderr, complaint->message, args);
+ fputs_filtered ("...", gdb_stderr);
wrap_here ("");
complaint_series++;
break;
(We'll already have produced a "Reading in symbols for XXX..."
message and will clean up at the end with a newline.) */
default:
- vprintf_filtered (complaint->message, args);
- puts_filtered ("...");
+ vfprintf_filtered (gdb_stderr, complaint->message, args);
+ fputs_filtered ("...", gdb_stderr);
wrap_here ("");
}
/* If GDB dumps core, we'd like to see the complaints first. Presumably
GDB will not be sending so many complaints that this becomes a
performance hog. */
- gdb_flush (gdb_stdout);
+ gdb_flush (gdb_stderr);
va_end (args);
}
}
#endif
-/* Command classes are top-level categories into which commands are broken
- down for "help" purposes.
- Notes on classes: class_alias is for alias commands which are not
- abbreviations of the original command. class-pseudo is for commands
- which are not really commands nor help topics ("stop"). */
-
-enum command_class
-{
- /* Special args to help_list */
- all_classes = -2, all_commands = -1,
- /* Classes of commands */
- no_class = -1, class_run = 0, class_vars, class_stack,
- class_files, class_support, class_info, class_breakpoint, class_trace,
- class_alias, class_obscure, class_user, class_maintenance,
- class_pseudo, class_tui, class_xdb
-};
-
/* Languages represented in the symbol table and elsewhere.
This should probably be in language.h, but since enum's can't
be forward declared to satisfy opaque references before their
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 do_exec_error_cleanups PARAMS ((struct cleanup *));
extern void discard_cleanups PARAMS ((struct cleanup *));
extern void discard_final_cleanups PARAMS ((struct cleanup *));
+extern void discard_exec_error_cleanups PARAMS ((struct cleanup *));
extern void discard_my_cleanups PARAMS ((struct cleanup **, struct cleanup *));
typedef void (*make_cleanup_func) PARAMS ((void *));
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 *make_exec_error_cleanup PARAMS ((make_cleanup_func, void *));
extern struct cleanup *save_cleanups PARAMS ((void));
extern struct cleanup *save_final_cleanups PARAMS ((void));
/* From top.c */
+typedef void initialize_file_ftype (void);
+
extern char *skip_quoted PARAMS ((char *));
extern char *gdb_readline PARAMS ((char *));
/* Should the asynchronous variant of the interpreter (using the
event-loop) be enabled? */
-extern int async_p;
+extern int event_loop_p;
extern void (*init_ui_hook) PARAMS ((char *argv0));
extern void (*command_loop_hook) PARAMS ((void));
extern int (*target_wait_hook) PARAMS ((int pid,
struct target_waitstatus *status));
+extern void (*attach_hook) PARAMS ((void));
+extern void (*detach_hook) PARAMS ((void));
extern void (*call_command_hook) PARAMS ((struct cmd_list_element *c,
char *cmd, int from_tty));
extern void _initialize_elfread PARAMS ((void));
/* The struct elfinfo is available only during ELF symbol table and
- psymtab reading. It is destroyed at the complation of psymtab-reading.
+ psymtab reading. It is destroyed at the completion of psymtab-reading.
It's local to elf_symfile_read. */
struct elfinfo
#include "top.h"
#include "event-loop.h"
#include "event-top.h"
-#include "inferior.h" /* For fetch_inferior_event. */
+#include "inferior.h" /* For fetch_inferior_event. */
#ifdef HAVE_POLL
#include <poll.h>
#else
int mask; /* Events we want to monitor: POLLIN, etc. */
int ready_mask; /* Events that have been seen since
the last time. */
- handler_func *proc; /* Procedure to call when fd is ready. */
+ handler_func *proc; /* Procedure to call when fd is ready. */
gdb_client_data client_data; /* Argument to pass to proc. */
- int error; /* Was an error detected on this fd? */
+ int error; /* Was an error detected on this fd? */
struct file_handler *next_file; /* Next registered file descriptor. */
}
file_handler;
int ready; /* If ready, call this handler from the main event loop,
using invoke_async_handler. */
struct async_signal_handler *next_handler; /* Ptr to next handler */
- sig_handler_func *proc; /* Function to call to do the work */
+ sig_handler_func *proc; /* Function to call to do the work */
gdb_client_data client_data; /* Argument to async_handler_func */
}
async_signal_handler;
/* Flag to tell whether the timeout struct should be used. */
int timeout_valid;
- }
+ }
gdb_notifier;
#endif /* HAVE_POLL */
struct timeval when;
int timer_id;
struct gdb_timer *next;
- timer_handler_func *proc; /* Function to call to do the work */
- gdb_client_data client_data; /* Argument to async_handler_func */
+ timer_handler_func *proc; /* Function to call to do the work */
+ gdb_client_data client_data; /* Argument to async_handler_func */
}
gdb_timer;
/* List of currently active timers. It is sorted in order of
- increasing timers.*/
+ increasing timers. */
static struct
{
/* Pointer to first in timer list. */
function. */
static int async_handler_ready = 0;
-static void create_file_handler (int fd, int mask, handler_func *proc, gdb_client_data client_data);
+static void create_file_handler (int fd, int mask, handler_func * proc, gdb_client_data client_data);
static void invoke_async_signal_handler (void);
static void handle_file_event (int event_file_desc);
static int gdb_wait_for_event (void);
static int gdb_do_one_event (void);
static int check_async_ready (void);
-static void async_queue_event (gdb_event *event_ptr, queue_position position);
-static gdb_event * create_file_event (int fd);
+static void async_queue_event (gdb_event * event_ptr, queue_position position);
+static gdb_event *create_file_event (int fd);
static int process_event (void);
static void handle_timer_event (int dummy);
static void poll_timers (void);
+static int fetch_inferior_event_wrapper (gdb_client_data client_data);
\f
/* Insert an event object into the gdb event queue at
as last in first out. Event appended at the tail of the queue
will be processed first in first out. */
static void
-async_queue_event (gdb_event *event_ptr, queue_position position)
+async_queue_event (gdb_event * event_ptr, queue_position position)
{
if (position == TAIL)
{
break;
}
- /* Are any timers that are ready? If so, put an event on the queue.*/
+ /* Are any timers that are ready? If so, put an event on the queue. */
poll_timers ();
/* Wait for a new event. If gdb_wait_for_event returns -1,
doesn't have to know implementation details about the use of poll
vs. select. */
void
-add_file_handler (int fd, handler_func *proc, gdb_client_data client_data)
+add_file_handler (int fd, handler_func * proc, gdb_client_data client_data)
{
#ifdef HAVE_POLL
create_file_handler (fd, POLLIN, proc, client_data);
PROC is the procedure that will be called when an event occurs for
FD. CLIENT_DATA is the argument to pass to PROC. */
static void
-create_file_handler (int fd, int mask, handler_func *proc, gdb_client_data client_data)
+create_file_handler (int fd, int mask, handler_func * proc, gdb_client_data client_data)
{
file_handler *file_ptr;
}
/* It is a new file descriptor. Add it to the list. Otherwise, just
- change the data associated with it.*/
+ change the data associated with it. */
if (file_ptr == NULL)
{
file_ptr = (file_handler *) xmalloc (sizeof (file_handler));
if (error_mask_returned != 0)
{
/* Work in progress. We may need to tell somebody what
- kind of error we had. */
+ kind of error we had. */
/*if (error_mask_returned & POLLHUP)
- printf_unfiltered ("Hangup detected on fd %d\n", file_ptr->fd);
- if (error_mask_returned & POLLERR)
- printf_unfiltered ("Error detected on fd %d\n", file_ptr->fd);
- if (error_mask_returned & POLLNVAL)
- printf_unfiltered ("Invalid fd %d\n", file_ptr->fd);*/
+ printf_unfiltered ("Hangup detected on fd %d\n", file_ptr->fd);
+ if (error_mask_returned & POLLERR)
+ printf_unfiltered ("Error detected on fd %d\n", file_ptr->fd);
+ if (error_mask_returned & POLLNVAL)
+ printf_unfiltered ("Invalid fd %d\n", file_ptr->fd); */
file_ptr->error = 1;
- }
- else
+ }
+ else
file_ptr->error = 0;
#else /* ! HAVE_POLL */
if (file_ptr->ready_mask & GDB_EXCEPTION)
#ifdef HAVE_POLL
num_found =
- poll (gdb_notifier.poll_fds,
- (unsigned long) gdb_notifier.num_fds,
+ poll (gdb_notifier.poll_fds,
+ (unsigned long) gdb_notifier.num_fds,
gdb_notifier.timeout_valid ? gdb_notifier.timeout : -1);
/* Don't print anything if we get out of poll because of a
- signal.*/
+ signal. */
if (num_found == -1 && errno != EINTR)
perror_with_name ("Poll");
num_found = select (gdb_notifier.num_fds,
(SELECT_MASK *) & gdb_notifier.ready_masks[0],
(SELECT_MASK *) & gdb_notifier.ready_masks[MASK_SIZE],
- (SELECT_MASK *) & gdb_notifier.ready_masks[2 * MASK_SIZE],
- gdb_notifier.timeout_valid ? gdb_notifier.timeout : NULL);
+ (SELECT_MASK *) & gdb_notifier.ready_masks[2 * MASK_SIZE],
+ gdb_notifier.timeout_valid ? &gdb_notifier.timeout : NULL);
/* Clear the masks after an error from select. */
if (num_found == -1)
PROC is the function to call with CLIENT_DATA argument
whenever the handler is invoked. */
async_signal_handler *
-create_async_signal_handler (sig_handler_func *proc, gdb_client_data client_data)
+create_async_signal_handler (sig_handler_func * proc, gdb_client_data client_data)
{
async_signal_handler *async_handler_ptr;
some event. The caller of this function is the interrupt handler
associated with a signal. */
void
-mark_async_signal_handler (async_signal_handler *async_handler_ptr)
+mark_async_signal_handler (async_signal_handler * async_handler_ptr)
{
((async_signal_handler *) async_handler_ptr)->ready = 1;
async_handler_ready = 1;
/* Delete an asynchronous handler (ASYNC_HANDLER_PTR).
Free the space allocated for it. */
void
-delete_async_signal_handler (async_signal_handler **async_handler_ptr)
+delete_async_signal_handler (async_signal_handler ** async_handler_ptr)
{
async_signal_handler *prev_ptr;
{
printf_unfiltered ("error detected on fd %d\n", fd);
delete_file_handler (fd);
+ pop_target ();
discard_all_continuations ();
}
else
- fetch_inferior_event (client_data);
+ /* Use catch errors for now, until the inner layers of
+ fetch_inferior_event (i.e. readchar) can return meaningful
+ error status. If an error occurs while getting an event from
+ the target, just get rid of the target. */
+ if (!catch_errors (fetch_inferior_event_wrapper, client_data, "", RETURN_MASK_ALL))
+ {
+ delete_file_handler (fd);
+ discard_all_continuations ();
+ pop_target ();
+ display_gdb_prompt (0);
+ }
+}
+
+static int
+fetch_inferior_event_wrapper (gdb_client_data client_data)
+{
+ fetch_inferior_event (client_data);
+ return 1;
}
/* Create a timer that will expire in MILLISECONDS from now. When the
timer is ready, PROC will be executed. At creation, the timer is
aded to the timers queue. This queue is kept sorted in order of
- increasing timers. Return a handle to the timer struct.*/
+ increasing timers. Return a handle to the timer struct. */
int
-create_timer (int milliseconds, timer_handler_func *proc, gdb_client_data client_data)
+create_timer (int milliseconds, timer_handler_func * proc, gdb_client_data client_data)
{
struct gdb_timer *timer_ptr, *timer_index, *prev_timer;
struct timeval time_now, delta;
/* compute seconds */
delta.tv_sec = milliseconds / 1000;
/* compute microseconds */
- delta.tv_usec = (milliseconds % 1000) * 1000;
-
+ delta.tv_usec = (milliseconds % 1000) * 1000;
+
gettimeofday (&time_now, NULL);
timer_ptr = (struct gdb_timer *) xmalloc (sizeof (gdb_timer));
timer_ptr->when.tv_sec = time_now.tv_sec + delta.tv_sec;
timer_ptr->when.tv_usec = time_now.tv_usec + delta.tv_usec;
/* carry? */
- if (timer_ptr->when.tv_usec >= 1000000 )
+ if (timer_ptr->when.tv_usec >= 1000000)
{
timer_ptr->when.tv_sec += 1;
timer_ptr->when.tv_usec -= 1000000;
}
timer_ptr->proc = proc;
timer_ptr->client_data = client_data;
- timer_list.num_timers ++;
+ timer_list.num_timers++;
timer_ptr->timer_id = timer_list.num_timers;
/* Now add the timer to the timer queue, making sure it is sorted in
increasing order of expiration. */
- for (timer_index = timer_list.first_timer;
- timer_index != NULL;
+ for (timer_index = timer_list.first_timer;
+ timer_index != NULL;
timer_index = timer_index->next)
{
/* If the seconds field is greater or if it is the same, but the
microsecond field is greater. */
- if ((timer_index->when.tv_sec > timer_ptr->when.tv_sec) ||
+ if ((timer_index->when.tv_sec > timer_ptr->when.tv_sec) ||
((timer_index->when.tv_sec == timer_ptr->when.tv_sec)
&& (timer_index->when.tv_usec > timer_ptr->when.tv_usec)))
break;
}
-
+
if (timer_index == timer_list.first_timer)
{
timer_ptr->next = timer_list.first_timer;
}
else
{
- for (prev_timer = timer_list.first_timer;
- prev_timer->next != timer_index;
+ for (prev_timer = timer_list.first_timer;
+ prev_timer->next != timer_index;
prev_timer = prev_timer->next)
;
-
+
prev_timer->next = timer_ptr;
timer_ptr->next = timer_index;
}
/* When a timer event is put on the event queue, it will be handled by
this function. Just call the assiciated procedure and delete the
timer event from the event queue. Repeat this for each timer that
- has expired.*/
+ has expired. */
static void
handle_timer_event (int dummy)
{
struct timeval time_now;
struct gdb_timer *timer_ptr, *saved_timer;
-
+
gettimeofday (&time_now, NULL);
timer_ptr = timer_list.first_timer;
while (timer_ptr != NULL)
{
- if ((timer_ptr->when.tv_sec > time_now.tv_sec) ||
- ((timer_ptr->when.tv_sec == time_now.tv_sec) &&
+ if ((timer_ptr->when.tv_sec > time_now.tv_sec) ||
+ ((timer_ptr->when.tv_sec == time_now.tv_sec) &&
(timer_ptr->when.tv_usec > time_now.tv_usec)))
break;
gdb_notifier.timeout_valid = 0;
}
-
+
/* Check whether any timers in the timers queue are ready. If at least
one timer is ready, stick an event onto the event queue. Even in
case more than one timer is ready, one event is enough, because the
handle_timer_event() will go through the timers list and call the
procedures associated with all that have expired. Update the
- timeout for the select() or poll() as well.*/
+ timeout for the select() or poll() as well. */
static void
poll_timers (void)
{
struct timeval time_now, delta;
gdb_event *event_ptr;
-
+
if (timer_list.num_timers)
{
gettimeofday (&time_now, NULL);
delta.tv_sec -= 1;
delta.tv_usec += 1000000;
}
-
+
/* Oops it expired already. Tell select / poll to return
- immediately. */
+ immediately. */
if (delta.tv_sec < 0)
{
delta.tv_sec = 0;
}
/* Now we need to update the timeout for select/ poll, because we
- don't want to sit there while this timer is expiring. */
+ don't want to sit there while this timer is expiring. */
#ifdef HAVE_POLL
- gdb_notifier.timeout = delta.tv_sec * 1000;
+ gdb_notifier.timeout = delta.tv_sec * 1000;
#else
- gdb_notifier.timeout.sec = delta.tv_sec;
- gdb_notifier.timeout.usec = delta.tv_usec;
+ gdb_notifier.timeout.tv_sec = delta.tv_sec;
+ gdb_notifier.timeout.tv_usec = delta.tv_usec;
#endif
gdb_notifier.timeout_valid = 1;
}
- else
+ else
gdb_notifier.timeout_valid = 0;
}
extern void start_event_loop (void);
extern void delete_file_handler (int fd);
-extern void add_file_handler (int fd, handler_func *proc, gdb_client_data client_data);
+extern void add_file_handler (int fd, handler_func * proc, gdb_client_data client_data);
extern void mark_async_signal_handler (struct async_signal_handler *async_handler_ptr);
-extern struct async_signal_handler *
- create_async_signal_handler (sig_handler_func *proc, gdb_client_data client_data);
-extern void delete_async_signal_handler (struct async_signal_handler ** async_handler_ptr);
+extern struct async_signal_handler *
+ create_async_signal_handler (sig_handler_func * proc, gdb_client_data client_data);
+extern void delete_async_signal_handler (struct async_signal_handler **async_handler_ptr);
extern void inferior_event_handler (int error, gdb_client_data client_data, int fd);
-extern int create_timer (int milliseconds, timer_handler_func *proc, gdb_client_data client_data);
+extern int create_timer (int milliseconds, timer_handler_func * proc, gdb_client_data client_data);
extern void delete_timer (int id);
-
-
-
-
char *gdb_prompt = get_prompt ();
- if (target_executing && sync_execution)
+ if (target_executing && sync_execution)
{
/* This is to trick readline into not trying to display the
- prompt. Even though we display the prompt using this
- function, readline still tries to do its own display if we
- don't call rl_callback_handler_install and
- rl_callback_handler_remove (which readline detects because a
- global variable is not set). If readline did that, it could
- mess up gdb signal handlers for SIGINT. Readline assumes
- that between calls to rl_set_signals and rl_clear_signals gdb
- doesn't do anything with the signal handlers. Well, that's
- not the case, because when the target executes we change the
- SIGINT signal handler. If we allowed readline to display the
- prompt, the signal handler change would happen exactly
- between the calls to the above two functions.
- Calling rl_callback_handler_remove(), does the job. */
+ prompt. Even though we display the prompt using this
+ function, readline still tries to do its own display if we
+ don't call rl_callback_handler_install and
+ rl_callback_handler_remove (which readline detects because a
+ global variable is not set). If readline did that, it could
+ mess up gdb signal handlers for SIGINT. Readline assumes
+ that between calls to rl_set_signals and rl_clear_signals gdb
+ doesn't do anything with the signal handlers. Well, that's
+ not the case, because when the target executes we change the
+ SIGINT signal handler. If we allowed readline to display the
+ prompt, the signal handler change would happen exactly
+ between the calls to the above two functions.
+ Calling rl_callback_handler_remove(), does the job. */
rl_callback_handler_remove ();
return;
exit (1);
}
else
- (*call_readline) (client_data);
+ (*call_readline) (client_data);
}
+/* Re-enable stdin after the end of an execution command in
+ synchronous mode, or after an error from the target, and we aborted
+ the exec operation. */
+
+void
+async_enable_stdin (void *dummy)
+{
+ /* See NOTE in async_disable_stdin() */
+ /* FIXME: cagney/1999-09-27: Call this before clearing
+ sync_execution. Current target_terminal_ours() implementations
+ check for sync_execution before switching the terminal. */
+ target_terminal_ours ();
+ pop_prompt ();
+ sync_execution = 0;
+}
+
+/* Disable reads from stdin (the console) marking the command as
+ synchronous. */
+
+void
+async_disable_stdin (void)
+{
+ sync_execution = 1;
+ push_prompt ("", "", "");
+ /* FIXME: cagney/1999-09-27: At present this call is technically
+ redundant since infcmd.c and infrun.c both already call
+ target_terminal_inferior(). As the terminal handling (in
+ sync/async mode) is refined, the duplicate calls can be
+ eliminated (Here or in infcmd.c/infrun.c). */
+ target_terminal_inferior ();
+ make_exec_cleanup (async_enable_stdin, NULL);
+ make_exec_error_cleanup (async_enable_stdin, NULL);
+}
\f
+
/* Handles a gdb command. This function is called by
command_line_handler, which has processed one or more input lines
into COMMAND. */
/* 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)
+ if (target_can_async_p () && target_executing)
{
arg1 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
/* 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)
+ if (!target_can_async_p () || !target_executing)
{
bpstat_do_actions (&stop_bpstat);
do_cleanups (old_chain);
void
_initialize_event_loop (void)
{
- if (async_p)
+ if (event_loop_p)
{
/* When a character is detected on instream by select or poll,
readline will be invoked via this callback function. */
extern void mark_async_signal_handler_wrapper (PTR token);
extern void async_request_quit (gdb_client_data arg);
extern void stdin_event_handler (int error, int fd, gdb_client_data client_data);
+extern void async_disable_stdin (void);
+extern void async_enable_stdin (void *dummy);
/* Exported variables from event-top.c.
FIXME: these should really go into top.h. */
/* It must also be an import stub. */
u = find_unwind_entry (SYMBOL_VALUE (stub_symbol));
- if (!u
- || (u->stub_unwind.stub_type != IMPORT)
- && u->stub_unwind.stub_type != IMPORT_SHLIB)
+ if (u == NULL
+ || (u->stub_unwind.stub_type != IMPORT
+#ifdef GDB_NATIVE_HPUX_11
+ /* Sigh. The hpux 10.20 dynamic linker will blow
+ chunks if we perform a call to an unbound function
+ via the IMPORT_SHLIB stub. The hpux 11.00 dynamic
+ linker will blow chunks if we do not call the
+ unbound function via the IMPORT_SHLIB stub.
+
+ We currently have no way to select bevahior on just
+ the target. However, we only support HPUX/SOM in
+ native mode. So we conditinalize on a native
+ #ifdef. Ugly. Ugly. Ugly */
+ && u->stub_unwind.stub_type != IMPORT_SHLIB
+#endif
+ ))
continue;
/* OK. Looks like the correct import stub. */
newfun = SYMBOL_VALUE (stub_symbol);
fun = newfun;
+
+ /* If we found an IMPORT stub, then we want to stop
+ searching now. If we found an IMPORT_SHLIB, we want
+ to continue the search in the hopes that we will find
+ an IMPORT stub. */
+ if (u->stub_unwind.stub_type == IMPORT)
+ break;
}
}
|| (inst & 0xffffc00c) == 0x73c10008)
save_sp = 0;
+ /* Are we loading some register with an offset from the argument
+ pointer? */
+ if ((inst & 0xffe00000) == 0x37a00000
+ || (inst & 0xffffffe0) == 0x081d0240)
+ {
+ pc += 4;
+ continue;
+ }
+
/* Account for general and floating-point register saves. */
reg_num = inst_saves_gr (inst);
save_gr &= ~(1 << reg_num);
FIXME. Can still die if we have a mix of GR and FR argument
stores! */
- if (reg_num >= 23 && reg_num <= 26)
+ if (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
{
- while (reg_num >= 23 && reg_num <= 26)
+ while (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
{
pc += 4;
status = target_read_memory (pc, buf, 4);
save. */
if ((inst & 0xfc000000) == 0x34000000
&& inst_saves_fr (next_inst) >= 4
- && inst_saves_fr (next_inst) <= 7)
+ && inst_saves_fr (next_inst) <= (TARGET_PTR_BIT == 64 ? 11 : 7))
{
/* So we drop into the code below in a reasonable state. */
reg_num = inst_saves_fr (next_inst);
This is a kludge as on the HP compiler sets this bit and it
never does prologue scheduling. So once we see one, skip past
all of them. */
- if (reg_num >= 4 && reg_num <= 7)
+ if (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
{
- while (reg_num >= 4 && reg_num <= 7)
+ while (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
{
pc += 8;
status = target_read_memory (pc, buf, 4);
#include "symfile.h"
#include "objfiles.h"
#include "event-loop.h"
+#include "event-top.h"
#include "parser-defs.h"
/* Functions exported for general use: */
want them to go away (PR 2207). This is probably reasonable. */
if (!args)
- sync_execution = 1;
+ {
+ if (event_loop_p && target_can_async_p ())
+ async_disable_stdin ();
+ }
else
{
char *cmd;
/* 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)
+ if (event_loop_p && async_exec && !target_can_async_p ())
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)
+ if (event_loop_p && !async_exec && target_can_async_p ())
{
/* Simulate synchronous execution */
- sync_execution = 1;
+ async_disable_stdin ();
}
/* If there were other args, beside '&', process them. */
/* If we must run in the background, but the target can't do it,
error out. */
- if (async_p && async_exec && !target_has_async)
+ if (event_loop_p && async_exec && !target_can_async_p ())
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)
+ if (event_loop_p && !async_exec && target_can_async_p ())
{
/* Simulate synchronous execution */
- sync_execution = 1;
+ async_disable_stdin ();
}
/* If have argument (besides '&'), set proceed count of breakpoint
/* 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)
+ if (event_loop_p && async_exec && !target_can_async_p ())
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)
+ if (event_loop_p && !async_exec && target_can_async_p ())
{
/* Simulate synchronous execution */
- sync_execution = 1;
+ async_disable_stdin ();
}
count = count_string ? parse_and_eval_address (count_string) : 1;
/* If we must run in the background, but the target can't do it,
error out. */
- if (async_p && async_exec && !target_has_async)
+ if (event_loop_p && async_exec && !target_can_async_p ())
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)
+ if (event_loop_p && !async_exec && target_can_async_p ())
{
/* Simulate synchronous execution */
- sync_execution = 1;
+ async_disable_stdin ();
}
if (!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)
+ if (event_loop_p && async_exec && !target_can_async_p ())
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)
+ if (event_loop_p && !async_exec && target_can_async_p ())
{
/* Simulate synchronous execution */
- sync_execution = 1;
+ async_disable_stdin ();
}
if (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)
+ if (event_loop_p && async_exec && !target_can_async_p ())
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)
+ if (event_loop_p && !async_exec && target_can_async_p ())
{
/* Simulate synchronous execution */
- sync_execution = 1;
+ async_disable_stdin ();
}
if (arg)
breakpoint = set_momentary_breakpoint (sal, frame, bp_finish);
- if (!async_p || !target_has_async)
+ if (!event_loop_p || !target_can_async_p ())
old_chain = make_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint);
else
make_exec_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint);
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)
+ if (event_loop_p && target_can_async_p ())
{
arg1 =
(struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
/* 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)
+ if (!event_loop_p || !target_can_async_p ())
{
/* Did we stop at our breakpoint? */
target_post_attach (inferior_pid);
normal_stop ();
+
+ if (attach_hook)
+ attach_hook ();
}
/*
#if defined(SOLIB_RESTART)
SOLIB_RESTART ();
#endif
+ if (detach_hook)
+ detach_hook ();
}
/* Stop the execution of the target while running in async mode, in
char *args;
int from_tty;
{
- if (async_p && target_has_async)
+ if (event_loop_p && target_can_async_p ())
{
dont_repeat (); /* Not for the faint of heart */
target_stop ();
#include <signal.h>
#include "event-loop.h"
#include "event-top.h"
-#include "remote.h" /* For cleanup_sigint_signal_handler. */
/* Prototypes for local functions */
and in any case decode why it stopped, and act accordingly. */
/* 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)
+ if (!event_loop_p || !target_can_async_p ())
{
wait_for_inferior ();
normal_stop ();
stop_soon_quietly = 1;
trap_expected = 0;
- /* 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;
- }
+ /* Always go on waiting for the target, regardless of the mode. */
+ /* FIXME: cagney/1999-09-23: At present it isn't possible to
+ indicate th wait_for_inferior that a target should timeout if
+ nothing is returned (instead of just blocking). Because of this,
+ targets expecting an immediate response need to, internally, set
+ things up so that the target_wait() is forced to eventually
+ timeout. */
+ /* FIXME: cagney/1999-09-24: It isn't possible for target_open() to
+ differentiate to its caller what the state of the target is after
+ the initial open has been performed. Here we're assuming that
+ the target has stopped. It should be possible to eventually have
+ target_open() return to the caller an indication that the target
+ is currently running and GDB state should be set to the same as
+ for an async run. */
+ wait_for_inferior ();
+ normal_stop ();
}
/* Initialize static vars when a new inferior begins. */
stop_pc = read_pc_pid (ecs->pid);
ecs->saved_inferior_pid = inferior_pid;
inferior_pid = ecs->pid;
- stop_bpstat = bpstat_stop_status
- (&stop_pc,
- (DECR_PC_AFTER_BREAK ?
- (prev_pc != stop_pc - DECR_PC_AFTER_BREAK
- && currently_stepping (ecs))
- : 0)
- );
+ stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_pid = ecs->saved_inferior_pid;
goto process_event_stop_test;
}
stop_pc = read_pc ();
- stop_bpstat = bpstat_stop_status
- (&stop_pc,
- (DECR_PC_AFTER_BREAK ?
- (prev_pc != stop_pc - DECR_PC_AFTER_BREAK
- && currently_stepping (ecs))
- : 0)
- );
+ stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
goto process_event_stop_test;
stop_pc = read_pc_pid (ecs->pid);
ecs->saved_inferior_pid = inferior_pid;
inferior_pid = ecs->pid;
- stop_bpstat = bpstat_stop_status
- (&stop_pc,
- (DECR_PC_AFTER_BREAK ?
- (prev_pc != stop_pc - DECR_PC_AFTER_BREAK
- && currently_stepping (ecs))
- : 0)
- );
+ stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_pid = ecs->saved_inferior_pid;
goto process_event_stop_test;
/* See if there is a breakpoint at the current PC. */
stop_bpstat = bpstat_stop_status
(&stop_pc,
- (DECR_PC_AFTER_BREAK ?
- /* Notice the case of stepping through a jump
- that lands just after a breakpoint.
- Don't confuse that with hitting the breakpoint.
- What we check for is that 1) stepping is going on
- and 2) the pc before the last insn does not match
- the address of the breakpoint before the current pc
- and 3) we didn't hit a breakpoint in a signal handler
- without an intervening stop in sigtramp, which is
- detected by a new stack pointer value below
- any usual function calling stack adjustments. */
+ /* Pass TRUE if our reason for stopping is something other
+ than hitting a breakpoint. We do this by checking that
+ 1) stepping is going on and 2) we didn't hit a breakpoint
+ in a signal handler without an intervening stop in
+ sigtramp, which is detected by a new stack pointer value
+ below any usual function calling stack adjustments. */
(currently_stepping (ecs)
- && prev_pc != stop_pc - DECR_PC_AFTER_BREAK
&& !(step_range_end
- && INNER_THAN (read_sp (), (step_sp - 16)))) :
- 0)
+ && INNER_THAN (read_sp (), (step_sp - 16))))
);
/* Following in case break condition called a
function. */
complete_execution (void)
{
target_executing = 0;
+
if (sync_execution)
{
- add_file_handler (input_fd, stdin_event_handler, 0);
- pop_prompt ();
- sync_execution = 0;
- cleanup_sigint_signal_handler ();
+ do_exec_error_cleanups (ALL_CLEANUPS);
display_gdb_prompt (0);
}
else
if (count)
{
- int update_coreops;
-
- /* We must update the to_sections field in the core_ops structure
- here, otherwise we dereference a potential dangling pointer
- for each call to target_read/write_memory within this routine. */
- update_coreops = core_ops.to_sections == target->to_sections;
-
- /* Reallocate the target's section table including the new size. */
- if (target->to_sections)
- {
- old = target->to_sections_end - target->to_sections;
- target->to_sections = (struct section_table *)
- xrealloc ((char *) target->to_sections,
- (sizeof (struct section_table)) * (count + old));
- }
- else
- {
- old = 0;
- target->to_sections = (struct section_table *)
- xmalloc ((sizeof (struct section_table)) * count);
- }
- target->to_sections_end = target->to_sections + (count + old);
-
- /* Update the to_sections field in the core_ops structure
- if needed. */
- if (update_coreops)
- {
- core_ops.to_sections = target->to_sections;
- core_ops.to_sections_end = target->to_sections_end;
- }
-
+ old = target_resize_to_sections (target, count);
+
/* Add these section table entries to the target's table. */
while ((so = find_solib (so)) != NULL)
{
break;
}
case 'G': /* set the value of the CPU registers - return OK */
- hex2mem(&ptr, (unsigned char*) registers, NUMREGBYTES, 0);
+ hex2mem(ptr, (unsigned char*) registers, NUMREGBYTES, 0);
strcpy(remcomOutBuffer,"OK");
break;
case 's': /* sAA..AA Step one instruction from AA..AA(optional) */
invoked on the command line with the -nw --async options. In this
version, the usual command_loop is substituted by and event loop which
processes UI events asynchronously. */
-int async_p = 1;
+int event_loop_p = 1;
/* Whether this is the command line version or not */
int tui_version = 0;
with no equivalent). */
static struct option long_options[] =
{
- {"async", no_argument, &async_p, 1},
- {"noasync", no_argument, &async_p, 0},
+ {"async", no_argument, &event_loop_p, 1},
+ {"noasync", no_argument, &event_loop_p, 0},
#if defined(TUI)
{"tui", no_argument, &tui_version, 1},
#endif
if (count)
{
- int update_coreops;
-
- /* We must update the to_sections field in the core_ops structure
- here, otherwise we dereference a potential dangling pointer
- for each call to target_read/write_memory within this routine. */
- update_coreops = core_ops.to_sections == target->to_sections;
-
- /* Reallocate the target's section table including the new size. */
- if (target->to_sections)
- {
- old = target->to_sections_end - target->to_sections;
- target->to_sections = (struct section_table *)
- xrealloc ((char *) target->to_sections,
- (sizeof (struct section_table)) * (count + old));
- }
- else
- {
- old = 0;
- target->to_sections = (struct section_table *)
- xmalloc ((sizeof (struct section_table)) * count);
- }
- target->to_sections_end = target->to_sections + (count + old);
-
- /* Update the to_sections field in the core_ops structure
- if needed. */
- if (update_coreops)
- {
- core_ops.to_sections = target->to_sections;
- core_ops.to_sections_end = target->to_sections_end;
- }
-
/* Add these section table entries to the target's table. */
+
+ old = target_resize_to_sections (target, count);
+
while ((so = find_solib (so)) != NULL)
{
if (so->so_name[0])
status = target_read_memory (text_addr, buf, 4);
if (status != 0)
{
- int old, new;
- int update_coreops;
- int update_execops;
-
- /* We must update the to_sections field in the core_ops structure
- here, otherwise we dereference a potential dangling pointer
- for each call to target_read/write_memory within this routine. */
- update_coreops = core_ops.to_sections == target->to_sections;
-
- /* Ditto exec_ops (this was a bug). */
- update_execops = exec_ops.to_sections == target->to_sections;
-
+ int new, old;
+
new = so->sections_end - so->sections;
- /* Add sections from the shared library to the core target. */
- if (target->to_sections)
- {
- old = target->to_sections_end - target->to_sections;
- target->to_sections = (struct section_table *)
- xrealloc ((char *) target->to_sections,
- ((sizeof (struct section_table)) * (old + new)));
- }
- else
- {
- old = 0;
- target->to_sections = (struct section_table *)
- xmalloc ((sizeof (struct section_table)) * new);
- }
- target->to_sections_end = (target->to_sections + old + new);
-
- /* Update the to_sections field in the core_ops structure
- if needed, ditto exec_ops. */
- if (update_coreops)
- {
- core_ops.to_sections = target->to_sections;
- core_ops.to_sections_end = target->to_sections_end;
- }
-
- if (update_execops)
- {
- exec_ops.to_sections = target->to_sections;
- exec_ops.to_sections_end = target->to_sections_end;
- }
+ old = target_resize_to_sections (target, new);
+
/* Copy over the old data before it gets clobbered. */
memcpy ((char *) (target->to_sections + old),
so->sections,
prfillset (&sctl.sigset);
notice_signals (pi, &sctl);
- prfillset (&fctl.fltset);
- prdelset (&fctl.fltset, FLTPAGE);
-
#else /* ! UNIXWARE */
ioctl (pi->ctl_fd, PIOCGTRACE, &pi->saved_trace.sigset);
ioctl (pi->ctl_fd, PIOCGHOLD, &pi->saved_sighold.sigset);
memset ((char *) &pi->prrun, 0, sizeof (pi->prrun));
prfillset (&pi->prrun.pr_trace);
procfs_notice_signals (pid);
- prfillset (&pi->prrun.pr_fault);
- prdelset (&pi->prrun.pr_fault, FLTPAGE);
-#ifdef PROCFS_DONT_TRACE_FAULTS
- premptyset (&pi->prrun.pr_fault);
-#endif
#endif /* UNIXWARE */
if (!procfs_read_status (pi))
#ifdef PROCFS_USE_READ_WRITE
fctl.cmd = PCSFAULT;
+ prfillset (&fctl.fltset);
+ prdelset (&fctl.fltset, FLTPAGE);
+
if (write (pi->ctl_fd, (char *) &fctl, sizeof (struct flt_ctl)) < 0)
proc_init_failed (pi, "PCSFAULT failed", 1);
#else
+ prfillset (&pi->prrun.pr_fault);
+ prdelset (&pi->prrun.pr_fault, FLTPAGE);
+#ifdef PROCFS_DONT_TRACE_FAULTS
+ premptyset (&pi->prrun.pr_fault);
+#endif
if (ioctl (pi->ctl_fd, PIOCSFAULT, &pi->prrun.pr_fault) < 0)
proc_init_failed (pi, "PIOCSFAULT failed", 1);
#endif
#ifdef PROCFS_USE_READ_WRITE
fctl.cmd = PCSFAULT;
+ prfillset (&fctl.fltset);
+ prdelset (&fctl.fltset, FLTPAGE);
+
if (write (pi->ctl_fd, (char *) &fctl, sizeof (struct flt_ctl)) < 0)
print_sys_errmsg ("PCSFAULT failed", errno);
#else /* PROCFS_USE_READ_WRITE */
+ prfillset (&pi->prrun.pr_fault);
+ prdelset (&pi->prrun.pr_fault, FLTPAGE);
+#ifdef PROCFS_DONT_TRACE_FAULTS
+ premptyset (&pi->prrun.pr_fault);
+#endif
if (ioctl (pi->ctl_fd, PIOCSFAULT, &pi->prrun.pr_fault))
{
print_sys_errmsg ("PIOCSFAULT failed", errno);
#include "serial.h"
/* Prototypes for local functions */
-static void initialize_sigint_signal_handler PARAMS ((void));
+static void cleanup_sigint_signal_handler (void *dummy);
+static void initialize_sigint_signal_handler (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));
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));
was static int remote_timeout = 2; */
extern int remote_timeout;
+/* FIXME: cagney/1999-09-23: Even though getpkt was called with
+ ``forever'' still use the normal timeout mechanism. This is
+ currently used by the ASYNC code to guarentee that target reads
+ during the initial connect always time-out. Once getpkt has been
+ modified to return a timeout indication and, in turn
+ remote_wait()/wait_for_inferior() have gained a timeout parameter
+ this can go away. */
+static int wait_forever_enabled_p = 1;
+
+
/* This variable chooses whether to send a ^C or a break when the user
requests program interruption. Although ^C is usually what remote
systems expect, and that is the default here, sometimes a break is
static int remote_register_buf_size = 0;
+/* Tempoary to track who currently owns the terminal. See
+ target_async_terminal_* for more details. */
+
+static int remote_async_terminal_ours_p;
+
/* Generic configuration support for packets the stub optionally
supports. Allows the user to specify the use of the packet as well
as allowing GDB to auto-detect support in the remote stub. */
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).");
+ /* See FIXME above */
+ wait_forever_enabled_p = 1;
+
target_preopen (from_tty);
unpush_target (target);
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 && SERIAL_CAN_ASYNC_P (remote_desc))
- SERIAL_ASYNC (remote_desc, inferior_event_handler, 0);
- if (remote_debug && SERIAL_IS_ASYNC_P (remote_desc))
- fputs_unfiltered ("Async mode.\n", gdb_stdlog);
-
push_target (target); /* Switch to using remote target now */
init_packet_config (&remote_protocol_P);
binary downloading. */
init_packet_config (&remote_protocol_binary_download);
- /* 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 && SERIAL_IS_ASYNC_P (remote_desc))
- 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;
+
+ /* With this target we start out by owning the terminal. */
+ remote_async_terminal_ours_p = 1;
+
+ /* FIXME: cagney/1999-09-23: During the initial connection it is
+ assumed that the target is already ready and able to respond to
+ requests. Unfortunatly remote_start_remote() eventually calls
+ wait_for_inferior() with no timeout. wait_forever_enabled_p gets
+ around this. Eventually a mechanism that allows
+ wait_for_inferior() to expect/get timeouts will be
+ implemented. */
+ wait_forever_enabled_p = 0;
+
/* 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). */
"Couldn't establish connection to remote target\n",
RETURN_MASK_ALL))
{
- /* Unregister the file descriptor from the event loop. */
- if (SERIAL_IS_ASYNC_P (remote_desc))
- SERIAL_ASYNC (remote_desc, NULL, 0);
pop_target ();
+ wait_forever_enabled_p = 1;
return;
}
- if (!SERIAL_IS_ASYNC_P (remote_desc))
+ wait_forever_enabled_p = 1;
+
+ if (extended_p)
{
- if (extended_p)
- {
- /* tell the remote that we're using the extended protocol. */
- char *buf = alloca (PBUFSIZ);
- putpkt ("!");
- getpkt (buf, 0);
- }
+ /* 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);
+ /* 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. */
+ /* FIXME: cagney/1999-09-26: We shouldn't just put the target into
+ async mode. Instead we should leave the target synchronous and
+ then leave it to the client to flip modes. */
+ if (event_loop_p && target_can_async_p ())
+ target_async (inferior_event_handler, 0);
+ if (remote_debug && SERIAL_IS_ASYNC_P (remote_desc))
+ fputs_unfiltered ("Serial put into async mode.\n", gdb_stdlog);
}
/* This takes a program previously attached to and detaches it. After
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 (SERIAL_IS_ASYNC_P (remote_desc) && !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 ();
- }
- }
+ /* Tell the world that the target is now executing. */
+ /* FIXME: cagney/1999-09-23: Is it the targets responsibility to set
+ this? Instead, should the client of target just assume (for
+ async targets) that the target is going to start executing? Is
+ this information already found in the continuation block? */
+ if (SERIAL_IS_ASYNC_P (remote_desc))
+ target_executing = 1;
if (siggnal != TARGET_SIGNAL_0)
{
{
signal (sig, handle_sigint);
sigint_remote_twice_token =
- create_async_signal_handler (async_remote_interrupt, NULL);
+ create_async_signal_handler (async_remote_interrupt_twice, NULL);
mark_async_signal_handler_wrapper (sigint_remote_twice_token);
}
-/* Perform the real interruption of hte target execution, in response
+/* Perform the real interruption of the target execution, in response
to a ^C. */
static void
async_remote_interrupt (arg)
async_remote_interrupt_twice (arg)
gdb_client_data arg;
{
- interrupt_query ();
- signal (SIGINT, handle_remote_sigint);
+ /* Do something only if the target was not killed by the previous
+ cntl-C. */
+ if (target_executing)
+ {
+ interrupt_query ();
+ signal (SIGINT, handle_remote_sigint);
+ }
}
/* Reinstall the usual SIGINT handlers, after the target has
stopped. */
-void
-cleanup_sigint_signal_handler ()
+static void
+cleanup_sigint_signal_handler (void *dummy)
{
signal (SIGINT, handle_sigint);
if (sigint_remote_twice_token)
target_terminal_inferior ();
}
+/* Enable/disable target terminal ownership. Most targets can use
+ terminal groups to control terminal ownership. Remote targets are
+ different in that explicit transfer of ownership to/from GDB/target
+ is required. */
+
+static void
+remote_async_terminal_inferior (void)
+{
+ /* FIXME: cagney/1999-09-27: Shouldn't need to test for
+ sync_execution here. This function should only be called when
+ GDB is resuming the inferior in the forground. A background
+ resume (``run&'') should leave GDB in control of the terminal and
+ consequently should not call this code. */
+ if (!sync_execution)
+ return;
+ /* FIXME: cagney/1999-09-27: Closely related to the above. Make
+ calls target_terminal_*() idenpotent. The event-loop GDB talking
+ to an asynchronous target with a synchronous command calls this
+ function from both event-top.c and infrun.c/infcmd.c. Once GDB
+ stops trying to transfer the terminal to the target when it
+ shouldn't this guard can go away. */
+ if (!remote_async_terminal_ours_p)
+ return;
+ delete_file_handler (input_fd);
+ remote_async_terminal_ours_p = 0;
+ initialize_sigint_signal_handler ();
+ /* NOTE: At this point we could also register our selves as the
+ recipient of all input. Any characters typed could then be
+ passed on down to the target. */
+}
+
+static void
+remote_async_terminal_ours (void)
+{
+ /* See FIXME in remote_async_terminal_inferior. */
+ if (!sync_execution)
+ return;
+ /* See FIXME in remote_async_terminal_inferior. */
+ if (remote_async_terminal_ours_p)
+ return;
+ cleanup_sigint_signal_handler (NULL);
+ add_file_handler (input_fd, stdin_event_handler, 0);
+ remote_async_terminal_ours_p = 1;
+}
+
/* If nonzero, ignore the next kill. */
int kill_kludge;
if (!SERIAL_IS_ASYNC_P (remote_desc))
ofunc = signal (SIGINT, remote_interrupt);
- getpkt ((char *) buf, 1);
+ /* FIXME: cagney/1999-09-27: If we're in async mode we should
+ _never_ wait for ever -> test on target_is_async_p().
+ However, before we do that we need to ensure that the caller
+ knows how to take the target into/out of async mode. */
+ getpkt ((char *) buf, wait_forever_enabled_p);
if (!SERIAL_IS_ASYNC_P (remote_desc))
signal (SIGINT, ofunc);
/* If running asynchronously, register the target file descriptor
with the event loop. */
- if (async_p && SERIAL_CAN_ASYNC_P (remote_desc))
+ if (event_loop_p && SERIAL_CAN_ASYNC_P (remote_desc))
SERIAL_ASYNC (remote_desc, inferior_event_handler, 0);
/* Now restart the remote server. */
"To open a remote debug connection, you need to specify what \n\
device is attached to the remote system (e.g. host:port).");
+ /* See FIXME above */
+ wait_forever_enabled_p = 1;
+
target_preopen (from_tty);
unpush_target (&remote_cisco_ops);
remote_cisco_ops.to_magic = OPS_MAGIC;
}
+static int
+remote_can_async_p (void)
+{
+ /* We're async whenever the serial device is. */
+ return SERIAL_CAN_ASYNC_P (remote_desc);
+}
+
+static int
+remote_is_async_p (void)
+{
+ /* We're async whenever the serial device is. */
+ return SERIAL_IS_ASYNC_P (remote_desc);
+}
+
+static void
+remote_async (void (*callback) (int error, void *context, int fd), void *context)
+{
+ SERIAL_ASYNC (remote_desc, callback, context);
+}
+
/* Target async and target extended-async.
This are temporary targets, until it is all tested. Eventually
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_terminal_inferior = remote_async_terminal_inferior;
+ remote_async_ops.to_terminal_ours = remote_async_terminal_ours;
remote_async_ops.to_kill = remote_async_kill;
remote_async_ops.to_load = generic_load;
remote_async_ops.to_mourn_inferior = remote_async_mourn;
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_can_async_p = remote_can_async_p;
+ remote_async_ops.to_is_async_p = remote_is_async_p;
+ remote_async_ops.to_async = remote_async;
remote_async_ops.to_magic = OPS_MAGIC;
}
extern void remote_console_output PARAMS ((char *));
-/* FIXME: cagney/1999-09-20: This function is going to be replaced
- with a more generic (non remote specific) mechanism. */
-
-extern void cleanup_sigint_signal_handler (void);
-
/* FIXME: cagney/1999-09-20: The remote cisco stuff in remote.c needs
to be broken out into a separate file (remote-cisco.[hc]?). Before
that can happen, a remote protocol stack framework needs to be
add our sections to the section table for the core target. */
if (vp != vmap)
{
- int count;
struct section_table *stp;
- int update_coreops;
-
- /* We must update the to_sections field in the core_ops structure
- now to avoid dangling pointer dereferences. */
- update_coreops = core_ops.to_sections == target->to_sections;
-
- count = target->to_sections_end - target->to_sections;
- count += 2;
- target->to_sections = (struct section_table *)
- xrealloc (target->to_sections,
- sizeof (struct section_table) * count);
- target->to_sections_end = target->to_sections + count;
-
- /* Update the to_sections field in the core_ops structure
- if needed. */
- if (update_coreops)
- {
- core_ops.to_sections = target->to_sections;
- core_ops.to_sections_end = target->to_sections_end;
- }
+
+ target_resize_to_sections (target, 2);
stp = target->to_sections_end - 2;
stp->bfd = vp->bfd;
#endif SVR4_SHARED_LIBS
- if ((re_err = re_comp (arg_string ? arg_string : ".")) != NULL)
+ if ((re_err = re_comp (arg_string? arg_string : ".")) != NULL)
{
error ("Invalid regexp: %s", re_err);
}
if (count)
{
- int update_coreops;
-
- /* We must update the to_sections field in the core_ops structure
- here, otherwise we dereference a potential dangling pointer
- for each call to target_read/write_memory within this routine. */
- update_coreops = core_ops.to_sections == target->to_sections;
-
- /* Reallocate the target's section table including the new size. */
- if (target->to_sections)
- {
- old = target->to_sections_end - target->to_sections;
- target->to_sections = (struct section_table *)
- xrealloc ((char *) target->to_sections,
- (sizeof (struct section_table)) * (count + old));
- }
- else
- {
- old = 0;
- target->to_sections = (struct section_table *)
- xmalloc ((sizeof (struct section_table)) * count);
- }
- target->to_sections_end = target->to_sections + (count + old);
-
- /* Update the to_sections field in the core_ops structure
- if needed. */
- if (update_coreops)
- {
- core_ops.to_sections = target->to_sections;
- core_ops.to_sections_end = target->to_sections_end;
- }
-
+
/* Add these section table entries to the target's table. */
+ old = target_resize_to_sections (target, count);
while ((so = find_solib (so)) != NULL)
{
if (so->so_name[0])
if (status != 0)
{
int old, new;
- int update_coreops;
- int update_execops;
-
- /* We must update the to_sections field in the core_ops structure
- here, otherwise we dereference a potential dangling pointer
- for each call to target_read/write_memory within this routine. */
- update_coreops = core_ops.to_sections == target->to_sections;
-
- /* Ditto exec_ops (this was a bug).
- */
- update_execops = exec_ops.to_sections == target->to_sections;
new = so->sections_end - so->sections;
- /* Add sections from the shared library to the core target. */
- if (target->to_sections)
- {
- old = target->to_sections_end - target->to_sections;
- target->to_sections = (struct section_table *)
- xrealloc ((char *) target->to_sections,
- ((sizeof (struct section_table)) * (old + new)));
- }
- else
- {
- old = 0;
- target->to_sections = (struct section_table *)
- xmalloc ((sizeof (struct section_table)) * new);
- }
- target->to_sections_end = (target->to_sections + old + new);
-
- /* Update the to_sections field in the core_ops structure
- if needed, ditto exec_ops. */
- if (update_coreops)
- {
- core_ops.to_sections = target->to_sections;
- core_ops.to_sections_end = target->to_sections_end;
- }
-
- if (update_execops)
- {
- exec_ops.to_sections = target->to_sections;
- exec_ops.to_sections_end = target->to_sections_end;
- }
-
+
+ old = target_resize_to_sections (target, new);
+
/* Copy over the old data before it gets clobbered. */
memcpy ((char *) (target->to_sections + old),
so->sections,
de_fault (to_pid_to_exec_file, (char *(*)PARAMS ((int))) return_zero);
de_fault (to_core_file_to_sym_file, (char *(*)PARAMS ((char *))) return_zero);
+ de_fault (to_can_async_p, (int (*) (void)) return_zero);
+ de_fault (to_is_async_p, (int (*) (void)) return_zero);
+ de_fault (to_async, (void (*) (void (*) (int, void*, int), void*)) tcomplain);
#undef de_fault
}
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_can_async_p, t);
+ INHERIT (to_is_async_p, t);
+ INHERIT (to_async, t);
INHERIT (to_magic, t);
#undef INHERIT
return 1;
}
+/*
+ * Resize the to_sections pointer. Also make sure that anyone that
+ * was holding on to an old value of it gets updated.
+ * Returns the old size.
+ */
+
+int
+target_resize_to_sections (struct target_ops *target, int num_added)
+{
+ struct target_ops **t;
+ struct section_table *old_value;
+ int old_count;
+
+ old_value = target->to_sections;
+
+ if (target->to_sections)
+ {
+ old_count = target->to_sections_end - target->to_sections;
+ target->to_sections = (struct section_table *)
+ xrealloc ((char *) target->to_sections,
+ (sizeof (struct section_table)) * (num_added + old_count));
+ }
+ else
+ {
+ old_count = 0;
+ target->to_sections = (struct section_table *)
+ xmalloc ((sizeof (struct section_table)) * num_added);
+ }
+ target->to_sections_end = target->to_sections + (num_added + old_count);
+
+ /* Check to see if anyone else was pointing to this structure.
+ If old_value was null, then no one was. */
+
+ if (old_value)
+ {
+ for (t = target_structs; t < target_structs + target_struct_size;
+ ++t)
+ {
+ if ((*t)->to_sections == old_value)
+ {
+ (*t)->to_sections = target->to_sections;
+ (*t)->to_sections_end = target->to_sections_end;
+ }
+ }
+ }
+
+ return old_count;
+
+}
+
/* Find a single runnable target in the stack and return it. If for
some reason there is more than one, return NULL. */
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
*to_sections_end;
+ /* ASYNC target controls */
+ int (*to_can_async_p) (void);
+ int (*to_is_async_p) (void);
+ void (*to_async) (void (*cb) (int error, void *context, int fd), void *context);
int to_magic;
/* Need sub-structure for target machine related rather than comm related? */
};
#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)
+/* Can the target support asynchronous execution? */
+#define target_can_async_p() (current_target.to_can_async_p ())
+
+/* Is the target in asynchronous execution mode? */
+#define target_is_async_p() (current_target.to_is_async_p())
+
+/* Put the target in async mode with the specified callback function. */
+#define target_async(CALLBACK,CONTEXT) (current_target.to_async((CALLBACK), (CONTEXT)))
extern void target_link PARAMS ((char *, CORE_ADDR *));
extern struct target_ops *
find_core_target PARAMS ((void));
+
+int
+target_resize_to_sections PARAMS ((struct target_ops *target, int num_added));
\f
/* Stuff that should be shared among the various remote targets. */
void (*delete_breakpoint_hook) PARAMS ((struct breakpoint * bpt));
void (*modify_breakpoint_hook) PARAMS ((struct breakpoint * bpt));
+/* Called as appropriate to notify the interface that we have attached
+ to or detached from an already running process. */
+
+void (*attach_hook) PARAMS ((void));
+void (*detach_hook) PARAMS ((void));
+
/* Called during long calculations to allow GUI to repair window damage, and to
check for stop buttons, etc... */
loop, but can be caught via catch_errors. */
NORETURN void
- return_to_top_level (reason)
+return_to_top_level (reason)
enum return_reason reason;
{
quit_flag = 0;
disable_current_display ();
do_cleanups (ALL_CLEANUPS);
- if (async_p && target_has_async)
+ if (event_loop_p && target_can_async_p ())
do_exec_cleanups (ALL_CLEANUPS);
+ if (event_loop_p && sync_execution)
+ do_exec_error_cleanups (ALL_CLEANUPS);
if (annotation_level > 1)
switch (reason)
not the async version is run. NOTE: in the future we plan to make
the event loop be the default engine of gdb, and this difference
will disappear. */
- if (async_p)
+ if (event_loop_p)
async_init_signals ();
else
init_signals ();
/* If the target is running, we allow only a limited set of
commands. */
- if (async_p && target_has_async && target_executing)
+ if (event_loop_p && target_can_async_p () && target_executing)
if (!strcmp (c->name, "help")
&& !strcmp (c->name, "pwd")
&& !strcmp (c->name, "show")
#ifdef STOP_SIGNAL
if (job_control)
{
- if (async_p)
+ if (event_loop_p)
signal (STOP_SIGNAL, handle_stop_sig);
else
signal (STOP_SIGNAL, stop_sig);
{
char *local_prompt;
- if (async_p)
+ if (event_loop_p)
local_prompt = PROMPT (0);
else
local_prompt = gdb_prompt_string;
else
{
/* Prompt could not be formatted. */
- if (async_p)
+ if (event_loop_p)
return PROMPT (0);
else
return gdb_prompt_string;
if (prompt != NULL)
free (prompt);
*/
- if (async_p)
+ if (event_loop_p)
PROMPT (0) = savestring (s, strlen (s));
else
gdb_prompt_string = savestring (s, strlen (s));
/* If we are running the asynchronous version,
we initialize the prompts differently. */
- if (!async_p)
+ if (!event_loop_p)
{
gdb_prompt_string = savestring (DEFAULT_PROMPT, strlen (DEFAULT_PROMPT));
}
async version is run. NOTE: this difference is going to
disappear as we make the event loop be the default engine of
gdb. */
- if (!async_p)
+ if (!event_loop_p)
{
add_show_from_set
(add_set_cmd ("prompt", class_support, var_string,
/* The set editing command is different depending whether or not the
async version is run. NOTE: this difference is going to disappear
as we make the event loop be the default engine of gdb. */
- if (!async_p)
+ if (!event_loop_p)
{
add_show_from_set
(add_set_cmd ("editing", class_support, var_boolean, (char *) &command_editing_p,
the async version is run. NOTE: this difference is going to
disappear as we make the event loop be the default engine of
gdb. */
- if (!async_p)
+ if (!event_loop_p)
{
c = add_set_cmd ("annotate", class_obscure, var_zinteger,
(char *) &annotation_level, "Set annotation_level.\n\
add_show_from_set (c, &showlist);
c->function.sfunc = set_async_annotation_level;
}
- if (async_p)
+ if (event_loop_p)
{
add_show_from_set
(add_set_cmd ("exec-done-display", class_support, var_boolean, (char *) &exec_done_display_p,
#ifdef STOP_SIGNAL
if (job_control)
{
- if (async_p)
+ if (event_loop_p)
signal (STOP_SIGNAL, handle_stop_sig);
else
signal (STOP_SIGNAL, stop_sig);
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 */
+/* cleaned up on each error from within an execution command */
+static struct cleanup *exec_error_cleanup_chain;
/* Pointer to what is left to do for an execution command after the
target stops. Used only in asynchronous mode, by targets that
return make_my_cleanup (&exec_cleanup_chain, function, arg);
}
+struct cleanup *
+make_exec_error_cleanup (function, arg)
+ void (*function) PARAMS ((PTR));
+ PTR arg;
+{
+ return make_my_cleanup (&exec_error_cleanup_chain, function, arg);
+}
+
static void
do_freeargv (arg)
void *arg;
do_my_cleanups (&exec_cleanup_chain, old_chain);
}
+void
+do_exec_error_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ do_my_cleanups (&exec_error_cleanup_chain, old_chain);
+}
+
void
do_my_cleanups (pmy_chain, old_chain)
register struct cleanup **pmy_chain;
discard_my_cleanups (&final_cleanup_chain, old_chain);
}
+void
+discard_exec_error_cleanups (old_chain)
+ register struct cleanup *old_chain;
+{
+ discard_my_cleanups (&exec_error_cleanup_chain, old_chain);
+}
+
void
discard_my_cleanups (pmy_chain, old_chain)
register struct cleanup **pmy_chain;
++p;
if (p[0] == 'q')
{
- if (!async_p)
+ if (!event_loop_p)
request_quit (SIGINT);
else
async_request_quit (0);
+1999-07-16 Ben Elliston <bje@cygnus.com>
+
+ * configure.in: Configure the testsuite directory for arm.
+ * configure: Regenerate.
+
1999-04-08 Nick Clifton <nickc@cygnus.com>
* configure.in: Add support for MCore target.
+1999-09-25 Doug Evans <devans@casey.cygnus.com>
+
+ * cgen-ops.h (SUBWORD*): Delete cpu arg.
+ (JOIN*): Delete cpu arg.
+
+Tue Sep 21 17:14:16 1999 Dave Brolley <brolley@cygnus.com>
+
+ * genmloop.sh (@cpu@_scache_lookup): No longer takes last_insn_p
+ parameter.
+ (SET_LAST_INSN_P): Set last_insn_p flag in the scache element.
+
Mon Sep 20 21:44:06 1999 Geoffrey Keating <geoffk@cygnus.com>
* sim-fpu.c (i2fpu): Keep the guard bits sticky when converting
-
/* Semantics ops support for CGEN-based simulators.
Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
Contributed by Cygnus Solutions.
#define TRUNCDISI(x) ((SI) (DI) (x))
#endif
\f
-/* Composing/decomposing the various types. */
-
-/* ??? endianness issues undecided */
-/* ??? CURRENT_TARGET_BYTE_ORDER usage wip */
+/* Composing/decomposing the various types.
+ Word ordering is endian-independent. Words are specified most to least
+ significant and word number 0 is the most significant word.
+ ??? May also wish an endian-dependent version. Later. */
#ifdef SEMOPS_DEFINE_INLINE
SEMOPS_INLINE SF
-SUBWORDSISF (SIM_CPU *cpu, SI in)
+SUBWORDSISF (SI in)
{
union { SI in; SF out; } x;
x.in = in;
}
SEMOPS_INLINE SI
-SUBWORDSFSI (SIM_CPU *cpu, SF in)
+SUBWORDSFSI (SF in)
{
union { SF in; SI out; } x;
x.in = in;
}
SEMOPS_INLINE SI
-SUBWORDDISI (SIM_CPU *cpu, DI in, int word)
+SUBWORDDISI (DI in, int word)
{
- if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
- {
- if (word == 0)
- return (UDI) in >> 32;
- else
- return in;
- }
+ if (word == 0)
+ return (UDI) in >> 32;
else
- {
- if (word == 1)
- return (UDI) in >> 32;
- else
- return in;
- }
+ return in;
}
SEMOPS_INLINE SI
-SUBWORDDFSI (SIM_CPU *cpu, DF in, int word)
+SUBWORDDFSI (DF in, int word)
{
- union { DF in; SI out[2]; } x;
- x.in = in;
- if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
- return x.out[word];
+ /* Note: typedef UDI DF; */
+ if (word == 0)
+ return (UDI) in >> 32;
else
- return x.out[!word];
+ return in;
}
SEMOPS_INLINE SI
-SUBWORDXFSI (SIM_CPU *cpu, XF in, int word)
+SUBWORDXFSI (XF in, int word)
{
+ /* Note: typedef struct { SI parts[3]; } XF; */
union { XF in; SI out[3]; } x;
x.in = in;
- if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
- return x.out[word];
- else
- return x.out[2 - word];
+ return x.out[word];
}
SEMOPS_INLINE SI
-SUBWORDTFSI (SIM_CPU *cpu, TF in, int word)
+SUBWORDTFSI (TF in, int word)
{
+ /* Note: typedef struct { SI parts[4]; } TF; */
union { TF in; SI out[4]; } x;
x.in = in;
- if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
- return x.out[word];
- else
- return x.out[3 - word];
+ return x.out[word];
}
SEMOPS_INLINE DI
-JOINSIDI (SIM_CPU *cpu, SI x0, SI x1)
+JOINSIDI (SI x0, SI x1)
{
if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
return MAKEDI (x0, x1);
}
SEMOPS_INLINE DF
-JOINSIDF (SIM_CPU *cpu, SI x0, SI x1)
+JOINSIDF (SI x0, SI x1)
{
union { SI in[2]; DF out; } x;
if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
}
SEMOPS_INLINE XF
-JOINSIXF (SIM_CPU *cpu, SI x0, SI x1, SI x2)
+JOINSIXF (SI x0, SI x1, SI x2)
{
union { SI in[3]; XF out; } x;
if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
}
SEMOPS_INLINE TF
-JOINSITF (SIM_CPU *cpu, SI x0, SI x1, SI x2, SI x3)
+JOINSITF (SI x0, SI x1, SI x2, SI x3)
{
union { SI in[4]; TF out; } x;
if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
#else
-SF SUBWORDSISF (SIM_CPU *, SI);
-SI SUBWORDSFSI (SIM_CPU *, SF);
-SI SUBWORDDISI (SIM_CPU *, DI, int);
-SI SUBWORDDFSI (SIM_CPU *, DF, int);
-SI SUBWORDXFSI (SIM_CPU *, XF, int);
-SI SUBWORDTFSI (SIM_CPU *, TF, int);
-
-DI JOINSIDI (SIM_CPU *, SI, SI);
-DF JOINSIDF (SIM_CPU *, SI, SI);
-XF JOINSIXF (SIM_CPU *, SI, SI, SI);
-TF JOINSITF (SIM_CPU *, SI, SI, SI, SI);
+SF SUBWORDSISF (SI);
+SI SUBWORDSFSI (SF);
+SI SUBWORDDISI (DI, int);
+SI SUBWORDDFSI (DF, int);
+SI SUBWORDXFSI (XF, int);
+SI SUBWORDTFSI (TF, int);
+
+DI JOINSIDI (SI, SI);
+DF JOINSIDF (SI, SI);
+XF JOINSIXF (SI, SI, SI);
+TF JOINSITF (SI, SI, SI, SI);
#endif /* SUBWORD,JOIN */
\f
static INLINE SCACHE *
@cpu@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
- unsigned int hash_mask, int *last_insn_p, int FAST_P)
+ unsigned int hash_mask, int FAST_P)
{
/* First step: look up current insn in hash table. */
SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
if (! FAST_P)
PROFILE_COUNT_SCACHE_MISS (current_cpu);
-#define SET_LAST_INSN_P(last_p) do { *last_insn_p = (last_p); } while (0)
+#define SET_LAST_INSN_P(last_p) do { sc->last_insn_p = (last_p); } while (0)
/* begin extract-scache */
EOF
# convention, else the table becomes a real mess to understand and maintain.
case "${target}" in
- arm*-*-*) sim_target=arm ;;
+ arm*-*-*)
+ sim_target=arm
+ extra_subdirs="${extra_subdirs} testsuite"
+ ;;
strongarm*-*-*) sim_target=arm ;;
thumb*-*-*) sim_target=arm ;;
d10v-*-*) sim_target=d10v ;;
# convention, else the table becomes a real mess to understand and maintain.
case "${target}" in
- arm*-*-*) sim_target=arm ;;
+ arm*-*-*)
+ sim_target=arm
+ extra_subdirs="${extra_subdirs} testsuite"
+ ;;
strongarm*-*-*) sim_target=arm ;;
thumb*-*-*) sim_target=arm ;;
d10v-*-*) sim_target=d10v ;;