diff --git a/gdb/defs.h b/gdb/defs.h
index 07739cc..02ff94c 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -339,12 +339,20 @@ enum openp_flags
   /* Ask for bfd * to be returned in file_location.  */
   OPF_IS_BFD          = (1 << 2),
 
-  /* Open the file in read/write mode if WRITE_FILES says so.  */
-  OPF_OPEN_RW_TMP     = (1 << 3),
+  /* bfd_get_filename can be incorrect then, use only if you keep your
+     original filename separate from resulting bfd.
+     Returned file_location.filename is not canonicalized.  */
+  OPF_BFD_CANONICAL   = (1 << 3),
 };
 
 extern int openp (const char *, enum openp_flags, const char *, char **);
 
+extern bfd *openp_bfd (const char *path, enum openp_flags opts,
+		       const char *string);
+
+extern struct file_location openp_file (const char *path, enum openp_flags opts,
+					const char *string);
+
 extern int source_full_path_of (const char *, char **);
 
 extern void mod_path (char *, char **);
diff --git a/gdb/exec.c b/gdb/exec.c
index e87d154..8222e51 100644
--- a/gdb/exec.c
+++ b/gdb/exec.c
@@ -216,81 +216,37 @@ exec_file_attach (const char *filename, int from_tty)
     }
   else
     {
-      int load_via_target = 0;
-      char *scratch_pathname, *canonical_pathname;
-      int scratch_chan;
       struct target_section *sections = NULL, *sections_end = NULL;
       char **matching;
 
-      if (is_target_filename (filename))
-	{
-	  if (target_filesystem_is_local ())
-	    filename += strlen (TARGET_SYSROOT_PREFIX);
-	  else
-	    load_via_target = 1;
-	}
-
-      if (load_via_target)
+      exec_bfd = openp_bfd (getenv ("PATH"),
+			    OPF_TRY_CWD_FIRST | OPF_BFD_CANONICAL, filename);
+#if defined(__GO32__) || defined(_WIN32) || defined(__CYGWIN__)
+      if (exec_bfd == NULL)
 	{
-	  /* gdb_bfd_fopen does not support "target:" filenames.  */
-	  if (write_files)
-	    warning (_("writing into executable files is "
-		       "not supported for %s sysroots"),
-		     TARGET_SYSROOT_PREFIX);
-
-	  scratch_pathname = xstrdup (filename);
-	  make_cleanup (xfree, scratch_pathname);
+	  char *exename = alloca (strlen (filename) + 5);
 
-	  scratch_chan = -1;
-
-	  canonical_pathname = scratch_pathname;
+	  strcat (strcpy (exename, filename), ".exe");
+	  exec_bfd = openp_bfd (getenv ("PATH"),
+				OPF_TRY_CWD_FIRST | OPF_BFD_CANONICAL, exename);
 	}
-      else
-	{
-	  scratch_chan = openp (getenv ("PATH"),
-				OPF_TRY_CWD_FIRST | OPF_OPEN_RW_TMP,
-				filename, &scratch_pathname);
-#if defined(__GO32__) || defined(_WIN32) || defined(__CYGWIN__)
-	  if (scratch_chan < 0)
-	    {
-	      char *exename = alloca (strlen (filename) + 5);
-
-	      strcat (strcpy (exename, filename), ".exe");
-	      scratch_chan = openp (getenv ("PATH"),
-	                            OPF_TRY_CWD_FIRST | OPF_OPEN_RW_TMP,
-				    exename, &scratch_pathname);
-	    }
 #endif
-	  if (scratch_chan < 0)
-	    perror_with_name (filename);
-
-	  make_cleanup (xfree, scratch_pathname);
-
-	  /* gdb_bfd_open (and its variants) prefers canonicalized
-	     pathname for better BFD caching.  */
-	  canonical_pathname = gdb_realpath (scratch_pathname);
-	  make_cleanup (xfree, canonical_pathname);
-	}
-
-      if (write_files && !load_via_target)
-	exec_bfd = gdb_bfd_fopen (canonical_pathname, gnutarget,
-				  FOPEN_RUB, scratch_chan);
-      else
-	exec_bfd = gdb_bfd_open (canonical_pathname, gnutarget, scratch_chan);
-
-      if (!exec_bfd)
-	{
-	  error (_("\"%s\": could not open as an executable file: %s."),
-		 scratch_pathname, bfd_errmsg (bfd_get_error ()));
-	}
+      if (exec_bfd == NULL)
+	error (_("\"%s\": could not open as an executable file: %s."),
+	       filename, bfd_errmsg (bfd_get_error ()));
 
       /* gdb_realpath_keepfile resolves symlinks on the local
 	 filesystem and so cannot be used for "target:" files.  */
       gdb_assert (exec_filename == NULL);
-      if (load_via_target)
+      if (is_target_filename (filename))
 	exec_filename = xstrdup (bfd_get_filename (exec_bfd));
       else
-	exec_filename = gdb_realpath_keepfile (scratch_pathname);
+	{
+	  char *abspath = gdb_abspath (filename);
+
+	  exec_filename = gdb_realpath_keepfile (abspath);
+	  xfree (abspath);
+	}
 
       if (!bfd_check_format_matches (exec_bfd, bfd_object, &matching))
 	{
@@ -298,7 +254,7 @@ exec_file_attach (const char *filename, int from_tty)
 	     it.  */
 	  exec_close ();
 	  error (_("\"%s\": not in executable format: %s"),
-		 scratch_pathname,
+		 filename,
 		 gdb_bfd_errmsg (bfd_get_error (), matching));
 	}
 
@@ -308,7 +264,7 @@ exec_file_attach (const char *filename, int from_tty)
 	     it.  */
 	  exec_close ();
 	  error (_("\"%s\": can't find the file sections: %s"),
-		 scratch_pathname, bfd_errmsg (bfd_get_error ()));
+		 filename, bfd_errmsg (bfd_get_error ()));
 	}
 
       exec_bfd_mtime = bfd_get_mtime (exec_bfd);
diff --git a/gdb/source.c b/gdb/source.c
index d06cc84..029c3b5 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -868,8 +868,21 @@ file_location_from_filename (const char *filename, enum openp_flags opts)
     {
       if (write_files)
 	file.abfd = gdb_bfd_fopen (filename, gnutarget, FOPEN_RUB, file.fd);
-      else
+      else if ((opts & OPF_BFD_CANONICAL) == 0)
 	file.abfd = gdb_bfd_open (filename, gnutarget, file.fd);
+      else
+	{
+	  char *canonical;
+
+	  /* gdb_bfd_open (and its variants) prefers canonicalized
+	     pathname for better BFD caching.  */
+	  struct cleanup *canonical_cleanup;
+
+	  canonical = gdb_realpath (filename);
+	  canonical_cleanup = make_cleanup (xfree, canonical);
+	  file.abfd = gdb_bfd_open (canonical, gnutarget, file.fd);
+	  do_cleanups (canonical_cleanup);
+	}
       if ((opts & OPF_IS_BFD) != 0)
 	file.fd = -1;
       else
@@ -944,35 +957,79 @@ filename_to_bfd (const char *filename)
 							    OPF_IS_BFD));
 }
 
-/* Open a file named STRING, searching path PATH (dir names sep by some char).
-   You cannot use this function to create files.
-
-   OPTS specifies the function behaviour in specific cases.
+/* Wrapper of openp_file returning filename string.
 
-   FILENAME_OPENED must be non-null.  Set it to a newly allocated string naming
-   the actual file opened (this string will always start with a "/").  We
-   have to take special pains to avoid doubling the "/" between the directory
-   and the file, sigh!  Emacs gets confuzzed by this when we print the
-   source file name!!! 
+   FILENAME_OPENED must be non-null.  It is set to
+   file_location.filename returned from openp_file.
 
    If a file is found, return the descriptor.
    Otherwise, return -1, with errno set for the last name we tried to open.  */
 
-/*  >>>> This should only allow files of certain types,
-    >>>>  eg executable, non-directory.  */
 int
 openp (const char *path, enum openp_flags opts, const char *string,
        char **filename_opened)
 {
+  struct file_location file;
+  int retval;
+
+  gdb_assert ((opts & OPF_IS_BFD) == 0);
+
+  file = openp_file (path, opts, string);
+  gdb_assert (file.abfd == NULL);
+  if (file.fd == -1)
+    {
+      int save_errno = file.file_errno;
+
+      gdb_assert (file.filename == NULL);
+      file_location_free (&file);
+      *filename_opened = NULL;
+      errno = save_errno;
+      return -1;
+    }
+  gdb_assert (file.filename != NULL);
+  *filename_opened = xstrdup (file.filename);
+  retval = file.fd;
+  file.fd = -1;
+  file_location_free (&file);
+  return retval;
+}
+
+/* Wrapper of openp_file returning bfd *.  See file_location_to_bfd how
+   the function behaves in the case of failure.  */
+
+bfd *
+openp_bfd (const char *path, enum openp_flags opts, const char *string)
+{
+  gdb_assert ((opts & OPF_IS_BFD) == 0);
+
+  return file_location_to_bfd (openp_file (path, opts | OPF_IS_BFD, string));
+}
+
+/* Open a file named STRING, searching path PATH (dir names sep by some char).
+   You cannot use this function to create files.
+
+   OPTS specifies the function behaviour in specific cases.
+
+   Call file_location_is_valid on returned file_location to check
+   whether this function has succeeded.  */
+
+/*  >>>> This should only allow files of certain types,
+    >>>>  eg executable, non-directory.  */
+
+struct file_location
+openp_file (const char *path, enum openp_flags opts, const char *string)
+{
   int fd;
   char *filename;
   int alloclen;
   VEC (char_ptr) *dir_vec;
   struct cleanup *back_to;
-  int ix, mode;
+  int ix;
   char *dir;
+  struct file_location file;
 
   gdb_assert (string != NULL);
+  gdb_assert ((opts & (OPF_IS_BFD | OPF_BFD_CANONICAL)) != OPF_BFD_CANONICAL);
 
   /* A file with an empty name cannot possibly exist.  Report a failure
      without further checking.
@@ -983,16 +1040,13 @@ openp (const char *path, enum openp_flags opts, const char *string,
      when the debugger is started with an empty argument.  */
   if (string[0] == '\0')
     {
-      errno = ENOENT;
-      return -1;
+      file_location_enoent (&file);
+      return file;
     }
 
   if (!path)
     path = ".";
 
-  mode = (O_BINARY | (((opts & OPF_OPEN_RW_TMP) && write_files)
-		      ? O_RDWR : O_RDONLY));
-
   if ((opts & OPF_TRY_CWD_FIRST) || IS_ABSOLUTE_PATH (string))
     {
       int i;
@@ -1001,20 +1055,19 @@ openp (const char *path, enum openp_flags opts, const char *string,
 	{
 	  filename = alloca (strlen (string) + 1);
 	  strcpy (filename, string);
-	  fd = gdb_open_cloexec (filename, mode, 0);
-	  if (fd >= 0)
-	    goto done;
-	}
-      else
-	{
-	  filename = NULL;
-	  fd = -1;
+	  file = file_location_from_filename (filename, opts);
+	  if (file_location_is_valid (&file))
+	    return file;
+	  file_location_free (&file);
 	}
 
       if (!(opts & OPF_SEARCH_IN_PATH))
 	for (i = 0; string[i]; i++)
 	  if (IS_DIR_SEPARATOR (string[i]))
-	    goto done;
+	    {
+	      file_location_enoent (&file);
+	      return file;
+	    }
     }
 
   /* For dos paths, d:/foo -> /foo, and d:foo -> foo.  */
@@ -1033,7 +1086,7 @@ openp (const char *path, enum openp_flags opts, const char *string,
   filename = alloca (alloclen);
   fd = -1;
 
-  dir_vec = dirnames_to_char_ptr_vec (path);
+  dir_vec = dirnames_to_char_ptr_vec_target_exc (path);
   back_to = make_cleanup_free_char_ptr_vec (dir_vec);
 
   for (ix = 0; VEC_iterate (char_ptr, dir_vec, ix, dir); ++ix)
@@ -1097,23 +1150,22 @@ openp (const char *path, enum openp_flags opts, const char *string,
       strcat (filename + len, SLASH_STRING);
       strcat (filename, string);
 
-      if (is_regular_file (filename))
+      if (is_target_filename (filename) || is_regular_file (filename))
 	{
-	  fd = gdb_open_cloexec (filename, mode, 0);
-	  if (fd >= 0)
-	    break;
+	  file = file_location_from_filename (filename, opts);
+	  if (file_location_is_valid (&file))
+	    {
+	      do_cleanups (back_to);
+	      return file;
+	    }
+	  file_location_free (&file);
 	}
     }
 
   do_cleanups (back_to);
 
-done:
-  if (fd < 0)
-    *filename_opened = NULL;
-  else
-    *filename_opened = xstrdup (filename);
-
-  return fd;
+  file_location_enoent (&file);
+  return file;
 }
 
 
