diff --git a/gdb/corefile.c b/gdb/corefile.c
index 5246f71..5d861de 100644
--- a/gdb/corefile.c
+++ b/gdb/corefile.c
@@ -146,7 +146,7 @@ reopen_exec_file (void)
   res = stat (filename, &st);
 
   if (exec_bfd_mtime && exec_bfd_mtime != st.st_mtime)
-    exec_file_attach (filename, 0);
+    exec_file_attach (exec_file_was_user_supplied, filename, 0);
   else
     /* If we accessed the file since last opening it, close it now;
        this stops GDB from holding the executable open after it
diff --git a/gdb/exec.c b/gdb/exec.c
index 3dfc437..ce50037 100644
--- a/gdb/exec.c
+++ b/gdb/exec.c
@@ -78,7 +78,7 @@ static void
 exec_open (const char *args, int from_tty)
 {
   target_preopen (from_tty);
-  exec_file_attach (args, from_tty);
+  exec_file_attach (1, args, from_tty);
 }
 
 /* Close and clear exec_bfd.  If we end up with no target sections to
@@ -102,6 +102,7 @@ exec_close (void)
 
       xfree (exec_filename);
       exec_filename = NULL;
+      exec_file_was_user_supplied = 0;
     }
 }
 
@@ -138,40 +139,67 @@ exec_file_clear (int from_tty)
 /* See gdbcore.h.  */
 
 void
-exec_file_locate_attach (int pid, int from_tty)
+exec_file_and_symbols_resync (struct inferior *inf, int from_tty)
 {
   char *exec_file, *full_exec_path = NULL;
+  struct cleanup *old_chain = save_current_program_space ();
 
-  /* Do nothing if we already have an executable filename.  */
-  exec_file = (char *) get_exec_file (0);
-  if (exec_file != NULL)
-    return;
+  /* Switch over temporarily, while reading executable and
+     symbols.  */
+  set_current_program_space (inf->pspace);
 
   /* Try to determine a filename from the process itself.  */
-  exec_file = target_pid_to_exec_file (pid);
-  if (exec_file == NULL)
-    return;
+  exec_file = target_pid_to_exec_file (inf->pid);
+  if (exec_file != NULL)
+    {
+      /* If gdb_sysroot is not empty and the discovered filename
+	 is absolute then prefix the filename with gdb_sysroot.  */
+      if (*gdb_sysroot != '\0' && IS_ABSOLUTE_PATH (exec_file))
+	full_exec_path = exec_file_find (exec_file, NULL);
 
-  /* If gdb_sysroot is not empty and the discovered filename
-     is absolute then prefix the filename with gdb_sysroot.  */
-  if (*gdb_sysroot != '\0' && IS_ABSOLUTE_PATH (exec_file))
-    full_exec_path = exec_file_find (exec_file, NULL);
+      if (full_exec_path == NULL)
+	{
+	  /* It's possible we don't have a full path, but rather just a
+	     filename.  Some targets, such as HP-UX, don't provide the
+	     full path, sigh.
+
+	     Attempt to qualify the filename against the source path.
+	     (If that fails, we'll just fall back on the original
+	     filename.  Not much more we can do...)  */
+	  if (!source_full_path_of (exec_file, &full_exec_path))
+	    full_exec_path = xstrdup (exec_file);
+	}
+    }
 
-  if (full_exec_path == NULL)
+  if (exec_filename != NULL && exec_file_was_user_supplied)
     {
-      /* It's possible we don't have a full path, but rather just a
-	 filename.  Some targets, such as HP-UX, don't provide the
-	 full path, sigh.
-
-	 Attempt to qualify the filename against the source path.
-	 (If that fails, we'll just fall back on the original
-	 filename.  Not much more we can do...)  */
-      if (!source_full_path_of (exec_file, &full_exec_path))
-	full_exec_path = xstrdup (exec_file);
+      if (full_exec_path != NULL && strcmp (full_exec_path, exec_filename) != 0)
+	warning (_("Detected exec-file mismatch on %s.  Running %s; Loaded %s"),
+		 target_pid_to_str (pid_to_ptid (inf->pid)),
+		 full_exec_path, exec_filename);
+      reopen_exec_file ();
     }
+  else if (full_exec_path != NULL)
+    exec_file_attach (0, full_exec_path, from_tty);
 
-  exec_file_attach (full_exec_path, from_tty);
-  symbol_file_add_main (full_exec_path, from_tty);
+  if (symfile_objfile != NULL && symfile_objfile_was_user_supplied)
+    {
+      const char *symbol_filename = objfile_filename (symfile_objfile);
+
+      if (full_exec_path != NULL
+	  && strcmp (full_exec_path, symbol_filename) != 0)
+	warning (_("Detected symbol-file mismatch on %s.  Running %s; Loaded %s"),
+		 target_pid_to_str (pid_to_ptid (inf->pid)),
+		 full_exec_path, symbol_filename);
+    }
+  else if (full_exec_path != NULL)
+    symbol_file_add_main (0, full_exec_path, from_tty);
+
+  /* Re-read symbol files that were modified since we last loaded
+     them.  */
+  reread_symbols ();
+
+  do_cleanups (old_chain);
 }
 
 /* Set FILENAME as the new exec file.
@@ -192,7 +220,7 @@ exec_file_locate_attach (int pid, int from_tty)
    we're supplying the exec pathname late for good reason.)  */
 
 void
-exec_file_attach (const char *filename, int from_tty)
+exec_file_attach (int user_supplied, const char *filename, int from_tty)
 {
   struct cleanup *cleanups;
 
@@ -333,6 +361,8 @@ exec_file_attach (const char *filename, int from_tty)
 
   do_cleanups (cleanups);
 
+  exec_file_was_user_supplied = user_supplied;
+
   bfd_cache_close_all ();
   observer_notify_executable_changed ();
 }
@@ -374,12 +404,12 @@ exec_file_command (char *args, int from_tty)
 
       filename = tilde_expand (*argv);
       make_cleanup (xfree, filename);
-      exec_file_attach (filename, from_tty);
+      exec_file_attach (1, filename, from_tty);
 
       do_cleanups (cleanups);
     }
   else
-    exec_file_attach (NULL, from_tty);
+    exec_file_attach (1, NULL, from_tty);
 }
 
 /* Set both the exec file and the symbol file, in one command.
diff --git a/gdb/exec.h b/gdb/exec.h
index c7f3b56..aef2926 100644
--- a/gdb/exec.h
+++ b/gdb/exec.h
@@ -32,6 +32,8 @@ struct objfile;
 #define exec_bfd current_program_space->ebfd
 #define exec_bfd_mtime current_program_space->ebfd_mtime
 #define exec_filename current_program_space->pspace_exec_filename
+#define exec_file_was_user_supplied \
+  current_program_space->pspace_exec_file_was_user_supplied
 
 /* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
    Returns 0 if OK, 1 on error.  */
diff --git a/gdb/gdbcore.h b/gdb/gdbcore.h
index 0c08b37..f34ee77 100644
--- a/gdb/gdbcore.h
+++ b/gdb/gdbcore.h
@@ -146,14 +146,23 @@ extern int write_files;
 
 extern void core_file_command (char *filename, int from_tty);
 
-extern void exec_file_attach (const char *filename, int from_tty);
-
-/* If the filename of the main executable is unknown, attempt to
-   determine it.  If a filename is determined, proceed as though
-   it was just specified with the "file" command.  Do nothing if
-   the filename of the main executable is already known.  */
-
-extern void exec_file_locate_attach (int pid, int from_tty);
+extern void exec_file_attach (int user_supplied, const char *filename,
+			      int from_tty);
+
+/* Resync executable and symbols.  Fetch the filename of the main
+   executable based on what the target is running.  If a filename can
+   be determined, and the current exec file loaded was not previously
+   user supplied, then load the discovered filename as exec file.  If
+   the executable loaded had been user supplied (with e.g., the "file"
+   command), issue a warning if there's a mismatch, and reload the
+   previously user-specified executable (in case the program was
+   recompiled since the last time we loaded it).  Likewise, if the
+   currenly load main symbol file was not user supplied, load the
+   discovered filename as symbol file; otherwise, if there's a
+   mismatch, warn.  End by reading all symbol files that have been
+   modified since the last time we loaded them.  */
+
+extern void exec_file_and_symbols_resync (struct inferior *inf, int from_tty);
 
 extern void exec_file_clear (int from_tty);
 
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 03282a7..528fd65 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -2490,15 +2490,12 @@ attach_command_post_wait (char *args, int from_tty, int async_exec)
   inferior = current_inferior ();
   inferior->control.stop_soon = NO_STOP_QUIETLY;
 
-  /* If no exec file is yet known, try to determine it from the
-     process itself.  */
-  if (get_exec_file (0) == NULL)
-    exec_file_locate_attach (ptid_get_pid (inferior_ptid), from_tty);
-  else
-    {
-      reopen_exec_file ();
-      reread_symbols ();
-    }
+  /* Attempt to open the file that was executed to create this
+     inferior.  If the user has explicitly specified executable
+     and/or symbol files then warn the user if their choices do
+     not match.  Otherwise, set exec_file and symfile_objfile to
+     the new file.  */
+  exec_file_and_symbols_resync (inferior, from_tty);
 
   /* Take any necessary post-attaching actions for this platform.  */
   target_post_attach (ptid_get_pid (inferior_ptid));
diff --git a/gdb/inferior.c b/gdb/inferior.c
index d0783d3..1e0d76e 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -882,13 +882,13 @@ add_inferior_command (char *args, int from_tty)
       if (exec != NULL)
 	{
 	  /* Switch over temporarily, while reading executable and
-	     symbols.q.  */
+	     symbols.  */
 	  set_current_program_space (inf->pspace);
 	  set_current_inferior (inf);
 	  switch_to_thread (null_ptid);
 
-	  exec_file_attach (exec, from_tty);
-	  symbol_file_add_main (exec, from_tty);
+	  exec_file_attach (1, exec, from_tty);
+	  symbol_file_add_main (SYMFILE_USER_SPECIFIED, exec, from_tty);
 	}
     }
 
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 445a612..7dae228 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1181,7 +1181,7 @@ follow_exec (ptid_t ptid, char *execd_pathname)
   gdb_assert (current_program_space == inf->pspace);
 
   /* That a.out is now the one to use.  */
-  exec_file_attach (execd_pathname, 0);
+  exec_file_attach (0, execd_pathname, 0);
 
   /* SYMFILE_DEFER_BP_RESET is used as the proper displacement for PIE
      (Position Independent Executable) main symbol file will get applied by
diff --git a/gdb/main.c b/gdb/main.c
index aecd60a..d4a5671 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -405,6 +405,29 @@ catch_command_errors_const (catch_command_errors_const_ftype *command,
   return 1;
 }
 
+/* Like catch_command_errors, but specifically for symbol/exec load
+   routines.  */
+
+typedef void (catch_exec_or_symbol_errors_ftype) (int, const char *, int);
+
+static int
+catch_exec_or_symbol_errors (catch_exec_or_symbol_errors_ftype *func,
+			     int arg, const char *filename, int from_tty)
+{
+  TRY
+    {
+      func (arg, filename, from_tty);
+    }
+  CATCH (e, RETURN_MASK_ALL)
+    {
+      exception_print (gdb_stderr, e);
+      return 0;
+    }
+  END_CATCH
+
+  return 1;
+}
+
 /* Type of this option.  */
 enum cmdarg_kind
 {
@@ -1047,20 +1070,23 @@ captured_main (void *data)
     {
       /* The exec file and the symbol-file are the same.  If we can't
          open it, better only print one error message.
-         catch_command_errors returns non-zero on success!  */
-      if (catch_command_errors_const (exec_file_attach, execarg,
-				      !batch_flag))
-	catch_command_errors_const (symbol_file_add_main, symarg,
-				    !batch_flag);
+         catch_exec_or_symbol_errors returns non-zero on success.  */
+      if (catch_exec_or_symbol_errors (exec_file_attach,
+				       1, execarg, !batch_flag))
+	catch_exec_or_symbol_errors (symbol_file_add_main,
+				     SYMFILE_USER_SPECIFIED,
+				     symarg, !batch_flag);
     }
   else
     {
       if (execarg != NULL)
-	catch_command_errors_const (exec_file_attach, execarg,
-				    !batch_flag);
+	catch_exec_or_symbol_errors (exec_file_attach, 1,
+				     execarg, !batch_flag);
+
       if (symarg != NULL)
-	catch_command_errors_const (symbol_file_add_main, symarg,
-				    !batch_flag);
+	catch_exec_or_symbol_errors (symbol_file_add_main,
+				     SYMFILE_USER_SPECIFIED,
+				     symarg, !batch_flag);
     }
 
   if (corearg && pidarg)
diff --git a/gdb/progspace.c b/gdb/progspace.c
index 1c0a254..730f44a 100644
--- a/gdb/progspace.c
+++ b/gdb/progspace.c
@@ -182,10 +182,11 @@ clone_program_space (struct program_space *dest, struct program_space *src)
   set_current_program_space (dest);
 
   if (src->pspace_exec_filename != NULL)
-    exec_file_attach (src->pspace_exec_filename, 0);
+    exec_file_attach (1, src->pspace_exec_filename, 0);
 
   if (src->symfile_object_file != NULL)
-    symbol_file_add_main (objfile_name (src->symfile_object_file), 0);
+    symbol_file_add_main (SYMFILE_USER_SPECIFIED,
+			  objfile_name (src->symfile_object_file), 0);
 
   do_cleanups (old_chain);
   return dest;
diff --git a/gdb/progspace.h b/gdb/progspace.h
index f960093..956372f 100644
--- a/gdb/progspace.h
+++ b/gdb/progspace.h
@@ -154,6 +154,12 @@ struct program_space
        It needs to be freed by xfree.  It is not NULL iff EBFD is not NULL.  */
     char *pspace_exec_filename;
 
+    /* Nonzero if pspace_exec_filename was supplied by the user,
+       either at startup (on the command-line) or via the "file" or
+       "add-inferior -exec" commands.  Zero if pspace_exec_filename is
+       unset or was discovered by GDB.  */
+    int pspace_exec_file_was_user_supplied;
+
     /* The address space attached to this program space.  More than one
        program space may be bound to the same address space.  In the
        traditional unix-like debugging scenario, this will usually
@@ -183,6 +189,12 @@ struct program_space
        (e.g. the argument to the "symbol-file" or "file" command).  */
     struct objfile *symfile_object_file;
 
+    /* Nonzero if symfile_object_file is set and was discovered by
+       GDB.  Zero if symfile_object_file is not set or was supplied
+       by the user, either at startup (on the command-line) or via the
+       "file" or "add-inferior -exec" commands.  */
+    int symfile_object_file_was_user_supplied;
+
     /* All known objfiles are kept in a linked list.  This points to
        the head of this list.  */
     struct objfile *objfiles;
@@ -215,6 +227,11 @@ struct program_space
 
 #define symfile_objfile current_program_space->symfile_object_file
 
+/* See program_space->symfile_object_file_was_user_supplied.  */
+
+#define symfile_objfile_was_user_supplied \
+  current_program_space->symfile_object_file_was_user_supplied
+
 /* All known objfiles are kept in a linked list.  This points to the
    root of this list.  */
 #define object_files current_program_space->objfiles
diff --git a/gdb/remote.c b/gdb/remote.c
index 9d97f6b..aed0749 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1636,10 +1636,13 @@ remote_add_inferior (int fake_pid_p, int pid, int attached,
   inf->attach_flag = attached;
   inf->fake_pid_p = fake_pid_p;
 
-  /* If no main executable is currently open then attempt to
-     open the file that was executed to create this inferior.  */
-  if (try_open_exec && get_exec_file (0) == NULL)
-    exec_file_locate_attach (pid, 1);
+  /* Attempt to open the file that was executed to create this
+     inferior.  If the user has explicitly specified executable
+     and/or symbol files then warn the user if their choices do
+     not match.  Otherwise, set exec_file and symfile_objfile to
+     the new file.  */
+  if (try_open_exec)
+    exec_file_and_symbols_resync (inf, 1);
 
   return inf;
 }
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 909dfb7..4a329c3 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -1039,7 +1039,7 @@ open_symbol_file_object (void *from_ttyp)
     }
 
   /* Have a pathname: read the symbol file.  */
-  symbol_file_add_main (filename, from_tty);
+  symbol_file_add_main (0, filename, from_tty);
 
   do_cleanups (cleanups);
   return 1;
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 0c35ffa..4b3d6c3 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -85,7 +85,8 @@ int readnow_symbol_files;	/* Read full symbols immediately.  */
 
 static void load_command (char *, int);
 
-static void symbol_file_add_main_1 (const char *args, int from_tty, int flags);
+static void symbol_file_add_main_1 (int add_flags, const char *args,
+				    int from_tty, int flags);
 
 static void add_symbol_file_command (char *, int);
 
@@ -1306,16 +1307,17 @@ symbol_file_add (const char *name, int add_flags,
    command itself.  */
 
 void
-symbol_file_add_main (const char *args, int from_tty)
+symbol_file_add_main (int add_flags, const char *args, int from_tty)
 {
-  symbol_file_add_main_1 (args, from_tty, 0);
+  symbol_file_add_main_1 (add_flags, args, from_tty, 0);
 }
 
 static void
-symbol_file_add_main_1 (const char *args, int from_tty, int flags)
+symbol_file_add_main_1 (int add_flags, const char *args, int from_tty,
+			int flags)
 {
-  const int add_flags = (current_inferior ()->symfile_flags
-			 | SYMFILE_MAINLINE | (from_tty ? SYMFILE_VERBOSE : 0));
+  add_flags |= (current_inferior ()->symfile_flags
+		| SYMFILE_MAINLINE | (from_tty ? SYMFILE_VERBOSE : 0));
 
   symbol_file_add (args, add_flags, NULL, flags);
 
@@ -1325,6 +1327,9 @@ symbol_file_add_main_1 (const char *args, int from_tty, int flags)
 
   if ((flags & SYMFILE_NO_READ) == 0)
     set_initial_language ();
+
+  symfile_objfile_was_user_supplied
+    = (add_flags & SYMFILE_USER_SPECIFIED) != 0;
 }
 
 void
@@ -1347,6 +1352,8 @@ symbol_file_clear (int from_tty)
   gdb_assert (symfile_objfile == NULL);
   if (from_tty)
     printf_unfiltered (_("No symbol file now.\n"));
+
+  symfile_objfile_was_user_supplied = 0;
 }
 
 static int
@@ -1663,7 +1670,8 @@ symbol_file_command (char *args, int from_tty)
 	    error (_("unknown option `%s'"), *argv);
 	  else
 	    {
-	      symbol_file_add_main_1 (*argv, from_tty, flags);
+	      symbol_file_add_main_1 (SYMFILE_USER_SPECIFIED,
+				      *argv, from_tty, flags);
 	      name = *argv;
 	    }
 
@@ -2536,7 +2544,8 @@ reread_symbols (void)
 	    {
 	      /* Reload EXEC_BFD without asking anything.  */
 
-	      exec_file_attach (bfd_get_filename (objfile->obfd), 0);
+	      exec_file_attach (exec_file_was_user_supplied,
+				bfd_get_filename (objfile->obfd), 0);
 	    }
 
 	  /* Keep the calls order approx. the same as in free_objfile.  */
diff --git a/gdb/symfile.h b/gdb/symfile.h
index 9ef3f0b..9ef3d19 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -457,7 +457,11 @@ enum symfile_add_flags
 
     /* Do not immediately read symbols for this file.  By default,
        symbols are read when the objfile is created.  */
-    SYMFILE_NO_READ = 1 << 4
+    SYMFILE_NO_READ = 1 << 4,
+
+    /* Whether the symbol file was user-supplied, as opposed to
+       auto-discovered by GDB.  */
+    SYMFILE_USER_SPECIFIED = 1 << 5,
   };
 
 extern struct objfile *symbol_file_add (const char *, int,
@@ -556,7 +560,8 @@ extern CORE_ADDR overlay_unmapped_address (CORE_ADDR, struct obj_section *);
 extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, struct obj_section *);
 
 /* Load symbols from a file.  */
-extern void symbol_file_add_main (const char *args, int from_tty);
+extern void symbol_file_add_main (int add_flags,
+				  const char *args, int from_tty);
 
 /* Clear GDB symbol tables.  */
 extern void symbol_file_clear (int from_tty);
