diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index 5e412315e6d..b6ee30a54bd 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -6742,38 +6742,38 @@ linux_process_target::disable_btrace (btrace_target_info *tinfo)
 /* Encode an Intel Processor Trace configuration.  */
 
 static void
-linux_low_encode_pt_config (struct buffer *buffer,
+linux_low_encode_pt_config (std::string *buffer,
 			    const struct btrace_data_pt_config *config)
 {
-  buffer_grow_str (buffer, "<pt-config>\n");
+  *buffer += "<pt-config>\n";
 
   switch (config->cpu.vendor)
     {
     case CV_INTEL:
-      buffer_xml_printf (buffer, "<cpu vendor=\"GenuineIntel\" family=\"%u\" "
-			 "model=\"%u\" stepping=\"%u\"/>\n",
-			 config->cpu.family, config->cpu.model,
-			 config->cpu.stepping);
+      string_xml_appendf (*buffer, "<cpu vendor=\"GenuineIntel\" family=\"%u\" "
+			  "model=\"%u\" stepping=\"%u\"/>\n",
+			  config->cpu.family, config->cpu.model,
+			  config->cpu.stepping);
       break;
 
     default:
       break;
     }
 
-  buffer_grow_str (buffer, "</pt-config>\n");
+  *buffer += "</pt-config>\n";
 }
 
 /* Encode a raw buffer.  */
 
 static void
-linux_low_encode_raw (struct buffer *buffer, const gdb_byte *data,
+linux_low_encode_raw (std::string *buffer, const gdb_byte *data,
 		      unsigned int size)
 {
   if (size == 0)
     return;
 
   /* We use hex encoding - see gdbsupport/rsp-low.h.  */
-  buffer_grow_str (buffer, "<raw>\n");
+  *buffer += "<raw>\n";
 
   while (size-- > 0)
     {
@@ -6782,17 +6782,17 @@ linux_low_encode_raw (struct buffer *buffer, const gdb_byte *data,
       elem[0] = tohex ((*data >> 4) & 0xf);
       elem[1] = tohex (*data++ & 0xf);
 
-      buffer_grow (buffer, elem, 2);
+      buffer->append (elem);
     }
 
-  buffer_grow_str (buffer, "</raw>\n");
+  *buffer += "</raw>\n";
 }
 
 /* See to_read_btrace target method.  */
 
 int
 linux_process_target::read_btrace (btrace_target_info *tinfo,
-				   buffer *buffer,
+				   std::string *buffer,
 				   enum btrace_read_type type)
 {
   struct btrace_data btrace;
@@ -6802,9 +6802,9 @@ linux_process_target::read_btrace (btrace_target_info *tinfo,
   if (err != BTRACE_ERR_NONE)
     {
       if (err == BTRACE_ERR_OVERFLOW)
-	buffer_grow_str0 (buffer, "E.Overflow.");
+	*buffer += "E.Overflow.";
       else
-	buffer_grow_str0 (buffer, "E.Generic Error.");
+	*buffer += "E.Generic Error.";
 
       return -1;
     }
@@ -6812,36 +6812,36 @@ linux_process_target::read_btrace (btrace_target_info *tinfo,
   switch (btrace.format)
     {
     case BTRACE_FORMAT_NONE:
-      buffer_grow_str0 (buffer, "E.No Trace.");
+      *buffer += "E.No Trace.";
       return -1;
 
     case BTRACE_FORMAT_BTS:
-      buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
-      buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
+      *buffer += "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n";
+      *buffer += "<btrace version=\"1.0\">\n";
 
       for (const btrace_block &block : *btrace.variant.bts.blocks)
-	buffer_xml_printf (buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
-			   paddress (block.begin), paddress (block.end));
+	string_xml_appendf (*buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
+			    paddress (block.begin), paddress (block.end));
 
-      buffer_grow_str0 (buffer, "</btrace>\n");
+      *buffer += "</btrace>\n";
       break;
 
     case BTRACE_FORMAT_PT:
-      buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
-      buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
-      buffer_grow_str (buffer, "<pt>\n");
+      *buffer += "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n";
+      *buffer += "<btrace version=\"1.0\">\n";
+      *buffer += "<pt>\n";
 
       linux_low_encode_pt_config (buffer, &btrace.variant.pt.config);
 
       linux_low_encode_raw (buffer, btrace.variant.pt.data,
 			    btrace.variant.pt.size);
 
-      buffer_grow_str (buffer, "</pt>\n");
-      buffer_grow_str0 (buffer, "</btrace>\n");
+      *buffer += "</pt>\n";
+      *buffer += "</btrace>\n";
       break;
 
     default:
-      buffer_grow_str0 (buffer, "E.Unsupported Trace Format.");
+      *buffer += "E.Unsupported Trace Format.";
       return -1;
     }
 
@@ -6852,12 +6852,12 @@ linux_process_target::read_btrace (btrace_target_info *tinfo,
 
 int
 linux_process_target::read_btrace_conf (const btrace_target_info *tinfo,
-					buffer *buffer)
+					std::string *buffer)
 {
   const struct btrace_config *conf;
 
-  buffer_grow_str (buffer, "<!DOCTYPE btrace-conf SYSTEM \"btrace-conf.dtd\">\n");
-  buffer_grow_str (buffer, "<btrace-conf version=\"1.0\">\n");
+  *buffer += "<!DOCTYPE btrace-conf SYSTEM \"btrace-conf.dtd\">\n";
+  *buffer += "<btrace-conf version=\"1.0\">\n";
 
   conf = linux_btrace_conf (tinfo);
   if (conf != NULL)
@@ -6868,20 +6868,20 @@ linux_process_target::read_btrace_conf (const btrace_target_info *tinfo,
 	  break;
 
 	case BTRACE_FORMAT_BTS:
-	  buffer_xml_printf (buffer, "<bts");
-	  buffer_xml_printf (buffer, " size=\"0x%x\"", conf->bts.size);
-	  buffer_xml_printf (buffer, " />\n");
+	  string_xml_appendf (*buffer, "<bts");
+	  string_xml_appendf (*buffer, " size=\"0x%x\"", conf->bts.size);
+	  string_xml_appendf (*buffer, " />\n");
 	  break;
 
 	case BTRACE_FORMAT_PT:
-	  buffer_xml_printf (buffer, "<pt");
-	  buffer_xml_printf (buffer, " size=\"0x%x\"", conf->pt.size);
-	  buffer_xml_printf (buffer, "/>\n");
+	  string_xml_appendf (*buffer, "<pt");
+	  string_xml_appendf (*buffer, " size=\"0x%x\"", conf->pt.size);
+	  string_xml_appendf (*buffer, "/>\n");
 	  break;
 	}
     }
 
-  buffer_grow_str0 (buffer, "</btrace-conf>\n");
+  *buffer += "</btrace-conf>\n";
   return 0;
 }
 #endif /* HAVE_LINUX_BTRACE */
diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
index 1594f063f47..c046b93abf4 100644
--- a/gdbserver/linux-low.h
+++ b/gdbserver/linux-low.h
@@ -282,11 +282,11 @@ class linux_process_target : public process_stratum_target
 
   int disable_btrace (btrace_target_info *tinfo) override;
 
-  int read_btrace (btrace_target_info *tinfo, buffer *buf,
+  int read_btrace (btrace_target_info *tinfo, std::string *buf,
 		   enum btrace_read_type type) override;
 
   int read_btrace_conf (const btrace_target_info *tinfo,
-			buffer *buf) override;
+			std::string *buf) override;
 #endif
 
   bool supports_range_stepping () override;
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 58aeafe11d5..0f053559b77 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -1819,7 +1819,7 @@ handle_qxfer_btrace (const char *annex,
 		     ULONGEST offset, LONGEST len)
 {
   client_state &cs = get_client_state ();
-  static struct buffer cache;
+  static std::string cache;
   struct thread_info *thread;
   enum btrace_read_type type;
   int result;
@@ -1861,13 +1861,13 @@ handle_qxfer_btrace (const char *annex,
 
   if (offset == 0)
     {
-      buffer_free (&cache);
+      cache.clear ();
 
       try
 	{
 	  result = target_read_btrace (thread->btrace, &cache, type);
 	  if (result != 0)
-	    memcpy (cs.own_buf, cache.buffer, cache.used_size);
+	    memcpy (cs.own_buf, cache.c_str (), cache.length ());
 	}
       catch (const gdb_exception_error &exception)
 	{
@@ -1878,16 +1878,16 @@ handle_qxfer_btrace (const char *annex,
       if (result != 0)
 	return -3;
     }
-  else if (offset > cache.used_size)
+  else if (offset > cache.length ())
     {
-      buffer_free (&cache);
+      cache.clear ();
       return -3;
     }
 
-  if (len > cache.used_size - offset)
-    len = cache.used_size - offset;
+  if (len > cache.length () - offset)
+    len = cache.length () - offset;
 
-  memcpy (readbuf, cache.buffer + offset, len);
+  memcpy (readbuf, cache.c_str () + offset, len);
 
   return len;
 }
@@ -1900,7 +1900,7 @@ handle_qxfer_btrace_conf (const char *annex,
 			  ULONGEST offset, LONGEST len)
 {
   client_state &cs = get_client_state ();
-  static struct buffer cache;
+  static std::string cache;
   struct thread_info *thread;
   int result;
 
@@ -1932,13 +1932,13 @@ handle_qxfer_btrace_conf (const char *annex,
 
   if (offset == 0)
     {
-      buffer_free (&cache);
+      cache.clear ();
 
       try
 	{
 	  result = target_read_btrace_conf (thread->btrace, &cache);
 	  if (result != 0)
-	    memcpy (cs.own_buf, cache.buffer, cache.used_size);
+	    memcpy (cs.own_buf, cache.c_str (), cache.length ());
 	}
       catch (const gdb_exception_error &exception)
 	{
@@ -1949,16 +1949,16 @@ handle_qxfer_btrace_conf (const char *annex,
       if (result != 0)
 	return -3;
     }
-  else if (offset > cache.used_size)
+  else if (offset > cache.length ())
     {
-      buffer_free (&cache);
+      cache.clear ();
       return -3;
     }
 
-  if (len > cache.used_size - offset)
-    len = cache.used_size - offset;
+  if (len > cache.length () - offset)
+    len = cache.length () - offset;
 
-  memcpy (readbuf, cache.buffer + offset, len);
+  memcpy (readbuf, cache.c_str () + offset, len);
 
   return len;
 }
diff --git a/gdbserver/target.cc b/gdbserver/target.cc
index c06a67600b1..08e935ff334 100644
--- a/gdbserver/target.cc
+++ b/gdbserver/target.cc
@@ -715,15 +715,15 @@ process_stratum_target::disable_btrace (btrace_target_info *tinfo)
 
 int
 process_stratum_target::read_btrace (btrace_target_info *tinfo,
-			     buffer *buffer,
-			     enum btrace_read_type type)
+				     std::string *buffer,
+				     enum btrace_read_type type)
 {
   error (_("Target does not support branch tracing."));
 }
 
 int
 process_stratum_target::read_btrace_conf (const btrace_target_info *tinfo,
-					  buffer *buffer)
+					  std::string *buffer)
 {
   error (_("Target does not support branch tracing."));
 }
diff --git a/gdbserver/target.h b/gdbserver/target.h
index 18ab969dda7..9b1a73c07a2 100644
--- a/gdbserver/target.h
+++ b/gdbserver/target.h
@@ -33,7 +33,6 @@
 #include "gdbsupport/byte-vector.h"
 
 struct emit_ops;
-struct buffer;
 struct process_info;
 
 /* This structure describes how to resume a particular thread (or all
@@ -403,14 +402,14 @@ class process_stratum_target
   /* Read branch trace data into buffer.
      Return 0 on success; print an error message into BUFFER and return -1,
      otherwise.  */
-  virtual int read_btrace (btrace_target_info *tinfo, buffer *buf,
+  virtual int read_btrace (btrace_target_info *tinfo, std::string *buf,
 			   enum btrace_read_type type);
 
   /* Read the branch trace configuration into BUFFER.
      Return 0 on success; print an error message into BUFFER and return -1
      otherwise.  */
   virtual int read_btrace_conf (const btrace_target_info *tinfo,
-				buffer *buf);
+				std::string *buf);
 
   /* Return true if target supports range stepping.  */
   virtual bool supports_range_stepping ();
@@ -636,7 +635,7 @@ target_disable_btrace (struct btrace_target_info *tinfo)
 
 static inline int
 target_read_btrace (struct btrace_target_info *tinfo,
-		    struct buffer *buffer,
+		    std::string *buffer,
 		    enum btrace_read_type type)
 {
   return the_target->read_btrace (tinfo, buffer, type);
@@ -644,7 +643,7 @@ target_read_btrace (struct btrace_target_info *tinfo,
 
 static inline int
 target_read_btrace_conf (struct btrace_target_info *tinfo,
-			 struct buffer *buffer)
+			 std::string *buffer)
 {
   return the_target->read_btrace_conf (tinfo, buffer);
 }
