Return unique_xmalloc_ptr from target_read_stralloc
authorTom Tromey <tom@tromey.com>
Thu, 12 Oct 2017 22:48:35 +0000 (16:48 -0600)
committerTom Tromey <tom@tromey.com>
Mon, 16 Oct 2017 22:10:21 +0000 (16:10 -0600)
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-16  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.

12 files changed:
gdb/ChangeLog
gdb/osdata.c
gdb/remote.c
gdb/solib-aix.c
gdb/solib-svr4.c
gdb/solib-target.c
gdb/target.c
gdb/target.h
gdb/xml-support.c
gdb/xml-support.h
gdb/xml-syscall.c
gdb/xml-tdesc.c

index 4b0a971fe4fa7093e6a7d190511ef79f2251c110..df30b61bfa5d5d6c4ada62b546fe4804607451e8 100644 (file)
@@ -1,3 +1,25 @@
+2017-10-16  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.
+
 2017-10-16  Tom Tromey  <tom@tromey.com>
 
        * remote.c (remote_register_number_and_offset): Use std::vector.
index 9da3d07cdb3098d42cf2cbb87f22f7ccdd0edc89..276d22427a62a908fdf1650780150425ace95e8a 100644 (file)
@@ -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)
index 070f82e18671feacb8806b2c8049736e8074f16a..9ee46450d8cc9fa7bbebd7f2da87187a43649c36 100644 (file)
@@ -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
@@ -10893,16 +10892,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;
 }
@@ -13040,18 +13034,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;
 }
@@ -13310,18 +13297,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.  */
@@ -13492,9 +13471,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."));
@@ -13520,14 +13497,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;
 }
@@ -13561,16 +13536,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__,
@@ -13587,7 +13559,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.  */
index 9233e7815cf3f9bcdd671580447dfad8cf8cffc4..de238e597bdc8f019cb9b13de03141ebc026f8f1 100644 (file)
@@ -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;
 }
 
index d33479128e99b994151552b44b6a03d4f11e531f..bf2577a43367a38ccb50050dfa716cc73914cc18 100644 (file)
@@ -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
index cf569ec3e676ce859f31dd84d2e492ee16167985..01171f85dd2eeaa341297207a1d0e268ba480f4a 100644 (file)
@@ -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;
index 4a7589d445ec4a52d6321ee21dd6dd8f740e6bc5..94307cbdc7311288bf1064d2b1ee3f096fb2bb95 100644 (file)
@@ -1924,13 +1924,9 @@ target_read_alloc (struct target_ops *ops, enum target_object object,
   return target_read_alloc_1 (ops, object, annex, buf_p, 0);
 }
 
-/* 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.  */
+/* See target.h.  */
 
-char *
+gdb::unique_xmalloc_ptr<char>
 target_read_stralloc (struct target_ops *ops, enum target_object object,
                      const char *annex)
 {
@@ -1945,7 +1941,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 +1955,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 +2650,9 @@ target_supports_multi_process (void)
   return (*current_target.to_supports_multi_process) (&current_target);
 }
 
-char *
+/* See target.h.  */
+
+gdb::unique_xmalloc_ptr<char>
 target_get_osdata (const char *type)
 {
   struct target_ops *t;
index 581c89be545ac9287299014a14527df8ef8d3ede..8cac818f5ed5f436733db536ae1184035d27b0fc 100644 (file)
@@ -353,14 +353,13 @@ extern LONGEST target_read_alloc (struct target_ops *ops,
                                  const char *annex, gdb_byte **buf_p);
 
 /* 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.  */
 
-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;
@@ -2396,12 +2395,12 @@ extern struct target_ops *find_target_beneath (struct target_ops *);
 struct target_ops *find_target_at (enum strata stratum);
 
 /* Read OS data object of type TYPE from the target, and return it in
-   XML format.  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.  */
+   XML format.  The result is NUL-terminated and 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.  */
 
-extern char *target_get_osdata (const char *type);
+extern gdb::unique_xmalloc_ptr<char> target_get_osdata (const char *type);
 
 \f
 /* Stuff that should be shared among the various remote targets.  */
index 50a062a3a47b6d189d9977c05cfc241b63c16127..76d03b90c707f15fcf43e0313bd4989758accd63 100644 (file)
@@ -808,8 +808,6 @@ 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;
 
   gdb_xml_debug (parser, _("Processing XInclude of \"%s\""), href);
 
@@ -817,19 +815,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 +993,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 +1018,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 +1039,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;
 }
 
index 1a1b7fd0e7fe8b9a0199de3f0ab9a43a04b9a080..74bc8117c0a7b01fc8ac03661221430ac18dbb14 100644 (file)
@@ -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
index a43641893a60488a5ee47f70bd537cbbc6d2a108..fe036cbf5cc5496e6bc53a1c237faa1fd9554666 100644 (file)
@@ -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
index daa713f13f16835b3c04c0448caf1e010765b318..5a1f459f980a4b31fab1bbce4f3f6654a5d15a9a 100644 (file)
@@ -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 {};