This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA] remote-sim.c: Add support for multiple sim instances


On Sun, 8 Aug 2010 17:42:57 +0100
Pedro Alves <pedro@codesourcery.com> wrote:

> On Saturday 07 August 2010 00:20:43, Kevin Buettner wrote:
> 
> > +static int
> > +gdbsim_close_inferior (struct inferior *inf, void *arg)
> > +{
> > +  struct sim_inferior_data *sim_data = inferior_data (inf,
> > +                                                      sim_inferior_data_key);
> > +  if (sim_data != NULL)
> > +    {
> > +      ptid_t ptid = sim_data->remote_sim_ptid;
> > +
> > +      sim_inferior_data_cleanup (inf, sim_data);
> > +      set_inferior_data (inf, sim_inferior_data_key, NULL);
> > +
> > +      inferior_ptid = ptid;
> 
> Please do "switch_to_thread (ptid)" instead, so that the
> program space and current inferior globals are kept
> in sync with inferior_ptid while mourning.

I did this, but testing showed an assertion failure, inf != NULL,
when the target was opened and then closed without creating an
inferior.

I ended up checking to see whether the inferior had been created prior
to invoking switch_to_thread() and generic_mourn_inferior(). 
Here's what I ended up with:

static int
gdbsim_close_inferior (struct inferior *inf, void *arg)
{
  struct sim_inferior_data *sim_data = inferior_data (inf,
                                                      sim_inferior_data_key);
  if (sim_data != NULL)
    {
      ptid_t ptid = sim_data->remote_sim_ptid;

      sim_inferior_data_cleanup (inf, sim_data);
      set_inferior_data (inf, sim_inferior_data_key, NULL);

      /* Having a ptid allocated and stored in remote_sim_ptid does
	 not mean that a corresponding inferior was ever created. 
	 Thus we need to verify the existence of an inferior using the
	 pid in question before setting inferior_ptid via
	 switch_to_thread() or mourning the inferior.  */
      if (find_inferior_pid (ptid_get_pid (ptid)) != NULL)
	{
	  switch_to_thread (ptid);
	  generic_mourn_inferior ();
	}
    }

  return 0;
}


> > +static int
> > +gdbsim_stop_inferior (struct inferior *inf, void *arg)
> > +{
> > +  struct sim_inferior_data *sim_data
> > +    = get_sim_inferior_data (inf, SIM_INSTANCE_NEEDED);
> > +
> > +  if (sim_data)
> > +    {
> > +      /* Try to stop the sim.  If it can't stop, exit GDB altogether.  */
> > +      if (!sim_stop (sim_data->gdbsim_desc))
> > +	{
> > +	  quit ();
> > +	}
> > +    }
> > +
> 
> Calling quit doesn't exit GDB; it throws the same exception ^C usually
> ends up throwing, cancelling the whole current operation all the way back
> to the top CLI prompt.   (Well, usually.  Some places catch all
> exceptions instead of just RETURN_MASK_ERROR.

This really had me puzzled for a while because quit() - defined in
utils.c - calls fatal().  When I looked up fatal, I didn't look
closely at the name of the file it was defined in, but I did see that
it printed a message and then called exit().  Problem was, I was
looking at the fatal() defined in gdbserver/utils.c, rather than the
definition of fatal in utils.c.  And, of course, the definition of
fatal() in utils.c does exactly what you say it does.

I ended up deleting that comment.

> Other than that, it looked good to me.  Thanks!

Thank you for the patch reviews!

Below is the patch which I've just committed:

	* remote-sim.c (program_loaded, gdbsim_desc, remote_sim_ptid)
	(resume_siggnal, resume_step): Move these static globals...
	(struct sim_inferior_data): ...into this new struct.
	(sim_inferior_data_key, next_pid, sim_argv, gdbsim_is_open):
	New static globals.
	(gdb_callback, callbacks_initialized): Move these globals to
	a point earlier in the file.
	(check_for_duplicate_sim_descriptor, get_sim_inferior_data)
	(get_sim_inferior_data_by_ptid, sim_inferior_data_cleanup)
	(gdbsim_close_inferior, gdbsim_resume_inferior)
	(gdbsim_stop_inferior): New functions.
	(SIM_INSTANCE_NOT_NEEDED, SIM_INSTANCE_NEEDED, INITIAL_PID):
	New constants.
	(gdbsim_fetch_register, gdbsim_store_register, gdbsim_load)
	(gdbsim_create_inferior, gdbsim_open, gdbsim_close, gdbsim_resume)
	(gdbsim_stop, gdbsim_cntrl_c, gdbsim_wait)
	(gdbsim_xfer_inferior_memory, gdbsim_files_info)
	(gdbsim_mourn_inferior, simulator_command, gdbsim_thread_alive,
	(gdbsim_pid_to_str): Invoke `get_sim_inferior_data' to set
	new local variable `sim_data' in each of these functions.  Use
	`sim_data' to reference former globals `program_loaded',
	`gdbsim_desc', `remote_sim_ptid', `resume_siggnal', and
	`resume_step'.
	(gdbsim_open): Remove local variable `argv'.  Put results of call
	to `gdb_buildargv' in `sim_argv' rather than in `argv'.  Don't
	make a cleanup for it.  Free it though when a sim instance cannot
	be obtained.
	(gdbsim_close): Free sim_argv and null it out as appropriate.
	Close sim instances in all inferiors.
	(gdbsim_cntrl_c): Stop all inferiors.
	(gdbsim_wait): 
	(_initialize_remote_sim): Initialize `sim_inferior_data_key'.

Index: remote-sim.c
===================================================================
RCS file: /cvs/src/src/gdb/remote-sim.c,v
retrieving revision 1.96
diff -u -p -r1.96 remote-sim.c
--- remote-sim.c	16 May 2010 21:11:14 -0000	1.96
+++ remote-sim.c	10 Aug 2010 00:12:36 -0000
@@ -101,19 +101,175 @@ void simulator_command (char *args, int 
 /* Forward data declarations */
 extern struct target_ops gdbsim_ops;
 
-static int program_loaded = 0;
+static const struct inferior_data *sim_inferior_data_key;
 
-/* We must keep track of whether the simulator has been opened or not because
-   GDB can call a target's close routine twice, but sim_close doesn't allow
-   this.  We also need to record the result of sim_open so we can pass it
-   back to the other sim_foo routines.  */
-static SIM_DESC gdbsim_desc = 0;
-
-/* This is the ptid we use while we're connected to the simulator.
-   Its value is arbitrary, as the simulator target don't have a notion
-   or processes or threads, but we need something non-null to place in
-   inferior_ptid.  */
-static ptid_t remote_sim_ptid;
+/* Simulator-specific, per-inferior state.  */
+struct sim_inferior_data {
+  /* Flag which indicates whether or not the program has been loaded.  */
+  int program_loaded;
+
+  /* Simulator descriptor for this inferior.  */
+  SIM_DESC gdbsim_desc;
+
+  /* This is the ptid we use for this particular simulator instance.  Its
+     value is somewhat arbitrary, as the simulator target don't have a
+     notion of tasks or threads, but we need something non-null to place
+     in inferior_ptid.  For simulators which permit multiple instances,
+     we also need a unique identifier to use for each inferior.  */
+  ptid_t remote_sim_ptid;
+
+  /* Signal with which to resume.  */
+  enum target_signal resume_siggnal;
+
+  /* Flag which indicates whether resume should step or not.  */
+  int resume_step;
+};
+
+/* Flag indicating the "open" status of this module.  It's set to 1
+   in gdbsim_open() and 0 in gdbsim_close().  */
+static int gdbsim_is_open = 0;
+
+/* Value of the next pid to allocate for an inferior.  As indicated
+   elsewhere, its initial value is somewhat arbitrary; it's critical
+   though that it's not zero or negative.  */
+static int next_pid;
+#define INITIAL_PID 42000
+
+/* Argument list to pass to sim_open().  It is allocated in gdbsim_open()
+   and deallocated in gdbsim_close().  The lifetime needs to extend beyond
+   the call to gdbsim_open() due to the fact that other sim instances other
+   than the first will be allocated after the gdbsim_open() call.  */
+static char **sim_argv = NULL;
+
+/* OS-level callback functions for write, flush, etc.  */
+static host_callback gdb_callback;
+static int callbacks_initialized = 0;
+
+/* Callback for iterate_over_inferiors.  It checks to see if the sim
+   descriptor passed via ARG is the same as that for the inferior
+   designated by INF.  Return true if so; false otherwise.  */
+
+static int
+check_for_duplicate_sim_descriptor (struct inferior *inf, void *arg)
+{
+  struct sim_inferior_data *sim_data;
+  SIM_DESC new_sim_desc = arg;
+
+  sim_data = inferior_data (inf, sim_inferior_data_key);
+
+  return (sim_data != NULL && sim_data->gdbsim_desc == new_sim_desc);
+}
+
+/* Flags indicating whether or not a sim instance is needed.  One of these
+   flags should be passed to get_sim_inferior_data().  */
+
+enum {SIM_INSTANCE_NOT_NEEDED = 0, SIM_INSTANCE_NEEDED = 1};
+
+/* Obtain pointer to per-inferior simulator data, allocating it if necessary.
+   Attempt to open the sim if SIM_INSTANCE_NEEDED is true.  */
+
+static struct sim_inferior_data *
+get_sim_inferior_data (struct inferior *inf, int sim_instance_needed)
+{
+  SIM_DESC sim_desc = NULL;
+  struct sim_inferior_data *sim_data
+    = inferior_data (inf, sim_inferior_data_key);
+
+  /* Try to allocate a new sim instance, if needed.  We do this ahead of
+     a potential allocation of a sim_inferior_data struct in order to
+     avoid needlessly allocating that struct in the event that the sim
+     instance allocation fails.  */
+  if (sim_instance_needed == SIM_INSTANCE_NEEDED 
+      && (sim_data == NULL || sim_data->gdbsim_desc == NULL))
+    {
+      struct inferior *idup;
+      sim_desc = sim_open (SIM_OPEN_DEBUG, &gdb_callback, exec_bfd, sim_argv);
+      if (sim_desc == NULL)
+	error (_("Unable to create simulator instance for inferior %d."),
+	       inf->num);
+
+      idup = iterate_over_inferiors (check_for_duplicate_sim_descriptor,
+                                     sim_desc);
+      if (idup != NULL)
+	{
+	  /* We don't close the descriptor due to the fact that it's
+	     shared with some other inferior.  If we were to close it,
+	     that might needlessly muck up the other inferior.  Of
+	     course, it's possible that the damage has already been
+	     done...  Note that it *will* ultimately be closed during
+	     cleanup of the other inferior.  */
+	  sim_desc = NULL;
+	  error (
+ _("Inferior %d and inferior %d would have identical simulator state.\n"
+   "(This simulator does not support the running of more than one inferior.)"),
+		 inf->num, idup->num); 
+        }
+    }
+
+  if (sim_data == NULL)
+    {
+      sim_data = XZALLOC(struct sim_inferior_data);
+      set_inferior_data (inf, sim_inferior_data_key, sim_data);
+
+      /* Allocate a ptid for this inferior.  */
+      sim_data->remote_sim_ptid = ptid_build (next_pid, 0, next_pid);
+      next_pid++;
+
+      /* Initialize the other instance variables.  */
+      sim_data->program_loaded = 0;
+      sim_data->gdbsim_desc = sim_desc;
+      sim_data->resume_siggnal = TARGET_SIGNAL_0;
+      sim_data->resume_step = 0;
+    }
+  else if (sim_desc)
+    {
+      /* This handles the case where sim_data was allocated prior to
+         needing a sim instance.  */
+      sim_data->gdbsim_desc = sim_desc;
+    }
+
+
+  return sim_data;
+}
+
+/* Return pointer to per-inferior simulator data using PTID to find the
+   inferior in question.  Return NULL when no inferior is found or
+   when ptid has a zero or negative pid component.  */
+
+static struct sim_inferior_data *
+get_sim_inferior_data_by_ptid (ptid_t ptid, int sim_instance_needed)
+{
+  struct inferior *inf;
+  int pid = ptid_get_pid (ptid);
+
+  if (pid <= 0)
+    return NULL;
+  
+  inf = find_inferior_pid (pid);
+
+  if (inf)
+    return get_sim_inferior_data (inf, sim_instance_needed);
+  else
+    return NULL;
+}
+
+/* Free the per-inferior simulator data.  */
+
+static void
+sim_inferior_data_cleanup (struct inferior *inf, void *data)
+{
+  struct sim_inferior_data *sim_data = data;
+
+  if (sim_data != NULL)
+    {
+      if (sim_data->gdbsim_desc)
+	{
+	  sim_close (sim_data->gdbsim_desc, 0);
+	  sim_data->gdbsim_desc = NULL;
+	}
+      xfree (sim_data);
+    }
+}
 
 static void
 dump_mem (char *buf, int len)
@@ -142,9 +298,6 @@ dump_mem (char *buf, int len)
     }
 }
 
-static host_callback gdb_callback;
-static int callbacks_initialized = 0;
-
 /* Initialize gdb_callback.  */
 
 static void
@@ -278,6 +431,8 @@ gdbsim_fetch_register (struct target_ops
 		       struct regcache *regcache, int regno)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NEEDED);
 
   if (regno == -1)
     {
@@ -310,7 +465,7 @@ gdbsim_fetch_register (struct target_ops
 
 	gdb_assert (regno >= 0 && regno < gdbarch_num_regs (gdbarch));
 	memset (buf, 0, MAX_REGISTER_SIZE);
-	nr_bytes = sim_fetch_register (gdbsim_desc,
+	nr_bytes = sim_fetch_register (sim_data->gdbsim_desc,
 				       gdbarch_register_sim_regno
 					 (gdbarch, regno),
 				       buf,
@@ -350,6 +505,9 @@ gdbsim_store_register (struct target_ops
 		       struct regcache *regcache, int regno)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NEEDED);
+
   if (regno == -1)
     {
       for (regno = 0; regno < gdbarch_num_regs (gdbarch); regno++)
@@ -362,7 +520,7 @@ gdbsim_store_register (struct target_ops
       int nr_bytes;
 
       regcache_cooked_read (regcache, regno, tmp);
-      nr_bytes = sim_store_register (gdbsim_desc,
+      nr_bytes = sim_store_register (sim_data->gdbsim_desc,
 				     gdbarch_register_sim_regno
 				       (gdbarch, regno),
 				     tmp, register_size (gdbarch, regno));
@@ -404,6 +562,8 @@ gdbsim_load (char *args, int fromtty)
 {
   char **argv;
   char *prog;
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NEEDED);
 
   if (args == NULL)
       error_no_arg (_("program to load"));
@@ -422,13 +582,13 @@ gdbsim_load (char *args, int fromtty)
   /* FIXME: We will print two messages on error.
      Need error to either not print anything if passed NULL or need
      another routine that doesn't take any arguments.  */
-  if (sim_load (gdbsim_desc, prog, NULL, fromtty) == SIM_RC_FAIL)
+  if (sim_load (sim_data->gdbsim_desc, prog, NULL, fromtty) == SIM_RC_FAIL)
     error (_("unable to load program"));
 
   /* FIXME: If a load command should reset the targets registers then
      a call to sim_create_inferior() should go here. */
 
-  program_loaded = 1;
+  sim_data->program_loaded = 1;
 }
 
 
@@ -444,12 +604,14 @@ static void
 gdbsim_create_inferior (struct target_ops *target, char *exec_file, char *args,
 			char **env, int from_tty)
 {
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NEEDED);
   int len;
   char *arg_buf, **argv;
 
   if (exec_file == 0 || exec_bfd == 0)
     warning (_("No executable file specified."));
-  if (!program_loaded)
+  if (!sim_data->program_loaded)
     warning (_("No program loaded."));
 
   if (remote_debug)
@@ -457,7 +619,7 @@ gdbsim_create_inferior (struct target_op
 		     (exec_file ? exec_file : "(NULL)"),
 		     args);
 
-  if (ptid_equal (inferior_ptid, remote_sim_ptid))
+  if (ptid_equal (inferior_ptid, sim_data->remote_sim_ptid))
     gdbsim_kill (target);
   remove_breakpoints ();
   init_wait_for_inferior ();
@@ -475,9 +637,9 @@ gdbsim_create_inferior (struct target_op
     }
   else
     argv = NULL;
-  sim_create_inferior (gdbsim_desc, exec_bfd, argv, env);
+  sim_create_inferior (sim_data->gdbsim_desc, exec_bfd, argv, env);
 
-  inferior_ptid = remote_sim_ptid;
+  inferior_ptid = sim_data->remote_sim_ptid;
   inferior_appeared (current_inferior (), ptid_get_pid (inferior_ptid));
   add_thread_silent (inferior_ptid);
 
@@ -496,18 +658,20 @@ gdbsim_open (char *args, int from_tty)
 {
   int len;
   char *arg_buf;
-  char **argv;
+  struct sim_inferior_data *sim_data;
+  SIM_DESC gdbsim_desc;
 
   if (remote_debug)
     printf_filtered ("gdbsim_open: args \"%s\"\n", args ? args : "(null)");
 
-  /* Remove current simulator if one exists.  Only do this if the simulator
-     has been opened because sim_close requires it.
-     This is important because the call to push_target below will cause
-     sim_close to be called if the simulator is already open, but push_target
-     is called after sim_open!  We can't move the call to push_target before
-     the call to sim_open because sim_open may invoke `error'.  */
-  if (gdbsim_desc != NULL)
+  /* Ensure that the sim target is not on the target stack.  This is
+     necessary, because if it is on the target stack, the call to
+     push_target below will invoke sim_close(), thus freeing various
+     state (including a sim instance) that we allocate prior to
+     invoking push_target().  We want to delay the push_target()
+     operation until after we complete those operations which could
+     error out.  */
+  if (gdbsim_is_open)
     unpush_target (&gdbsim_ops);
 
   len = (7 + 1			/* gdbsim */
@@ -543,14 +707,26 @@ gdbsim_open (char *args, int from_tty)
       strcat (arg_buf, " ");	/* 1 */
       strcat (arg_buf, args);
     }
-  argv = gdb_buildargv (arg_buf);
-  make_cleanup_freeargv (argv);
+  sim_argv = gdb_buildargv (arg_buf);
 
   init_callbacks ();
-  gdbsim_desc = sim_open (SIM_OPEN_DEBUG, &gdb_callback, exec_bfd, argv);
+  gdbsim_desc = sim_open (SIM_OPEN_DEBUG, &gdb_callback, exec_bfd, sim_argv);
 
   if (gdbsim_desc == 0)
-    error (_("unable to create simulator instance"));
+    {
+      freeargv (sim_argv);
+      sim_argv = NULL;
+      error (_("unable to create simulator instance"));
+    }
+
+  /* Reset the pid numberings for this batch of sim instances.  */
+  next_pid = INITIAL_PID;
+
+  /* Allocate the inferior data, but do not allocate a sim instance
+     since we've already just done that.  */
+  sim_data = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NOT_NEEDED);
+
+  sim_data->gdbsim_desc = gdbsim_desc;
 
   push_target (&gdbsim_ops);
   printf_filtered ("Connected to the simulator.\n");
@@ -558,6 +734,38 @@ gdbsim_open (char *args, int from_tty)
   /* There's nothing running after "target sim" or "load"; not until
      "run".  */
   inferior_ptid = null_ptid;
+
+  gdbsim_is_open = 1;
+}
+
+/* Callback for iterate_over_inferiors.  Called (indirectly) by
+   gdbsim_close().  */
+
+static int
+gdbsim_close_inferior (struct inferior *inf, void *arg)
+{
+  struct sim_inferior_data *sim_data = inferior_data (inf,
+                                                      sim_inferior_data_key);
+  if (sim_data != NULL)
+    {
+      ptid_t ptid = sim_data->remote_sim_ptid;
+
+      sim_inferior_data_cleanup (inf, sim_data);
+      set_inferior_data (inf, sim_inferior_data_key, NULL);
+
+      /* Having a ptid allocated and stored in remote_sim_ptid does
+	 not mean that a corresponding inferior was ever created. 
+	 Thus we need to verify the existence of an inferior using the
+	 pid in question before setting inferior_ptid via
+	 switch_to_thread() or mourning the inferior.  */
+      if (find_inferior_pid (ptid_get_pid (ptid)) != NULL)
+	{
+	  switch_to_thread (ptid);
+	  generic_mourn_inferior ();
+	}
+    }
+
+  return 0;
 }
 
 /* Does whatever cleanup is required for a target that we are no longer
@@ -572,21 +780,23 @@ gdbsim_open (char *args, int from_tty)
 static void
 gdbsim_close (int quitting)
 {
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NOT_NEEDED);
+
   if (remote_debug)
     printf_filtered ("gdbsim_close: quitting %d\n", quitting);
 
-  program_loaded = 0;
+  iterate_over_inferiors (gdbsim_close_inferior, NULL);
 
-  if (gdbsim_desc != NULL)
+  if (sim_argv != NULL)
     {
-      sim_close (gdbsim_desc, quitting);
-      gdbsim_desc = NULL;
+      freeargv (sim_argv);
+      sim_argv = NULL;
     }
 
   end_callbacks ();
-  generic_mourn_inferior ();
-  delete_thread_silent (remote_sim_ptid);
-  delete_inferior_silent (ptid_get_pid (remote_sim_ptid));
+
+  gdbsim_is_open = 0;
 }
 
 /* Takes a program previously attached to and detaches it.
@@ -613,21 +823,59 @@ gdbsim_detach (struct target_ops *ops, c
    or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given
    to the target, or zero for no signal.  */
 
-static enum target_signal resume_siggnal;
-static int resume_step;
+struct resume_data
+{
+  enum target_signal siggnal;
+  int step;
+};
+
+static int
+gdbsim_resume_inferior (struct inferior *inf, void *arg)
+{
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (inf, SIM_INSTANCE_NOT_NEEDED);
+  struct resume_data *rd = arg;
+
+  if (sim_data)
+    {
+      sim_data->resume_siggnal = rd->siggnal;
+      sim_data->resume_step = rd->step;
+
+      if (remote_debug)
+	printf_filtered (_("gdbsim_resume: pid %d, step %d, signal %d\n"),
+	                 inf->pid, rd->step, rd->siggnal);
+    }
+
+  /* When called from iterate_over_inferiors, a zero return causes the
+     iteration process to proceed until there are no more inferiors to
+     consider.  */
+  return 0;
+}
 
 static void
 gdbsim_resume (struct target_ops *ops,
 	       ptid_t ptid, int step, enum target_signal siggnal)
 {
-  if (!ptid_equal (inferior_ptid, remote_sim_ptid))
+  struct resume_data rd;
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data_by_ptid (ptid, SIM_INSTANCE_NOT_NEEDED);
+
+  rd.siggnal = siggnal;
+  rd.step = step;
+
+  /* We don't access any sim_data members within this function. 
+     What's of interest is whether or not the call to
+     get_sim_inferior_data_by_ptid(), above, is able to obtain a
+     non-NULL pointer.  If it managed to obtain a non-NULL pointer, we
+     know we have a single inferior to consider.  If it's NULL, we
+     either have multiple inferiors to resume or an error condition.  */
+
+  if (sim_data)
+    gdbsim_resume_inferior (find_inferior_pid (ptid_get_pid (ptid)), &rd);
+  else if (ptid_equal (ptid, minus_one_ptid))
+    iterate_over_inferiors (gdbsim_resume_inferior, &rd);
+  else
     error (_("The program is not being run."));
-
-  if (remote_debug)
-    printf_filtered ("gdbsim_resume: step %d, signal %d\n", step, siggnal);
-
-  resume_siggnal = siggnal;
-  resume_step = step;
 }
 
 /* Notify the simulator of an asynchronous request to stop.
@@ -637,14 +885,45 @@ gdbsim_resume (struct target_ops *ops,
    simulator is not running then the stop request is processed when
    the simulator is next resumed.
 
-   For simulators that do not support this operation, just abort */
+   For simulators that do not support this operation, just abort.  */
+
+static int
+gdbsim_stop_inferior (struct inferior *inf, void *arg)
+{
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (inf, SIM_INSTANCE_NEEDED);
+
+  if (sim_data)
+    {
+      if (!sim_stop (sim_data->gdbsim_desc))
+	{
+	  quit ();
+	}
+    }
+
+  /* When called from iterate_over_inferiors, a zero return causes the
+     iteration process to proceed until there are no more inferiors to
+     consider.  */
+  return 0;
+}
 
 static void
 gdbsim_stop (ptid_t ptid)
 {
-  if (!sim_stop (gdbsim_desc))
+  struct sim_inferior_data *sim_data;
+
+  if (ptid_equal (ptid, minus_one_ptid))
     {
-      quit ();
+      iterate_over_inferiors (gdbsim_stop_inferior, NULL);
+    }
+  else
+    {
+      struct inferior *inf = find_inferior_pid (ptid_get_pid (ptid));
+
+      if (inf == NULL)
+	error (_("Can't stop pid %d.  No inferior found."), ptid_get_pid (ptid));
+
+      gdbsim_stop_inferior (inf, NULL);
     }
 }
 
@@ -676,17 +955,32 @@ gdb_os_poll_quit (host_callback *p)
 static void
 gdbsim_cntrl_c (int signo)
 {
-  gdbsim_stop (remote_sim_ptid);
+  gdbsim_stop (minus_one_ptid);
 }
 
 static ptid_t
 gdbsim_wait (struct target_ops *ops,
 	     ptid_t ptid, struct target_waitstatus *status, int options)
 {
+  struct sim_inferior_data *sim_data;
   static RETSIGTYPE (*prev_sigint) ();
   int sigrc = 0;
   enum sim_stop reason = sim_running;
 
+  /* This target isn't able to (yet) resume more than one inferior at a time.
+     When ptid is minus_one_ptid, just use the current inferior.  If we're
+     given an explicit pid, we'll try to find it and use that instead.  */
+  if (ptid_equal (ptid, minus_one_ptid))
+    sim_data = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NEEDED);
+  else
+    {
+      sim_data = get_sim_inferior_data_by_ptid (ptid, SIM_INSTANCE_NEEDED);
+      if (sim_data == NULL)
+	error (_("Unable to wait for pid %d.  Inferior not found."),
+	       ptid_get_pid (ptid));
+      inferior_ptid = ptid;
+    }
+
   if (remote_debug)
     printf_filtered ("gdbsim_wait\n");
 
@@ -702,11 +996,13 @@ gdbsim_wait (struct target_ops *ops,
 #else
   prev_sigint = signal (SIGINT, gdbsim_cntrl_c);
 #endif
-  sim_resume (gdbsim_desc, resume_step, resume_siggnal);
+  sim_resume (sim_data->gdbsim_desc, sim_data->resume_step,
+              sim_data->resume_siggnal);
+
   signal (SIGINT, prev_sigint);
-  resume_step = 0;
+  sim_data->resume_step = 0;
 
-  sim_stop_reason (gdbsim_desc, &reason, &sigrc);
+  sim_stop_reason (sim_data->gdbsim_desc, &reason, &sigrc);
 
   switch (reason)
     {
@@ -764,15 +1060,26 @@ gdbsim_xfer_inferior_memory (CORE_ADDR m
 			     int write, struct mem_attrib *attrib,
 			     struct target_ops *target)
 {
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NOT_NEEDED);
+
   /* If no program is running yet, then ignore the simulator for
      memory.  Pass the request down to the next target, hopefully
      an exec file.  */
   if (!target_has_execution)
     return 0;
 
-  if (!program_loaded)
+  if (!sim_data->program_loaded)
     error (_("No program loaded."));
 
+  /* Note that we obtained the sim_data pointer above using
+     SIM_INSTANCE_NOT_NEEDED.  We do this so that we don't needlessly
+     allocate a sim instance prior to loading a program.   If we
+     get to this point in the code though, gdbsim_desc should be
+     non-NULL.  (Note that a sim instance is needed in order to load
+     the program...)  */
+  gdb_assert (sim_data->gdbsim_desc != NULL);
+
   if (remote_debug)
     {
       /* FIXME: Send to something other than STDOUT? */
@@ -786,11 +1093,11 @@ gdbsim_xfer_inferior_memory (CORE_ADDR m
 
   if (write)
     {
-      len = sim_write (gdbsim_desc, memaddr, myaddr, len);
+      len = sim_write (sim_data->gdbsim_desc, memaddr, myaddr, len);
     }
   else
     {
-      len = sim_read (gdbsim_desc, memaddr, myaddr, len);
+      len = sim_read (sim_data->gdbsim_desc, memaddr, myaddr, len);
       if (remote_debug && len > 0)
 	dump_mem (myaddr, len);
     }
@@ -800,6 +1107,8 @@ gdbsim_xfer_inferior_memory (CORE_ADDR m
 static void
 gdbsim_files_info (struct target_ops *target)
 {
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NEEDED);
   const char *file = "nothing";
 
   if (exec_bfd)
@@ -812,7 +1121,7 @@ gdbsim_files_info (struct target_ops *ta
     {
       printf_filtered ("\tAttached to %s running program %s\n",
 		       target_shortname, file);
-      sim_info (gdbsim_desc, 0);
+      sim_info (sim_data->gdbsim_desc, 0);
     }
 }
 
@@ -821,12 +1130,15 @@ gdbsim_files_info (struct target_ops *ta
 static void
 gdbsim_mourn_inferior (struct target_ops *target)
 {
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data (current_inferior (), SIM_INSTANCE_NOT_NEEDED);
+
   if (remote_debug)
     printf_filtered ("gdbsim_mourn_inferior:\n");
 
   remove_breakpoints ();
   generic_mourn_inferior ();
-  delete_thread_silent (remote_sim_ptid);
+  delete_thread_silent (sim_data->remote_sim_ptid);
 }
 
 /* Pass the command argument through to the simulator verbatim.  The
@@ -835,7 +1147,20 @@ gdbsim_mourn_inferior (struct target_ops
 void
 simulator_command (char *args, int from_tty)
 {
-  if (gdbsim_desc == NULL)
+  struct sim_inferior_data *sim_data;
+
+  /* We use inferior_data() instead of get_sim_inferior_data() here in
+     order to avoid attaching a sim_inferior_data struct to an
+     inferior unnecessarily.  The reason we take such care here is due
+     to the fact that this function, simulator_command(), may be called
+     even when the sim target is not active.  If we were to use
+     get_sim_inferior_data() here, it is possible that this call would
+     be made either prior to gdbsim_open() or after gdbsim_close(),
+     thus allocating memory that would not be garbage collected until
+     the ultimate destruction of the associated inferior.  */
+
+  sim_data  = inferior_data (current_inferior (), sim_inferior_data_key);
+  if (sim_data == NULL || sim_data->gdbsim_desc == NULL)
     {
 
       /* PREVIOUSLY: The user may give a command before the simulator
@@ -851,7 +1176,7 @@ simulator_command (char *args, int from_
       error (_("Not connected to the simulator target"));
     }
 
-  sim_do_command (gdbsim_desc, args);
+  sim_do_command (sim_data->gdbsim_desc, args);
 
   /* Invalidate the register cache, in case the simulator command does
      something funny. */
@@ -863,7 +1188,13 @@ simulator_command (char *args, int from_
 static int
 gdbsim_thread_alive (struct target_ops *ops, ptid_t ptid)
 {
-  if (ptid_equal (ptid, remote_sim_ptid))
+  struct sim_inferior_data *sim_data
+    = get_sim_inferior_data_by_ptid (ptid, SIM_INSTANCE_NOT_NEEDED);
+
+  if (sim_data == NULL)
+    return 0;
+
+  if (ptid_equal (ptid, sim_data->remote_sim_ptid))
     /* The simulators' task is always alive.  */
     return 1;
 
@@ -876,14 +1207,6 @@ gdbsim_thread_alive (struct target_ops *
 static char *
 gdbsim_pid_to_str (struct target_ops *ops, ptid_t ptid)
 {
-  static char buf[64];
-
-  if (ptid_equal (remote_sim_ptid, ptid))
-    {
-      xsnprintf (buf, sizeof buf, "Thread <main>");
-      return buf;
-    }
-
   return normal_pid_to_str (ptid);
 }
 
@@ -934,7 +1257,6 @@ _initialize_remote_sim (void)
   add_com ("sim", class_obscure, simulator_command,
 	   _("Send a command to the simulator."));
 
-  /* Yes, 42000 is arbitrary.  The only sense out of it, is that it
-     isn't 0.  */
-  remote_sim_ptid = ptid_build (42000, 0, 42000);
+  sim_inferior_data_key
+    = register_inferior_data_with_cleanup (sim_inferior_data_cleanup);
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]