[RFA,5/6] Return unique_xmalloc_ptr from target_read_stralloc

Message ID 20171016030427.21349-6-tom@tromey.com
State New, archived
Headers

Commit Message

Tom Tromey Oct. 16, 2017, 3:04 a.m. UTC
  This changes target_read_stralloc to return a unique_xmalloc_ptr, and
then fixes all the callers.  unique_xmalloc_ptr is used, rather than
std::string, because target_read_stralloc gives a special meaning to a
NULL return.

ChangeLog
2017-10-15  Tom Tromey  <tom@tromey.com>

	* xml-syscall.c (xml_init_syscalls_info): Update.
	* xml-support.c (xinclude_start_include): Update.
	(xml_fetch_content_from_file): Return unique_xmalloc_ptr.
	* xml-support.h (xml_fetch_another): Return unique_xmalloc_ptr.
	(xml_fetch_content_from_file): Likewise.
	* osdata.c (get_osdata): Update.
	* target.h (target_read_stralloc, target_get_osdata): Return
	unique_xmalloc_ptr.
	* solib-aix.c (solib_aix_get_library_list): Update.
	* solib-target.c (solib_target_current_sos): Update.
	* solib-svr4.c (svr4_current_sos_via_xfer_libraries): Update.
	* xml-tdesc.c (fetch_available_features_from_target): Update.
	(target_fetch_description_xml): Update.
	(file_read_description_xml): Update.
	* remote.c (remote_get_threads_with_qxfer, remote_memory_map)
	(remote_traceframe_info, btrace_read_config, remote_read_btrace)
	(remote_pid_to_exec_file): Update.
	* target.c (target_read_stralloc): Return unique_xmalloc_ptr.
	(target_get_osdata): Likewise.
---
 gdb/ChangeLog      | 22 +++++++++++++++++++
 gdb/osdata.c       | 10 +++------
 gdb/remote.c       | 64 +++++++++++++++---------------------------------------
 gdb/solib-aix.c    | 15 +++++--------
 gdb/solib-svr4.c   | 16 ++++----------
 gdb/solib-target.c | 15 +++----------
 gdb/target.c       | 16 +++++++-------
 gdb/target.h       |  7 +++---
 gdb/xml-support.c  | 28 +++++++++---------------
 gdb/xml-support.h  |  7 +++---
 gdb/xml-syscall.c  | 18 +++++----------
 gdb/xml-tdesc.c    | 37 ++++++++++---------------------
 12 files changed, 96 insertions(+), 159 deletions(-)
  

Comments

Simon Marchi Oct. 16, 2017, 9:02 p.m. UTC | #1
On 2017-10-15 11:04 PM, Tom Tromey wrote:
> diff --git a/gdb/target.h b/gdb/target.h
> index 581c89be54..98bcd789e0 100644
> --- a/gdb/target.h
> +++ b/gdb/target.h
> @@ -358,9 +358,8 @@ extern LONGEST target_read_alloc (struct target_ops *ops,
>     are returned as allocated but empty strings.  A warning is issued
>     if the result contains any embedded NUL bytes.  */
>  
> -extern char *target_read_stralloc (struct target_ops *ops,
> -				   enum target_object object,
> -				   const char *annex);
> +extern gdb::unique_xmalloc_ptr<char> target_read_stralloc
> +    (struct target_ops *ops, enum target_object object, const char *annex);

You changed the comment above target_read_stralloc in target.c.  Can you put

  /* See target.h.  */

and update this one instead?

>  
>  /* See target_ops->to_xfer_partial.  */
>  extern target_xfer_partial_ftype target_xfer_partial;
> @@ -2401,7 +2400,7 @@ struct target_ops *find_target_at (enum strata stratum);
>     unsupported, NULL is returned.  Empty objects are returned as
>     allocated but empty strings.  */
>  
> -extern char *target_get_osdata (const char *type);
> +extern gdb::unique_xmalloc_ptr<char> target_get_osdata (const char *type);

You can update the comment of this function in the same way, and add "See target.h"
in target.c.

>  
>  
>  /* Stuff that should be shared among the various remote targets.  */
> diff --git a/gdb/xml-support.c b/gdb/xml-support.c
> index 50a062a3a4..7cecaa8d4d 100644
> --- a/gdb/xml-support.c
> +++ b/gdb/xml-support.c
> @@ -808,8 +808,7 @@ xinclude_start_include (struct gdb_xml_parser *parser,
>    struct xinclude_parsing_data *data
>      = (struct xinclude_parsing_data *) user_data;
>    char *href = (char *) xml_find_attribute (attributes, "href")->value;
> -  struct cleanup *back_to;
> -  char *text, *output;
> +  char *output;

You can remove output too.

LGTM with those fixed.

Simon
  

Patch

diff --git a/gdb/osdata.c b/gdb/osdata.c
index 9da3d07cdb..276d22427a 100644
--- a/gdb/osdata.c
+++ b/gdb/osdata.c
@@ -245,13 +245,11 @@  struct osdata *
 get_osdata (const char *type)
 {
   struct osdata *osdata = NULL;
-  char *xml = target_get_osdata (type);
+  gdb::unique_xmalloc_ptr<char> xml = target_get_osdata (type);
 
   if (xml)
     {
-      struct cleanup *old_chain = make_cleanup (xfree, xml);
-
-      if (xml[0] == '\0')
+      if (xml.get ()[0] == '\0')
 	{
 	  if (type)
 	    warning (_("Empty data returned by target.  Wrong osdata type?"));
@@ -259,9 +257,7 @@  get_osdata (const char *type)
 	    warning (_("Empty type list returned by target.  No type data?"));
 	}
       else
-	osdata = osdata_parse (xml);
-
-      do_cleanups (old_chain);
+	osdata = osdata_parse (xml.get ());
     }
 
   if (!osdata)
diff --git a/gdb/remote.c b/gdb/remote.c
index 43cc661daf..b333d76a6a 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -3203,16 +3203,15 @@  remote_get_threads_with_qxfer (struct target_ops *ops,
 #if defined(HAVE_LIBEXPAT)
   if (packet_support (PACKET_qXfer_threads) == PACKET_ENABLE)
     {
-      char *xml = target_read_stralloc (ops, TARGET_OBJECT_THREADS, NULL);
-      struct cleanup *back_to = make_cleanup (xfree, xml);
+      gdb::unique_xmalloc_ptr<char> xml
+	= target_read_stralloc (ops, TARGET_OBJECT_THREADS, NULL);
 
       if (xml != NULL && *xml != '\0')
 	{
 	  gdb_xml_parse_quick (_("threads"), "threads.dtd",
-			       threads_elements, xml, context);
+			       threads_elements, xml.get (), context);
 	}
 
-      do_cleanups (back_to);
       return 1;
     }
 #endif
@@ -10902,16 +10901,11 @@  static VEC(mem_region_s) *
 remote_memory_map (struct target_ops *ops)
 {
   VEC(mem_region_s) *result = NULL;
-  char *text = target_read_stralloc (&current_target,
-				     TARGET_OBJECT_MEMORY_MAP, NULL);
+  gdb::unique_xmalloc_ptr<char> text
+    = target_read_stralloc (&current_target, TARGET_OBJECT_MEMORY_MAP, NULL);
 
   if (text)
-    {
-      struct cleanup *back_to = make_cleanup (xfree, text);
-
-      result = parse_memory_map (text);
-      do_cleanups (back_to);
-    }
+    result = parse_memory_map (text.get ());
 
   return result;
 }
@@ -13049,18 +13043,11 @@  remote_set_circular_trace_buffer (struct target_ops *self, int val)
 static traceframe_info_up
 remote_traceframe_info (struct target_ops *self)
 {
-  char *text;
-
-  text = target_read_stralloc (&current_target,
-			       TARGET_OBJECT_TRACEFRAME_INFO, NULL);
+  gdb::unique_xmalloc_ptr<char> text
+    = target_read_stralloc (&current_target, TARGET_OBJECT_TRACEFRAME_INFO,
+			    NULL);
   if (text != NULL)
-    {
-      struct cleanup *back_to = make_cleanup (xfree, text);
-      traceframe_info_up info = parse_traceframe_info (text);
-
-      do_cleanups (back_to);
-      return info;
-    }
+    return parse_traceframe_info (text.get ());
 
   return NULL;
 }
@@ -13319,18 +13306,10 @@  btrace_sync_conf (const struct btrace_config *conf)
 static void
 btrace_read_config (struct btrace_config *conf)
 {
-  char *xml;
-
-  xml = target_read_stralloc (&current_target,
-			      TARGET_OBJECT_BTRACE_CONF, "");
+  gdb::unique_xmalloc_ptr<char> xml
+    = target_read_stralloc (&current_target, TARGET_OBJECT_BTRACE_CONF, "");
   if (xml != NULL)
-    {
-      struct cleanup *cleanup;
-
-      cleanup = make_cleanup (xfree, xml);
-      parse_xml_btrace_conf (conf, xml);
-      do_cleanups (cleanup);
-    }
+    parse_xml_btrace_conf (conf, xml.get ());
 }
 
 /* Maybe reopen target btrace.  */
@@ -13501,9 +13480,7 @@  remote_read_btrace (struct target_ops *self,
 		    enum btrace_read_type type)
 {
   struct packet_config *packet = &remote_protocol_packets[PACKET_qXfer_btrace];
-  struct cleanup *cleanup;
   const char *annex;
-  char *xml;
 
   if (packet_config_support (packet) != PACKET_ENABLE)
     error (_("Target does not support branch tracing."));
@@ -13529,14 +13506,12 @@  remote_read_btrace (struct target_ops *self,
 		      (unsigned int) type);
     }
 
-  xml = target_read_stralloc (&current_target,
-			      TARGET_OBJECT_BTRACE, annex);
+  gdb::unique_xmalloc_ptr<char> xml
+    = target_read_stralloc (&current_target, TARGET_OBJECT_BTRACE, annex);
   if (xml == NULL)
     return BTRACE_ERR_UNKNOWN;
 
-  cleanup = make_cleanup (xfree, xml);
-  parse_xml_btrace (btrace, xml);
-  do_cleanups (cleanup);
+  parse_xml_btrace (btrace, xml.get ());
 
   return BTRACE_ERR_NONE;
 }
@@ -13570,16 +13545,13 @@  remote_load (struct target_ops *self, const char *name, int from_tty)
 static char *
 remote_pid_to_exec_file (struct target_ops *self, int pid)
 {
-  static char *filename = NULL;
+  static gdb::unique_xmalloc_ptr<char> filename;
   struct inferior *inf;
   char *annex = NULL;
 
   if (packet_support (PACKET_qXfer_exec_file) != PACKET_ENABLE)
     return NULL;
 
-  if (filename != NULL)
-    xfree (filename);
-
   inf = find_inferior_pid (pid);
   if (inf == NULL)
     internal_error (__FILE__, __LINE__,
@@ -13596,7 +13568,7 @@  remote_pid_to_exec_file (struct target_ops *self, int pid)
   filename = target_read_stralloc (&current_target,
 				   TARGET_OBJECT_EXEC_FILE, annex);
 
-  return filename;
+  return filename.get ();
 }
 
 /* Implement the to_can_do_single_step target_ops method.  */
diff --git a/gdb/solib-aix.c b/gdb/solib-aix.c
index 9233e7815c..de238e597b 100644
--- a/gdb/solib-aix.c
+++ b/gdb/solib-aix.c
@@ -271,39 +271,34 @@  static VEC (lm_info_aix_p) *
 solib_aix_get_library_list (struct inferior *inf, const char *warning_msg)
 {
   struct solib_aix_inferior_data *data;
-  char *library_document;
-  struct cleanup *cleanup;
 
   /* If already computed, return the cached value.  */
   data = get_solib_aix_inferior_data (inf);
   if (data->library_list != NULL)
     return data->library_list;
 
-  library_document = target_read_stralloc (&current_target,
-                                           TARGET_OBJECT_LIBRARIES_AIX,
-                                           NULL);
+  gdb::unique_xmalloc_ptr<char> library_document
+    = target_read_stralloc (&current_target, TARGET_OBJECT_LIBRARIES_AIX,
+			    NULL);
   if (library_document == NULL && warning_msg != NULL)
     {
       warning (_("%s (failed to read TARGET_OBJECT_LIBRARIES_AIX)"),
 	       warning_msg);
       return NULL;
     }
-  cleanup = make_cleanup (xfree, library_document);
 
   if (solib_aix_debug)
     fprintf_unfiltered (gdb_stdlog,
 			"DEBUG: TARGET_OBJECT_LIBRARIES_AIX = \n%s\n",
-			library_document);
+			library_document.get ());
 
-  data->library_list = solib_aix_parse_libraries (library_document);
+  data->library_list = solib_aix_parse_libraries (library_document.get ());
   if (data->library_list == NULL && warning_msg != NULL)
     {
       warning (_("%s (missing XML support?)"), warning_msg);
-      do_cleanups (cleanup);
       return NULL;
     }
 
-  do_cleanups (cleanup);
   return data->library_list;
 }
 
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index d33479128e..bf2577a433 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -1269,24 +1269,16 @@  static int
 svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
 				     const char *annex)
 {
-  char *svr4_library_document;
-  int result;
-  struct cleanup *back_to;
-
   gdb_assert (annex == NULL || target_augmented_libraries_svr4_read ());
 
   /* Fetch the list of shared libraries.  */
-  svr4_library_document = target_read_stralloc (&current_target,
-						TARGET_OBJECT_LIBRARIES_SVR4,
-						annex);
+  gdb::unique_xmalloc_ptr<char> svr4_library_document
+    = target_read_stralloc (&current_target, TARGET_OBJECT_LIBRARIES_SVR4,
+			    annex);
   if (svr4_library_document == NULL)
     return 0;
 
-  back_to = make_cleanup (xfree, svr4_library_document);
-  result = svr4_parse_libraries (svr4_library_document, list);
-  do_cleanups (back_to);
-
-  return result;
+  return svr4_parse_libraries (svr4_library_document.get (), list);
 }
 
 #else
diff --git a/gdb/solib-target.c b/gdb/solib-target.c
index cf569ec3e6..01171f85dd 100644
--- a/gdb/solib-target.c
+++ b/gdb/solib-target.c
@@ -248,27 +248,18 @@  static struct so_list *
 solib_target_current_sos (void)
 {
   struct so_list *new_solib, *start = NULL, *last = NULL;
-  char *library_document;
-  struct cleanup *old_chain;
   VEC(lm_info_target_p) *library_list;
   lm_info_target *info;
   int ix;
 
   /* Fetch the list of shared libraries.  */
-  library_document = target_read_stralloc (&current_target,
-					   TARGET_OBJECT_LIBRARIES,
-					   NULL);
+  gdb::unique_xmalloc_ptr<char> library_document
+    = target_read_stralloc (&current_target, TARGET_OBJECT_LIBRARIES, NULL);
   if (library_document == NULL)
     return NULL;
 
-  /* solib_target_parse_libraries may throw, so we use a cleanup.  */
-  old_chain = make_cleanup (xfree, library_document);
-
   /* Parse the list.  */
-  library_list = solib_target_parse_libraries (library_document);
-
-  /* library_document string is not needed behind this point.  */
-  do_cleanups (old_chain);
+  library_list = solib_target_parse_libraries (library_document.get ());
 
   if (library_list == NULL)
     return NULL;
diff --git a/gdb/target.c b/gdb/target.c
index 4a7589d445..9d65b496f1 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -1925,12 +1925,12 @@  target_read_alloc (struct target_ops *ops, enum target_object object,
 }
 
 /* Read OBJECT/ANNEX using OPS.  The result is NUL-terminated and
-   returned as a string, allocated using xmalloc.  If an error occurs
-   or the transfer is unsupported, NULL is returned.  Empty objects
-   are returned as allocated but empty strings.  A warning is issued
-   if the result contains any embedded NUL bytes.  */
+   returned as a string.  If an error occurs or the transfer is
+   unsupported, NULL is returned.  Empty objects are returned as
+   allocated but empty strings.  A warning is issued if the result
+   contains any embedded NUL bytes.  */
 
-char *
+gdb::unique_xmalloc_ptr<char>
 target_read_stralloc (struct target_ops *ops, enum target_object object,
 		      const char *annex)
 {
@@ -1945,7 +1945,7 @@  target_read_stralloc (struct target_ops *ops, enum target_object object,
     return NULL;
 
   if (transferred == 0)
-    return xstrdup ("");
+    return gdb::unique_xmalloc_ptr<char> (xstrdup (""));
 
   bufstr[transferred] = 0;
 
@@ -1959,7 +1959,7 @@  target_read_stralloc (struct target_ops *ops, enum target_object object,
 	break;
       }
 
-  return bufstr;
+  return gdb::unique_xmalloc_ptr<char> (bufstr);
 }
 
 /* Memory transfer methods.  */
@@ -2654,7 +2654,7 @@  target_supports_multi_process (void)
   return (*current_target.to_supports_multi_process) (&current_target);
 }
 
-char *
+gdb::unique_xmalloc_ptr<char>
 target_get_osdata (const char *type)
 {
   struct target_ops *t;
diff --git a/gdb/target.h b/gdb/target.h
index 581c89be54..98bcd789e0 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -358,9 +358,8 @@  extern LONGEST target_read_alloc (struct target_ops *ops,
    are returned as allocated but empty strings.  A warning is issued
    if the result contains any embedded NUL bytes.  */
 
-extern char *target_read_stralloc (struct target_ops *ops,
-				   enum target_object object,
-				   const char *annex);
+extern gdb::unique_xmalloc_ptr<char> target_read_stralloc
+    (struct target_ops *ops, enum target_object object, const char *annex);
 
 /* See target_ops->to_xfer_partial.  */
 extern target_xfer_partial_ftype target_xfer_partial;
@@ -2401,7 +2400,7 @@  struct target_ops *find_target_at (enum strata stratum);
    unsupported, NULL is returned.  Empty objects are returned as
    allocated but empty strings.  */
 
-extern char *target_get_osdata (const char *type);
+extern gdb::unique_xmalloc_ptr<char> target_get_osdata (const char *type);
 
 
 /* Stuff that should be shared among the various remote targets.  */
diff --git a/gdb/xml-support.c b/gdb/xml-support.c
index 50a062a3a4..7cecaa8d4d 100644
--- a/gdb/xml-support.c
+++ b/gdb/xml-support.c
@@ -808,8 +808,7 @@  xinclude_start_include (struct gdb_xml_parser *parser,
   struct xinclude_parsing_data *data
     = (struct xinclude_parsing_data *) user_data;
   char *href = (char *) xml_find_attribute (attributes, "href")->value;
-  struct cleanup *back_to;
-  char *text, *output;
+  char *output;
 
   gdb_xml_debug (parser, _("Processing XInclude of \"%s\""), href);
 
@@ -817,19 +816,17 @@  xinclude_start_include (struct gdb_xml_parser *parser,
     gdb_xml_error (parser, _("Maximum XInclude depth (%d) exceeded"),
 		   MAX_XINCLUDE_DEPTH);
 
-  text = data->fetcher (href, data->fetcher_baton);
+  gdb::unique_xmalloc_ptr<char> text = data->fetcher (href,
+						      data->fetcher_baton);
   if (text == NULL)
     gdb_xml_error (parser, _("Could not load XML document \"%s\""), href);
-  back_to = make_cleanup (xfree, text);
 
   if (!xml_process_xincludes (data->output, parser->name (),
-			      text, data->fetcher,
+			      text.get (), data->fetcher,
 			      data->fetcher_baton,
 			      data->include_depth + 1))
     gdb_xml_error (parser, _("Parsing \"%s\" failed"), href);
 
-  do_cleanups (back_to);
-
   data->skip_depth++;
 }
 
@@ -997,13 +994,11 @@  show_debug_xml (struct ui_file *file, int from_tty,
   fprintf_filtered (file, _("XML debugging is %s.\n"), value);
 }
 
-char *
+gdb::unique_xmalloc_ptr<char>
 xml_fetch_content_from_file (const char *filename, void *baton)
 {
   const char *dirname = (const char *) baton;
   gdb_file_up file;
-  struct cleanup *back_to;
-  char *text;
   size_t len, offset;
 
   if (dirname && *dirname)
@@ -1024,19 +1019,18 @@  xml_fetch_content_from_file (const char *filename, void *baton)
   /* Read in the whole file, one chunk at a time.  */
   len = 4096;
   offset = 0;
-  text = (char *) xmalloc (len);
-  back_to = make_cleanup (free_current_contents, &text);
+  gdb::unique_xmalloc_ptr<char> text ((char *) xmalloc (len));
   while (1)
     {
       size_t bytes_read;
 
       /* Continue reading where the last read left off.  Leave at least
 	 one byte so that we can NUL-terminate the result.  */
-      bytes_read = fread (text + offset, 1, len - offset - 1, file.get ());
+      bytes_read = fread (text.get () + offset, 1, len - offset - 1,
+			  file.get ());
       if (ferror (file.get ()))
 	{
 	  warning (_("Read error from \"%s\""), filename);
-	  do_cleanups (back_to);
 	  return NULL;
 	}
 
@@ -1046,12 +1040,10 @@  xml_fetch_content_from_file (const char *filename, void *baton)
 	break;
 
       len = len * 2;
-      text = (char *) xrealloc (text, len);
+      text.reset ((char *) xrealloc (text.get (), len));
     }
 
-  discard_cleanups (back_to);
-
-  text[offset] = '\0';
+  text.get ()[offset] = '\0';
   return text;
 }
 
diff --git a/gdb/xml-support.h b/gdb/xml-support.h
index 1a1b7fd0e7..74bc8117c0 100644
--- a/gdb/xml-support.h
+++ b/gdb/xml-support.h
@@ -52,7 +52,8 @@  extern const char *xml_builtin[][2];
 
 /* Callback to fetch a new XML file, based on the provided HREF.  */
 
-typedef char *(*xml_fetch_another) (const char *href, void *baton);
+typedef gdb::unique_xmalloc_ptr<char> (*xml_fetch_another) (const char *href,
+							    void *baton);
 
 /* Append the expansion of TEXT after processing <xi:include> tags in
    RESULT.  FETCHER will be called (with FETCHER_BATON) to retrieve
@@ -230,7 +231,7 @@  ULONGEST gdb_xml_parse_ulongest (struct gdb_xml_parser *parser,
 /* Open FILENAME, read all its text into memory, close it, and return
    the text.  If something goes wrong, return NULL and warn.  */
 
-extern char *xml_fetch_content_from_file (const char *filename,
-                                          void *baton);
+extern gdb::unique_xmalloc_ptr<char> xml_fetch_content_from_file
+    (const char *filename, void *baton);
 
 #endif
diff --git a/gdb/xml-syscall.c b/gdb/xml-syscall.c
index a43641893a..fe036cbf5c 100644
--- a/gdb/xml-syscall.c
+++ b/gdb/xml-syscall.c
@@ -362,22 +362,14 @@  syscall_parse_xml (const char *document, xml_fetch_another fetcher,
 static struct syscalls_info *
 xml_init_syscalls_info (const char *filename)
 {
-  char *full_file;
-  struct syscalls_info *syscalls_info;
-  struct cleanup *back_to;
-
-  full_file = xml_fetch_content_from_file (filename, gdb_datadir);
+  gdb::unique_xmalloc_ptr<char> full_file
+    = xml_fetch_content_from_file (filename, gdb_datadir);
   if (full_file == NULL)
     return NULL;
 
-  back_to = make_cleanup (xfree, full_file);
-
-  syscalls_info = syscall_parse_xml (full_file,
-				     xml_fetch_content_from_file,
-				     (void *) ldirname (filename).c_str ());
-  do_cleanups (back_to);
-
-  return syscalls_info;
+  return syscall_parse_xml (full_file.get (),
+			    xml_fetch_content_from_file,
+			    (void *) ldirname (filename).c_str ());
 }
 
 /* Initializes the syscalls_info structure according to the
diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c
index daa713f13f..5a1f459f98 100644
--- a/gdb/xml-tdesc.c
+++ b/gdb/xml-tdesc.c
@@ -673,24 +673,16 @@  tdesc_parse_xml (const char *document, xml_fetch_another fetcher,
 const struct target_desc *
 file_read_description_xml (const char *filename)
 {
-  struct target_desc *tdesc;
-  char *tdesc_str;
-  struct cleanup *back_to;
-
-  tdesc_str = xml_fetch_content_from_file (filename, NULL);
+  gdb::unique_xmalloc_ptr<char> tdesc_str
+    = xml_fetch_content_from_file (filename, NULL);
   if (tdesc_str == NULL)
     {
       warning (_("Could not open \"%s\""), filename);
       return NULL;
     }
 
-  back_to = make_cleanup (xfree, tdesc_str);
-
-  tdesc = tdesc_parse_xml (tdesc_str, xml_fetch_content_from_file,
-			   (void *) ldirname (filename).c_str ());
-  do_cleanups (back_to);
-
-  return tdesc;
+  return tdesc_parse_xml (tdesc_str.get (), xml_fetch_content_from_file,
+			  (void *) ldirname (filename).c_str ());
 }
 
 /* Read a string representation of available features from the target,
@@ -700,7 +692,7 @@  file_read_description_xml (const char *filename)
    is "target.xml".  Other calls may be performed for the DTD or
    for <xi:include>.  */
 
-static char *
+static gdb::unique_xmalloc_ptr<char>
 fetch_available_features_from_target (const char *name, void *baton_)
 {
   struct target_ops *ops = (struct target_ops *) baton_;
@@ -719,21 +711,14 @@  fetch_available_features_from_target (const char *name, void *baton_)
 const struct target_desc *
 target_read_description_xml (struct target_ops *ops)
 {
-  struct target_desc *tdesc;
-  char *tdesc_str;
-  struct cleanup *back_to;
-
-  tdesc_str = fetch_available_features_from_target ("target.xml", ops);
+  gdb::unique_xmalloc_ptr<char> tdesc_str
+    = fetch_available_features_from_target ("target.xml", ops);
   if (tdesc_str == NULL)
     return NULL;
 
-  back_to = make_cleanup (xfree, tdesc_str);
-  tdesc = tdesc_parse_xml (tdesc_str,
-			   fetch_available_features_from_target,
-			   ops);
-  do_cleanups (back_to);
-
-  return tdesc;
+  return tdesc_parse_xml (tdesc_str.get (),
+			  fetch_available_features_from_target,
+			  ops);
 }
 
 /* Fetches an XML target description using OPS,  processing
@@ -758,7 +743,7 @@  target_fetch_description_xml (struct target_ops *ops)
   struct target_desc *tdesc;
 
   gdb::unique_xmalloc_ptr<char>
-    tdesc_str (fetch_available_features_from_target ("target.xml", ops));
+    tdesc_str = fetch_available_features_from_target ("target.xml", ops);
   if (tdesc_str == NULL)
     return {};