Mirror of the gdb mailing list
 help / color / mirror / Atom feed
From: Andrew Burgess via Gdb <gdb@sourceware.org>
To: "Aktemur, Tankut Baris" <tankut.baris.aktemur@intel.com>,
	"robert@ocallahan.org" <robert@ocallahan.org>,
	"gdb@sourceware.org" <gdb@sourceware.org>
Subject: RE: Incompatible implementat ion of 'x' packet in GDB vs LLDB
Date: Thu, 23 Jan 2025 16:14:45 +0000	[thread overview]
Message-ID: <87a5bhmrre.fsf@redhat.com> (raw)
In-Reply-To: <DM4PR11MB7303F8845229367DDDDED2DEC4E02@DM4PR11MB7303.namprd11.prod.outlook.com>

"Aktemur, Tankut Baris via Gdb" <gdb@sourceware.org> writes:

> On Thursday, January 23, 2025 8:13 AM, Robert O'Callahan wrote:
>> On Thu, 23 Jan 2025 at 08:57, Robert O'Callahan <robert@ocallahan.org>
>> wrote:
>> 
>> > GDB (client) 16.1 started sending the gdbserver 'x' packet. It follows the
>> > documentation [1] and expects a leading 'b' in the response [2].
>> > Unfortunately LLDB has supported this packet for quite a long time [3] and
>> > does not expect a leading 'b' in the response. We added support for this
>> > packet to rr last year and followed LLDB's format because it was the only
>> > user of the packet at that time. So GDB 16.1 doesn't work with rr. [4]
>> >
>> > I realize that compatibility between GDB and LLDB flavoured gdbserver
>> > protocols is not a priority for either team, but until now it has actually
>> > worked in practice --- rr hasn't needed a client mode switch. We can add
>> > one, but it will be unfortunate if GDB 16.1 and later is incompatible for
>> > anyone who's installed the latest rr since May 2024.
>> >
>> > Could you make a GDB 16.1 point release that removes the 'b'? AFAIK it
>> > serves no purpose.
>> >
>> 
>> It has been pointed out that if you want to return different error codes
>> then you need the 'b'. Is that the rationale?
>
> Hello Rob,
>
> Essentially, yes.  In case of an error, the server responds with an 'E' packet.
> To be able to distinguish an error packet from binary data, 'E' would have to be
> added to the list of escaped characters.  Having the 'b' marker avoids that.
>
> Additionally, when the response is empty, per RSP, it means the packet is unsupported.
> So, in case of a zero-length request, the 'b' marker could help us distinguish the
> unsupported case from an actual zero-response.
> LLDB doc says
>
>   To test if this packet is available, send a addr/len of 0:
>
>     x0,0
>
>   You will get an OK response if it is supported. 
>   The reply will be the data requested in 8-bit binary data format.
>
> How does LLDB distinguish an "OK" response, an empty binary data, an error,
> and an unsupported case?  These were not clear to me from the docs.
> Is the x0,0 query special-cased?
>
> For the record, the 'x' packet series were discussed in
>
>   https://inbox.sourceware.org/gdb-patches/cover.1710343840.git.tankut.baris.aktemur@intel.com/#r
>
> with the part specific to the 'b' marker in
>
>   https://inbox.sourceware.org/gdb-patches/87msq82ced.fsf@redhat.com/

I also am not entirely sure how lldb's implementation can work in all
cases given their description.  For now at least, I still think we made
the right choice with our implementation, though I guess if we'd known
we were diverging from llvm we might have picked a different letter for
packet in order to make it completely different.

I have two thoughts for things we could do to possibly help with
compatibility here though:

  1. Hide the 'x' packet behind a feature flag.  So instead of using the
  empty reply to indicate 'x' packet support, we ask remote targets to
  send 'gdb-x+' in their qSupported reply.  If a remote target sends
  this to GDB then we will assume that they support GDB's style of 'x'
  packet, and can make use of the packet.  Otherwise, it's 'm' packets
  all the way.


  2. The other option would be to probe for 'x' packet support as a
  separate action.  Right now probing is done the first time we send an
  'x' packet.  The packet is sent, and if we get back the empty packet,
  then we know 'x' packets are supported.

  But if instead, we sent a zero length read, then by GDB's rules we
  should get back a lone 'b'.  By lldb's rules we should get back
  .... maybe "OK" ... or maybe the empty packet?  It's not really
  clear.  But the important thing is that neither of those replies are
  'b'.

  So the first time we consider sending an 'x' packet, we send
  'xADDR,0', if we get back 'b', then we know that we have GDB style
  support, otherwise, we disable the 'x' packet, and fall back to the
  'm' packet.

Approach #1 is pretty straight forward, but I wanted to check what
approach #2 would look like, so I drafted the patch below.  This patch
is pretty rough right now, but can easily be cleaned up.

For testing this patch I hacked up gdbserver so it no longer added the
'b' prefix, then I tried connecting with GDB.  I see GDB send the zero
length probe, then switch back to 'm' packets.

Questions:

  + Do people think we should change GDB to improve compatibility?  My
    thinking is yes, so long as the cost isn't too high.

  + Do people prefer approach #1 or #2?  I'm leaning slightly more to #2
    right now, but not massively so.  If people prefer #1 I can write
    the patch for that instead.

Thanks,
Andrew

---

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b65124d807f..e92227d3803 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -43531,6 +43531,10 @@ Packets
 use byte accesses, or not.  For this reason, this packet may not be
 suitable for accessing memory-mapped I/O devices.
 
+If @var{length} is zero then the reply should contain the leading
+@samp{b} prefix and not data.  @value{GDBN} sends a zero length
+@samp{x} packet to probe for support.
+
 Reply:
 @table @samp
 @item b @var{XX@dots{}}
diff --git a/gdb/remote.c b/gdb/remote.c
index 64622dbfcdf..a332fcd6f95 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -9683,17 +9683,55 @@ remote_target::remote_read_bytes_1 (CORE_ADDR memaddr, gdb_byte *myaddr,
   memaddr = remote_address_masked (memaddr);
 
   /* Construct "m/x"<memaddr>","<len>".  */
-  auto send_request = [this, rs, memaddr, todo_units] (char format) -> void
+  auto send_request = [this, rs, memaddr] (char format, int len) -> void
     {
       char *buffer = rs->buf.data ();
       *buffer++ = format;
       buffer += hexnumstr (buffer, (ULONGEST) memaddr);
       *buffer++ = ',';
-      buffer += hexnumstr (buffer, (ULONGEST) todo_units);
+      buffer += hexnumstr (buffer, (ULONGEST) len);
       *buffer = '\0';
       putpkt (rs->buf);
     };
 
+  /* Unfortunately, lldb and GDB disagree on the reply format for the 'x'
+     packet.  GDB expects a 'b' as the first byte of a successful packet,
+     while lldb does not.  There are good reasons why GDB uses the 'b'
+     prefix; it's not possible to distinguish between an empty
+     not-supported reply and a failed read empty reply, unless there is a
+     prefix.
+
+     As lldb "got there first", and there are clients in the wild that
+     support the lldb style reply, we probe with a zero length read.  If
+     this returns a single 'b' then we know that the 'x' packet is
+     supported.
+
+     If we get back an error packet (starts with 'E') then we cannot know
+     if a successful read would start with a 'b' or not.  We'll probe again
+     next time.  */
+  if (m_features.packet_support (PACKET_x) == PACKET_SUPPORT_UNKNOWN)
+    {
+      send_request ('x', 0);
+      int packet_len = getpkt (&rs->buf);
+
+      /* Catastrophic error fetching packet.  */
+      if (packet_len < 0)
+	return TARGET_XFER_E_IO;
+
+      /* If we get back a lone 'b' with no data then the remote replied as
+	 expected.  Anything else and we just disable the 'x' packet.  */
+      if (rs->buf[0] == 'b' && rs->buf[1] == '\0')
+	{
+	  remote_debug_printf ("binary memory read is supported by target");
+	  m_features.m_protocol_packets[PACKET_x].support = PACKET_ENABLE;
+	}
+      else
+	{
+	  remote_debug_printf ("binary memory read NOT supported by target");
+	  m_features.m_protocol_packets[PACKET_x].support = PACKET_DISABLE;
+	}
+    }
+
   /* Determine which packet format to use.  The target's support for
      'x' may be unknown.  We just try.  If it doesn't work, we try
      again using 'm'.  */
@@ -9703,32 +9741,11 @@ remote_target::remote_read_bytes_1 (CORE_ADDR memaddr, gdb_byte *myaddr,
   else
     packet_format = 'x';
 
-  send_request (packet_format);
+  send_request (packet_format, todo_units);
   int packet_len = getpkt (&rs->buf);
   if (packet_len < 0)
     return TARGET_XFER_E_IO;
 
-  if (m_features.packet_support (PACKET_x) == PACKET_SUPPORT_UNKNOWN)
-    {
-      if (rs->buf[0] == '\0')
-	{
-	  remote_debug_printf ("binary uploading NOT supported by target");
-	  m_features.m_protocol_packets[PACKET_x].support = PACKET_DISABLE;
-
-	  /* Try again using 'm'.  */
-	  packet_format = 'm';
-	  send_request (packet_format);
-	  packet_len = getpkt (&rs->buf);
-	  if (packet_len < 0)
-	    return TARGET_XFER_E_IO;
-	}
-      else
-	{
-	  remote_debug_printf ("binary uploading supported by target");
-	  m_features.m_protocol_packets[PACKET_x].support = PACKET_ENABLE;
-	}
-    }
-
   packet_result result = packet_check_result (rs->buf);
   if (result.status () == PACKET_ERROR)
     return TARGET_XFER_E_IO;


  parent reply	other threads:[~2025-01-23 16:15 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-22 19:57 Robert O'Callahan
2025-01-23  7:12 ` Robert O'Callahan
2025-01-23  8:13   ` Aktemur, Tankut Baris via Gdb
2025-01-23 11:23     ` Robert O'Callahan
2025-01-23 11:39       ` Luis Machado via Gdb
2025-01-23 16:14     ` Andrew Burgess via Gdb [this message]
2025-01-23 16:33       ` Luis Machado via Gdb
2025-01-23 17:28         ` Andrew Burgess via Gdb
2025-01-23 19:38           ` Andrew Burgess via Gdb
2025-01-28  8:26             ` Pavel Labath via Gdb
2025-01-28  9:25               ` Pavel Labath via Gdb
2025-01-28 10:15                 ` Luis Machado via Gdb

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87a5bhmrre.fsf@redhat.com \
    --to=gdb@sourceware.org \
    --cc=aburgess@redhat.com \
    --cc=robert@ocallahan.org \
    --cc=tankut.baris.aktemur@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox