public inbox for
 help / color / mirror / Atom feed
From: Pedro Alves <>
To: Adrian Oltean <>, Tom Tromey <>
Cc: Adrian Oltean via Gdb <>
Subject: Re: [EXT] Re: Semihosting in GDB 11.1 | Proposed patch for interrupting in sync mode
Date: Thu, 10 Mar 2022 11:30:51 +0000	[thread overview]
Message-ID: <> (raw)
In-Reply-To: <>

On 2022-03-10 10:02, Adrian Oltean wrote:

> As far as 'H' packet handling is concerned, note that the GDB server I'm referring is a proprietary implementation
> that is used for JTAG debugging. Threads are numbered from 1. However, in the old implementation "Hg0" was always
> switching to thread 1 ("first thread") internally, even though some other core/thread was suspended. The original
> implementation assumed "Hg0" must *always* switch to "first thread" (thread 1 in my case) but this doesn't seem
> to be enforced in the RSP specs. I updated the code and assimilate "arbitrary" (from spec) as "if there's no suspended
> thread/core internally selected, find a valid one".

So going back to your original problem description, you said:

2. File I/O (semihosting) when a multicore (ARMv8) target is involved seems
to exhibit an issue. My multicore debugging model assumes that each core is a
separate thread. If I have 'printf' calls executed on separate cores, I noticed
that the messages are duplicated on secondary cores (other than core 0). The
remote log snippet that highlights the root cause is pasted below. Long story
short, the 'H' packet that is sent to the server and instructs it to use
thread 0 for some further operations, actually causes troubles because breakpoint
handling and run control gets broken afterwards. Note that the 'Fwrite' is the
result of a 'printf' on a secondary core, thus instructing the server to use
thread 0 breaks lots of things inside the GDB server. The 'H' packet seems to
be sent as a result of the 'continue' action and it translates into a call to
'switch_to_no_thread'. If I ignore the 'H' packet, semihosting breakpoints and run
control are correctly handled, so the second 'Fwrite' RSP sequence would not
exist (this is the expected behavior). Is the described behavior a known issue
inside GDB? Or do I have to change something in the server to correct the
described behavior?

[remote] Sending packet: $vCont;c#a8
[remote] Received Ack
[remote] wait: enter
  [remote] Packet received: Fwrite,1,80026300,12
  [remote] Sending packet: $Hg0#df
  [remote] Received Ack
  [remote] Packet received: OK
  [remote] Sending packet: $m80026300,12#8f
  [remote] Received Ack
  [remote] Packet received: 48656c6c6f2066726f6d20436f726523370a
  [remote] Sending packet: $F12#a9
  [remote] Received Ack
  [remote] Packet received: Fwrite,1,80026300,12
  [remote] Sending packet: $m80026300,12#8f
  [remote] Received Ack
  [remote] Packet received: 48656c6c6f2066726f6d20436f726523370a
  [remote] Sending packet: $F12#a9
  [remote] Received Ack
  [remote] Packet received: T05thread:p1.8;core:7;
[remote] wait: exit

The printf calls end up calling write under the hood, of course, and those
syscalls are intercepted and translated to File I/O calls into GDB.  That's the
"Fwrite,1,80026300,12" packets.  Now, GDB processes those and writes to its
own stdout.  What is written to its stdout is 12 bytes found at 0x80026300 in
the inferior memory, as per the Fwrite packet's arguments.

Depending on the kind of target object is being accessed, GDB makes sure
to select the proper remote thread, or at least any thread of the right remote process.
This is important for when the remote side understands the multi-process extensions,
for example, lest GDB reads something of the wrong process.

So in remote.c, you'll see calls to set_general_process, like this:

  /* Make sure the remote is pointing at the right process.  */
  set_general_process ();

... which translate to "HgPID.0" when multi-process extensions are supported by
the server, and "Hg0" when they're not.

For memory reads in particular, GDB instead makes sure that GDB's selected thread
is selected on the server side as well, not just any thread of the gdb-selected process.
This is done here:

 enum target_xfer_status
 remote_target::xfer_partial (enum target_object object,
 			     const char *annex, gdb_byte *readbuf,
 			     const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
 			     ULONGEST *xfered_len)
   set_general_thread (inferior_ptid);

So what I think is happening is that inferior_ptid is null_ptid when you get here.
We always switch to null_ptid when waiting for events out of the target, exactly
to better uncover spots that would be relying on some stale non-null inferior_ptid
by accident.  This would be such a case.  The inferior is running, and we're waiting
for events, so whatever was the gdb-selected thread (per inferior_ptid) has no bearing
on what thread is reporting some event.

If the server supports multi-process extensions, then that set_general_thread call above
with inferior_ptid == null_ptid will end up sending "Hg0.0", meaning, select any thread of any process,
which means the subsequent memory read (m packet) will potentially read memory off of
the wrong process.  This is obviously bad.

HOWEVER.  Note that the File I/O packets, like "Fwrite,1,80026300,12" don't say
at all which thread is doing the File I/O access!  IOW, this packet is not useable
in multi-process scenarios as is...  It would need to be extended to also pass down
an extra thread id field, like "Fwrite,1,80026300,12,pPID.TID".  FSF GDBserver doesn't
support File I/O, so these File I/O packets didn't get attention when the multi-process
extensions were devised.

So alright, the current "Hg0" packet you see in your logs is a bit spurious, but, it should
be harmless, and you should be able to select any valid thread, as per the Hg0 packet's
description, as all threads share the same address space, in GDB's view.

  [remote] Packet received: Fwrite,1,80026300,12
  [remote] Sending packet: $Hg0#df
  [remote] Received Ack
  [remote] Packet received: OK
  [remote] Sending packet: $m80026300,12#8f
  [remote] Received Ack
  [remote] Packet received: 48656c6c6f2066726f6d20436f726523370a
  [remote] Sending packet: $F12#a9

What I think you should do is, when you get the reply to Fwrite -- the "$F12#a9"
packet -- your stub should make sure that that resumes the same thread that initiated
the Fwrite, not whatever Hg selected.  That $F12 reply is linked with the last Fwrite,
there can only be one File I/O request ongoing at a given time.

Pedro Alves

  reply	other threads:[~2022-03-10 11:30 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-09  7:25 Adrian Oltean
2022-03-09 19:49 ` Tom Tromey
2022-03-10  9:47   ` Pedro Alves
2022-03-10 10:02     ` [EXT] " Adrian Oltean
2022-03-10 11:30       ` Pedro Alves [this message]
2022-03-10 12:32         ` Pedro Alves
2022-03-14  7:33           ` Adrian Oltean
2022-03-17 17:48             ` Pedro Alves

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:

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

  git send-email \ \ \ \ \ \

* 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;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).