gdb/
authorPedro Alves <palves@redhat.com>
Fri, 9 Nov 2012 01:47:20 +0000 (01:47 +0000)
committerPedro Alves <palves@redhat.com>
Fri, 9 Nov 2012 01:47:20 +0000 (01:47 +0000)
2012-11-09  Pedro Alves  <palves@redhat.com>

* gdbarch.sh (target_gdbarch) <gdbarch.h>: Reimplement as macro.
(get_target_gdbarch) <gdbarch.h>: New function.
(startup_gdbarch) <gdbarch.h>: Declare.
<gdbarch.c> (target_gdbarch): Delete.
<gdbarch.c> (deprecated_target_gdbarch_select_hack): Set the
current inferior's gdbarch.
<gdbarch.c> (get_target_gdbarch): New function.
* inferior.c: Include target-descriptions.h.
(free_inferior): Free target description info.
(add_inferior_with_spaces): Set the inferior's initial
architecture.
(clone_inferior_command): Copy the original inferior's target
description if it was user specified.
(initialize_inferiors): Add comment.
* inferior.h (struct target_desc_info): Forward declare.
(struct inferior) <gdbarch>: New field.
* linux-nat.c: Include target-descriptions.h.
(linux_child_follow_fork): Copy the parent's architecture and
target description to the child.
* target-descriptions.c: Include inferior.h.
(struct target_desc_info): New structure, holding the equivalents
of ...
(target_desc_fetched, current_target_desc)
(target_description_filename): ... these removed globals.
(get_tdesc_info, target_desc_info_from_user_p)
(copy_inferior_target_desc_info, target_desc_info_free): New.
(target_desc_fetched, current_target_desc)
(target_description_filename): Reimplemented as convenience
macros.
(tdesc_filename_cmd_string): New global.
(set_tdesc_filename_cmd): Copy the string manipulated by the "set
tdescs filename ..." commands to the per-inferior equivalent.
(show_tdesc_filename_cmd): Get the value to show from the
per-inferior description filename.
(_initilize_target_descriptions): Change the "set/show tdesc
filename" commands' variable.
* target-descriptions.h (struct target_desc, struct target_desc_info)
(struct inferior): Forward declare.
(target_find_description, target_clear_description)
(target_current_description): Adjust comments.
(copy_inferior_target_desc_info, target_desc_info_free)
(target_desc_info_from_user_p). Declare.

gdb/testsuite/
2012-11-09  Pedro Alves  <palves@redhat.com>

* gdb.multi/multi-arch.exp: New.

gdb/ChangeLog
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/inferior.c
gdb/inferior.h
gdb/linux-nat.c
gdb/target-descriptions.c
gdb/target-descriptions.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.multi/multi-arch.exp [new file with mode: 0644]

index a74797addbb56c262967625833ce2e0c462e91fd..6797c72c3c874140559004aa4d816b79856bd0e5 100644 (file)
@@ -1,3 +1,48 @@
+2012-11-09  Pedro Alves  <palves@redhat.com>
+
+       * gdbarch.sh (target_gdbarch) <gdbarch.h>: Reimplement as macro.
+       (get_target_gdbarch) <gdbarch.h>: New function.
+       (startup_gdbarch) <gdbarch.h>: Declare.
+       <gdbarch.c> (target_gdbarch): Delete.
+       <gdbarch.c> (deprecated_target_gdbarch_select_hack): Set the
+       current inferior's gdbarch.
+       <gdbarch.c> (get_target_gdbarch): New function.
+       * inferior.c: Include target-descriptions.h.
+       (free_inferior): Free target description info.
+       (add_inferior_with_spaces): Set the inferior's initial
+       architecture.
+       (clone_inferior_command): Copy the original inferior's target
+       description if it was user specified.
+       (initialize_inferiors): Add comment.
+       * inferior.h (struct target_desc_info): Forward declare.
+       (struct inferior) <gdbarch>: New field.
+       * linux-nat.c: Include target-descriptions.h.
+       (linux_child_follow_fork): Copy the parent's architecture and
+       target description to the child.
+       * target-descriptions.c: Include inferior.h.
+       (struct target_desc_info): New structure, holding the equivalents
+       of ...
+       (target_desc_fetched, current_target_desc)
+       (target_description_filename): ... these removed globals.
+       (get_tdesc_info, target_desc_info_from_user_p)
+       (copy_inferior_target_desc_info, target_desc_info_free): New.
+       (target_desc_fetched, current_target_desc)
+       (target_description_filename): Reimplemented as convenience
+       macros.
+       (tdesc_filename_cmd_string): New global.
+       (set_tdesc_filename_cmd): Copy the string manipulated by the "set
+       tdescs filename ..." commands to the per-inferior equivalent.
+       (show_tdesc_filename_cmd): Get the value to show from the
+       per-inferior description filename.
+       (_initilize_target_descriptions): Change the "set/show tdesc
+       filename" commands' variable.
+       * target-descriptions.h (struct target_desc, struct target_desc_info)
+       (struct inferior): Forward declare.
+       (target_find_description, target_clear_description)
+       (target_current_description): Adjust comments.
+       (copy_inferior_target_desc_info, target_desc_info_free)
+       (target_desc_info_from_user_p). Declare.
+
 2012-11-08  Stephane Carrez  <Stephane.Carrez@gmail.com>
 
        * tui/tui-hooks.c (tui_about_to_proceed): New function.
index 6bc57afa69e6dcd8b56f643c1b6716e3da83c475..25e47506809c38cbe8cc184c4140d85730112f77 100644 (file)
@@ -457,7 +457,6 @@ struct gdbarch startup_gdbarch =
   /* startup_gdbarch() */
 };
 
-struct gdbarch *target_gdbarch = &startup_gdbarch;
 
 /* Create a new ``struct gdbarch'' based on information provided by
    ``struct gdbarch_info''.  */
@@ -4671,11 +4670,19 @@ deprecated_target_gdbarch_select_hack (struct gdbarch *new_gdbarch)
 {
   gdb_assert (new_gdbarch != NULL);
   gdb_assert (new_gdbarch->initialized_p);
-  target_gdbarch = new_gdbarch;
+  current_inferior ()->gdbarch = new_gdbarch;
   observer_notify_architecture_changed (new_gdbarch);
   registers_changed ();
 }
 
+/* Helper for 'target_gdbarch'.  */
+
+struct gdbarch *
+get_target_gdbarch (void)
+{
+  return current_inferior ()->gdbarch;
+}
+
 extern void _initialize_gdbarch (void);
 
 void
index 696bf14d3c1055e0dcee8f8c3ca347c9c879c456..5afb3db57cb0447466edf29842601dd6513a4fbc 100644 (file)
@@ -58,17 +58,26 @@ struct agent_expr;
 struct axs_value;
 struct stap_parse_info;
 
-/* The architecture associated with the connection to the target.
-   The architecture vector provides some information that is really
-   a property of the target: The layout of certain packets, for instance;
-   or the solib_ops vector.  Etc.  To differentiate architecture accesses
-   to per-target properties from per-thread/per-frame/per-objfile properties,
-   accesses to per-target properties should be made through target_gdbarch.
-
-   Eventually, when support for multiple targets is implemented in
-   GDB, this global should be made target-specific.  */
-extern struct gdbarch *target_gdbarch;
+/* The architecture associated with the inferior through the
+   connection to the target.
+
+   The architecture vector provides some information that is really a
+   property of the inferior, accessed through a particular target:
+   ptrace operations; the layout of certain RSP packets; the solib_ops
+   vector; etc.  To differentiate architecture accesses to
+   per-inferior/target properties from
+   per-thread/per-frame/per-objfile properties, accesses to
+   per-inferior/target properties should be made through this
+   gdbarch.  */
+
+/* This is a convenience wrapper for 'current_inferior ()->gdbarch'.  */
+#define target_gdbarch get_target_gdbarch ()
+extern struct gdbarch *get_target_gdbarch (void);
+
+/* The initial, default architecture.  It uses host values (for want of a better
+   choice).  */
+extern struct gdbarch startup_gdbarch;
+
 
 /* Callback type for the 'iterate_over_objfiles_in_search_order'
    gdbarch  method.  */
index e3e6329151c9c0c6a686fc6de2e275b31a054e91..13d5cc6539cb9485864bc51ebfa28d8fb85e2bff 100755 (executable)
@@ -1076,17 +1076,26 @@ struct agent_expr;
 struct axs_value;
 struct stap_parse_info;
 
-/* The architecture associated with the connection to the target.
-   The architecture vector provides some information that is really
-   a property of the target: The layout of certain packets, for instance;
-   or the solib_ops vector.  Etc.  To differentiate architecture accesses
-   to per-target properties from per-thread/per-frame/per-objfile properties,
-   accesses to per-target properties should be made through target_gdbarch.
-
-   Eventually, when support for multiple targets is implemented in
-   GDB, this global should be made target-specific.  */
-extern struct gdbarch *target_gdbarch;
+/* The architecture associated with the inferior through the
+   connection to the target.
+
+   The architecture vector provides some information that is really a
+   property of the inferior, accessed through a particular target:
+   ptrace operations; the layout of certain RSP packets; the solib_ops
+   vector; etc.  To differentiate architecture accesses to
+   per-inferior/target properties from
+   per-thread/per-frame/per-objfile properties, accesses to
+   per-inferior/target properties should be made through this
+   gdbarch.  */
+
+/* This is a convenience wrapper for 'current_inferior ()->gdbarch'.  */
+#define target_gdbarch get_target_gdbarch ()
+extern struct gdbarch *get_target_gdbarch (void);
+
+/* The initial, default architecture.  It uses host values (for want of a better
+   choice).  */
+extern struct gdbarch startup_gdbarch;
+
 
 /* Callback type for the 'iterate_over_objfiles_in_search_order'
    gdbarch  method.  */
@@ -1559,7 +1568,6 @@ cat <<EOF
   /* startup_gdbarch() */
 };
 
-struct gdbarch *target_gdbarch = &startup_gdbarch;
 EOF
 
 # Create a new gdbarch struct
@@ -2278,11 +2286,19 @@ deprecated_target_gdbarch_select_hack (struct gdbarch *new_gdbarch)
 {
   gdb_assert (new_gdbarch != NULL);
   gdb_assert (new_gdbarch->initialized_p);
-  target_gdbarch = new_gdbarch;
+  current_inferior ()->gdbarch = new_gdbarch;
   observer_notify_architecture_changed (new_gdbarch);
   registers_changed ();
 }
 
+/* Helper for 'target_gdbarch'.  */
+
+struct gdbarch *
+get_target_gdbarch (void)
+{
+  return current_inferior ()->gdbarch;
+}
+
 extern void _initialize_gdbarch (void);
 
 void
index f46e1e336cc4a34c42191d55ec44c8411e2d077d..5bb15140ec46e54c49c27fe53bf23aa790440e26 100644 (file)
@@ -33,6 +33,8 @@
 #include "environ.h"
 #include "cli/cli-utils.h"
 #include "continuations.h"
+#include "arch-utils.h"
+#include "target-descriptions.h"
 
 void _initialize_inferiors (void);
 
@@ -98,6 +100,7 @@ free_inferior (struct inferior *inf)
   xfree (inf->args);
   xfree (inf->terminal);
   free_environ (inf->environment);
+  target_desc_info_free (inf->tdesc_info);
   xfree (inf->private);
   xfree (inf);
 }
@@ -794,6 +797,7 @@ add_inferior_with_spaces (void)
   struct address_space *aspace;
   struct program_space *pspace;
   struct inferior *inf;
+  struct gdbarch_info info;
 
   /* If all inferiors share an address space on this system, this
      doesn't really return a new address space; otherwise, it
@@ -804,6 +808,14 @@ add_inferior_with_spaces (void)
   inf->pspace = pspace;
   inf->aspace = pspace->aspace;
 
+  /* Setup the inferior's initial arch, based on information obtained
+     from the global "set ..." options.  */
+  gdbarch_info_init (&info);
+  inf->gdbarch = gdbarch_find_by_info (info);
+  /* The "set ..." options reject invalid settings, so we should
+     always have a valid arch by now.  */
+  gdb_assert (inf->gdbarch != NULL);
+
   return inf;
 }
 
@@ -942,6 +954,12 @@ clone_inferior_command (char *args, int from_tty)
       inf = add_inferior (0);
       inf->pspace = pspace;
       inf->aspace = pspace->aspace;
+      inf->gdbarch = orginf->gdbarch;
+
+      /* If the original inferior had a user specified target
+        description, make the clone use it too.  */
+      if (target_desc_info_from_user_p (inf->tdesc_info))
+       copy_inferior_target_desc_info (inf, orginf);
 
       printf_filtered (_("Added inferior %d.\n"), inf->num);
 
@@ -977,6 +995,8 @@ initialize_inferiors (void)
   current_inferior_ = add_inferior (0);
   current_inferior_->pspace = current_program_space;
   current_inferior_->aspace = current_program_space->aspace;
+  /* The architecture will be initialized shortly, by
+     initialize_current_architecture.  */
 
   add_info ("inferiors", info_inferiors_command, 
            _("IDs of specified inferiors (all inferiors if no argument)."));
index b2607c39f502d396a033a0ec19f4c803aa71f666..e1e7d29a659dc16bec86fd431c63bc2cbc55b422 100644 (file)
@@ -30,6 +30,7 @@ struct gdbarch;
 struct regcache;
 struct ui_out;
 struct terminal_info;
+struct target_desc_info;
 
 #include "ptid.h"
 
@@ -513,6 +514,23 @@ struct inferior
      from enum symfile_add_flags.  */
   int symfile_flags;
 
+  /* Info about an inferior's target description (if it's fetched; the
+     user supplied description's filename, if any; etc.).  */
+  struct target_desc_info *tdesc_info;
+
+  /* The architecture associated with the inferior through the
+     connection to the target.
+
+     The architecture vector provides some information that is really
+     a property of the inferior, accessed through a particular target:
+     ptrace operations; the layout of certain RSP packets; the
+     solib_ops vector; etc.  To differentiate architecture accesses to
+     per-inferior/target properties from
+     per-thread/per-frame/per-objfile properties, accesses to
+     per-inferior/target properties should be made through
+     this gdbarch.  */
+  struct gdbarch *gdbarch;
+
   /* Per inferior data-pointers required by other GDB modules.  */
   REGISTRY_FIELDS;
 };
index 351656514553334c5a942ccda16878fc213a7ad7..c282e5d2abf3f1a74f411473ef4edae375dd63e7 100644 (file)
@@ -66,6 +66,7 @@
 #include "exceptions.h"
 #include "linux-ptrace.h"
 #include "buffer.h"
+#include "target-descriptions.h"
 
 #ifndef SPUFS_MAGIC
 #define SPUFS_MAGIC 0x23c9b64e
@@ -723,6 +724,8 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
          parent_inf = current_inferior ();
          child_inf->attach_flag = parent_inf->attach_flag;
          copy_terminal_info (child_inf, parent_inf);
+         child_inf->gdbarch = parent_inf->gdbarch;
+         copy_inferior_target_desc_info (child_inf, parent_inf);
 
          old_chain = save_inferior_ptid ();
          save_current_program_space ();
@@ -887,6 +890,8 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
       parent_inf = current_inferior ();
       child_inf->attach_flag = parent_inf->attach_flag;
       copy_terminal_info (child_inf, parent_inf);
+      child_inf->gdbarch = parent_inf->gdbarch;
+      copy_inferior_target_desc_info (child_inf, parent_inf);
 
       parent_pspace = parent_inf->pspace;
 
index 8b8173043d6f9e6391e7debf090319ea76537553..468fe4274cc9266cdea395c3b264f09e83e60191 100644 (file)
@@ -34,6 +34,7 @@
 #include "gdb_assert.h"
 #include "gdb_obstack.h"
 #include "hashtab.h"
+#include "inferior.h"
 
 /* Types.  */
 
@@ -231,34 +232,92 @@ struct tdesc_arch_data
   gdbarch_register_reggroup_p_ftype *pseudo_register_reggroup_p;
 };
 
-/* Global state.  These variables are associated with the current
-   target; if GDB adds support for multiple simultaneous targets, then
-   these variables should become target-specific data.  */
+/* Info about an inferior's target description.  There's one of these
+   for each inferior.  */
 
-/* A flag indicating that a description has already been fetched from
-   the current target, so it should not be queried again.  */
+struct target_desc_info
+{
+  /* A flag indicating that a description has already been fetched
+     from the target, so it should not be queried again.  */
+
+  int fetched;
 
-static int target_desc_fetched;
+  /* The description fetched from the target, or NULL if the target
+     did not supply any description.  Only valid when
+     target_desc_fetched is set.  Only the description initialization
+     code should access this; normally, the description should be
+     accessed through the gdbarch object.  */
 
-/* The description fetched from the current target, or NULL if the
-   current target did not supply any description.  Only valid when
-   target_desc_fetched is set.  Only the description initialization
-   code should access this; normally, the description should be
-   accessed through the gdbarch object.  */
+  const struct target_desc *tdesc;
 
-static const struct target_desc *current_target_desc;
+  /* The filename to read a target description from, as set by "set
+     tdesc filename ..."  */
 
-/* Other global variables.  */
+  char *filename;
+};
 
-/* The filename to read a target description from.  */
+/* Get the inferior INF's target description info, allocating one on
+   the stop if necessary.  */
 
-static char *target_description_filename;
+static struct target_desc_info *
+get_tdesc_info (struct inferior *inf)
+{
+  if (inf->tdesc_info == NULL)
+    inf->tdesc_info = XCNEW (struct target_desc_info);
+  return inf->tdesc_info;
+}
 
 /* A handle for architecture-specific data associated with the
    target description (see struct tdesc_arch_data).  */
 
 static struct gdbarch_data *tdesc_data;
 
+/* See target-descriptions.h.  */
+
+int
+target_desc_info_from_user_p (struct target_desc_info *info)
+{
+  return info != NULL && info->filename != NULL;
+}
+
+/* See target-descriptions.h.  */
+
+void
+copy_inferior_target_desc_info (struct inferior *destinf, struct inferior *srcinf)
+{
+  struct target_desc_info *src = get_tdesc_info (srcinf);
+  struct target_desc_info *dest = get_tdesc_info (destinf);
+
+  dest->fetched = src->fetched;
+  dest->tdesc = src->tdesc;
+  dest->filename = src->filename != NULL ? xstrdup (src->filename) : NULL;
+}
+
+/* See target-descriptions.h.  */
+
+void
+target_desc_info_free (struct target_desc_info *tdesc_info)
+{
+  if (tdesc_info != NULL)
+    {
+      xfree (tdesc_info->filename);
+      xfree (tdesc_info);
+    }
+}
+
+/* Convenience helper macros.  */
+
+#define target_desc_fetched \
+  get_tdesc_info (current_inferior ())->fetched
+#define current_target_desc \
+  get_tdesc_info (current_inferior ())->tdesc
+#define target_description_filename \
+  get_tdesc_info (current_inferior ())->filename
+
+/* The string manipulated by the "set tdesc filename ..." command.  */
+
+static char *tdesc_filename_cmd_string;
+
 /* Fetch the current target's description, and switch the current
    architecture to one which incorporates that description.  */
 
@@ -1510,6 +1569,9 @@ static void
 set_tdesc_filename_cmd (char *args, int from_tty,
                        struct cmd_list_element *c)
 {
+  xfree (target_description_filename);
+  target_description_filename = xstrdup (tdesc_filename_cmd_string);
+
   target_clear_description ();
   target_find_description ();
 }
@@ -1519,6 +1581,8 @@ show_tdesc_filename_cmd (struct ui_file *file, int from_tty,
                         struct cmd_list_element *c,
                         const char *value)
 {
+  value = target_description_filename;
+
   if (value != NULL && *value != '\0')
     printf_filtered (_("The target description will be read from \"%s\".\n"),
                     value);
@@ -1758,7 +1822,7 @@ Unset target description specific variables."),
                  0 /* allow-unknown */, &unsetlist);
 
   add_setshow_filename_cmd ("filename", class_obscure,
-                           &target_description_filename,
+                           &tdesc_filename_cmd_string,
                            _("\
 Set the file to read for an XML target description"), _("\
 Show the file to read for an XML target description"), _("\
index 6a09a9095c30d02ae9ad423969535300db7e574f..f0841d12c9f6c11a0a585fcbe26c8eda88fb5b03 100644 (file)
@@ -28,23 +28,45 @@ struct tdesc_type;
 struct tdesc_reg;
 struct target_desc;
 struct target_ops;
+struct target_desc;
+/* An inferior's target description info is stored in this opaque
+   object.  There's one such object per inferior.  */
+struct target_desc_info;
+struct inferior;
 
-/* Fetch the current target's description, and switch the current
+/* Fetch the current inferior's description, and switch its current
    architecture to one which incorporates that description.  */
 
 void target_find_description (void);
 
-/* Discard any description fetched from the current target, and switch
-   the current architecture to one with no target description.  */
+/* Discard any description fetched from the target for the current
+   inferior, and switch the current architecture to one with no target
+   description.  */
 
 void target_clear_description (void);
 
-/* Return the global current target description.  This should only be
-   used by gdbarch initialization code; most access should be through
-   an existing gdbarch.  */
+/* Return the current inferior's target description.  This should only
+   be used by gdbarch initialization code; most access should be
+   through an existing gdbarch.  */
 
 const struct target_desc *target_current_description (void);
 
+/* Copy inferior target description data.  Used for example when
+   handling (v)forks, where child's description is the same as the
+   parent's, since the child really is a copy of the parent.  */
+
+void copy_inferior_target_desc_info (struct inferior *destinf,
+                                    struct inferior *srcinf);
+
+/* Free a target_desc_info object.  */
+
+void target_desc_info_free (struct target_desc_info *tdesc_info);
+
+/* Returns true if INFO indicates the target description had been
+   supplied by the user.  */
+
+int target_desc_info_from_user_p (struct target_desc_info *info);
+
 /* Record architecture-specific functions to call for pseudo-register
    support.  If tdesc_use_registers is called and gdbarch_num_pseudo_regs
    is greater than zero, then these should be called as well.
index 5ff056cf3b3ca1fcc7e717b12f032df58a817f10..9afc594138d3633fa7f09ef904898728ffaf1c52 100644 (file)
@@ -1,3 +1,7 @@
+2012-11-09  Pedro Alves  <palves@redhat.com>
+
+       * gdb.multi/multi-arch.exp: New.
+
 2012-11-08  Tom Tromey  <tromey@redhat.com>
 
        * gdb.base/siginfo-obj.exp: Create core file.  Test siginfo from
diff --git a/gdb/testsuite/gdb.multi/multi-arch.exp b/gdb/testsuite/gdb.multi/multi-arch.exp
new file mode 100644 (file)
index 0000000..0adc127
--- /dev/null
@@ -0,0 +1,76 @@
+# Copyright 2009-2012 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test multi-exec / multi-process features that work for all configurations,
+# even ones that cannot run multiple processes simultaneously.
+
+set testfile "multi-arch"
+
+# The plain remote target can't do multiple inferiors.
+if [target_info exists use_gdb_stub] {
+    return
+}
+
+# Can't use standard_testfile, we want executables with specialized
+# names.
+set exec1 "ma-hello"
+set srcfile1 hello.c
+set binfile1 [standard_output_file ${exec1}]
+
+set exec2 "ma-hangout"
+set srcfile2 hangout.c
+set binfile2 [standard_output_file ${exec2}]
+
+# Build two executables, one for each arch.
+
+if [istarget "s390*-*-*"] {
+    set march1 "-m64"
+    set march2 "-m31"
+} else {
+    set march1 "-m64"
+    set march2 "-m32"
+}
+
+if { [prepare_for_testing ${testfile}.exp ${exec1} "${srcfile1}" \
+         [list debug nowarnings additional_flags=${march1}]] } {
+    return -1
+}
+
+if { [prepare_for_testing ${testfile}.exp ${exec2} "${srcfile2}" \
+         [list debug nowarnings additional_flags=${march2}]] } {
+    return -1
+}
+
+# Start inferior 1
+
+clean_restart ${exec1}
+if ![runto_main] then {
+    fail "starting inferior 1"
+}
+
+# Add and start inferior 2
+
+gdb_test "add-inferior" "Added inferior 2.*" "add empty inferior 2"
+gdb_test "inferior 2" "Switching to inferior 2.*" "switch to inferior 2"
+gdb_load ${binfile2}
+
+if ![runto_main] then {
+    fail "starting inferior 2"
+}
+
+# Check we do have two inferiors loaded.
+
+gdb_test "info inferiors" \
+    "Executable.*${exec2}.*${exec1}.*"