diff --git a/gdb/inf-child.c b/gdb/inf-child.c
index a712613f08..58ce3385b2 100644
--- a/gdb/inf-child.c
+++ b/gdb/inf-child.c
@@ -333,7 +333,7 @@ inf_child_fileio_unlink (struct target_ops *self,
 
 /* Implementation of to_fileio_readlink.  */
 
-static char *
+static gdb::unique_xmalloc_ptr<char>
 inf_child_fileio_readlink (struct target_ops *self,
 			   struct inferior *inf, const char *filename,
 			   int *target_errno)
@@ -355,7 +355,7 @@ inf_child_fileio_readlink (struct target_ops *self,
   ret = (char *) xmalloc (len + 1);
   memcpy (ret, buf, len);
   ret[len] = '\0';
-  return ret;
+  return gdb::unique_xmalloc_ptr<char> (ret);
 #else
   *target_errno = FILEIO_ENOSYS;
   return NULL;
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index a6395f4b5e..d11e44e568 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4754,7 +4754,7 @@ linux_nat_fileio_open (struct target_ops *self,
 
 /* Implementation of to_fileio_readlink.  */
 
-static char *
+static gdb::unique_xmalloc_ptr<char>
 linux_nat_fileio_readlink (struct target_ops *self,
 			   struct inferior *inf, const char *filename,
 			   int *target_errno)
@@ -4774,7 +4774,7 @@ linux_nat_fileio_readlink (struct target_ops *self,
   ret = (char *) xmalloc (len + 1);
   memcpy (ret, buf, len);
   ret[len] = '\0';
-  return ret;
+  return gdb::unique_xmalloc_ptr<char> (ret);
 }
 
 /* Implementation of to_fileio_unlink.  */
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 24237b8d39..ce7d6a09d0 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -759,26 +759,20 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
   if (cwd_f)
     {
       xsnprintf (filename, sizeof filename, "/proc/%ld/cwd", pid);
-      data = target_fileio_readlink (NULL, filename, &target_errno);
-      if (data)
-	{
-	  struct cleanup *cleanup = make_cleanup (xfree, data);
-          printf_filtered ("cwd = '%s'\n", data);
-	  do_cleanups (cleanup);
-	}
+      gdb::unique_xmalloc_ptr<char> contents
+	= target_fileio_readlink (NULL, filename, &target_errno);
+      if (contents)
+	printf_filtered ("cwd = '%s'\n", contents.get ());
       else
 	warning (_("unable to read link '%s'"), filename);
     }
   if (exe_f)
     {
       xsnprintf (filename, sizeof filename, "/proc/%ld/exe", pid);
-      data = target_fileio_readlink (NULL, filename, &target_errno);
-      if (data)
-	{
-	  struct cleanup *cleanup = make_cleanup (xfree, data);
-          printf_filtered ("exe = '%s'\n", data);
-	  do_cleanups (cleanup);
-	}
+      gdb::unique_xmalloc_ptr<char> contents
+	= target_fileio_readlink (NULL, filename, &target_errno);
+      if (contents)
+	printf_filtered ("exe = '%s'\n", contents.get ());
       else
 	warning (_("unable to read link '%s'"), filename);
     }
diff --git a/gdb/remote.c b/gdb/remote.c
index 62ac055119..3434af6f3c 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -11767,7 +11767,7 @@ remote_hostio_unlink (struct target_ops *self,
 
 /* Implementation of to_fileio_readlink.  */
 
-static char *
+static gdb::unique_xmalloc_ptr<char>
 remote_hostio_readlink (struct target_ops *self,
 			struct inferior *inf, const char *filename,
 			int *remote_errno)
@@ -11803,7 +11803,7 @@ remote_hostio_readlink (struct target_ops *self,
     error (_("Readlink returned %d, but %d bytes."), len, read_len);
 
   ret[len] = '\0';
-  return ret;
+  return gdb::unique_xmalloc_ptr<char> (ret);
 }
 
 /* Implementation of to_fileio_fstat.  */
diff --git a/gdb/target.c b/gdb/target.c
index 2e02a774e6..ae77ce9b76 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -2963,7 +2963,7 @@ target_fileio_unlink (struct inferior *inf, const char *filename,
 
 /* See target.h.  */
 
-char *
+gdb::unique_xmalloc_ptr<char>
 target_fileio_readlink (struct inferior *inf, const char *filename,
 			int *target_errno)
 {
@@ -2973,16 +2973,16 @@ target_fileio_readlink (struct inferior *inf, const char *filename,
     {
       if (t->to_fileio_readlink != NULL)
 	{
-	  char *ret = t->to_fileio_readlink (t, inf, filename,
-					     target_errno);
+	  gdb::unique_xmalloc_ptr<char> ret
+	    = t->to_fileio_readlink (t, inf, filename, target_errno);
 
 	  if (targetdebug)
 	    fprintf_unfiltered (gdb_stdlog,
 				"target_fileio_readlink (%d,%s)"
 				" = %s (%d)\n",
 				inf == NULL ? 0 : inf->num,
-				filename, ret? ret : "(nil)",
-				ret? 0 : *target_errno);
+				filename, ret ? ret.get () : "(nil)",
+				ret ? 0 : *target_errno);
 	  return ret;
 	}
     }
diff --git a/gdb/target.h b/gdb/target.h
index 1683af64d5..7e3c58b5e0 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -946,10 +946,10 @@ struct target_ops
        seen by the debugger (GDB or, for remote targets, the remote
        stub).  Return a null-terminated string allocated via xmalloc,
        or NULL if an error occurs (and set *TARGET_ERRNO).  */
-    char *(*to_fileio_readlink) (struct target_ops *,
-				 struct inferior *inf,
-				 const char *filename,
-				 int *target_errno);
+    gdb::unique_xmalloc_ptr<char> (*to_fileio_readlink) (struct target_ops *,
+							 struct inferior *inf,
+							 const char *filename,
+							 int *target_errno);
 
 
     /* Implement the "info proc" command.  */
@@ -2109,9 +2109,8 @@ extern int target_fileio_unlink (struct inferior *inf,
    by the debugger (GDB or, for remote targets, the remote stub).
    Return a null-terminated string allocated via xmalloc, or NULL if
    an error occurs (and set *TARGET_ERRNO).  */
-extern char *target_fileio_readlink (struct inferior *inf,
-				     const char *filename,
-				     int *target_errno);
+extern gdb::unique_xmalloc_ptr<char> target_fileio_readlink
+    (struct inferior *inf, const char *filename, int *target_errno);
 
 /* Read target file FILENAME, in the filesystem as seen by INF.  If
    INF is NULL, use the filesystem seen by the debugger (GDB or, for
