How to handle "O XX..." reply packets from gdb servers like openocd

Looking for guidance. This seems like an lldb issue, but maybe I'm
missing something. And while I have a potential solution, I'm not
familiar enough with lldb code to know if its a "good" solution.

Background

I dug into this a bit more, and these output reply packets seem to be
handled already, but only if the program is running.

Since the relevant openocd commands are often issued when the program
paused, the reply packets aren't processed as expected.

The spec does say that reply packets can happen "any time while the
program is running", so perhaps openocd is abusing the protocol, but
gdb handles the packets just fine when stopped.

It's unclear in which other cases these packets would arrive when the
program is stopped, so I've put together a narrowed solution:

1. Adding GDBRemoteClientBase::SendPacketHandlingOutput(), with a
callback argument to handle any output
2. Calling SendPacketHandlingOutput() from
CommandObjectProcessGDBRemotePacketMonitor, providing a callback lamda
that uses an already-available output stream

It's a simpler and less intrusive solution, but will only apply to
"process plugin packet monitor" commands. Perhaps that's sufficient.

Any thoughts still appreciated.

Thanks,
Owen

I dug into this a bit more, and these output reply packets seem to be
handled already, but only if the program is running.

Since the relevant openocd commands are often issued when the program
paused, the reply packets aren't processed as expected.

The spec does say that reply packets can happen "any time while the
program is running", so perhaps openocd is abusing the protocol, but
gdb handles the packets just fine when stopped.

Yes, LLDB is assuming that an "O" packet will only come during a continue command. "O" is for stdout output and it seems the rCmd assuming it will work. Why not just send back the text in response to the rCmd? Is some common code path being hit where it might send this text while running and also in response to the rCmd? I am confused by "O" packets are needed in response to the rCmd.

It's unclear in which other cases these packets would arrive when the
program is stopped, so I've put together a narrowed solution:

1. Adding GDBRemoteClientBase::SendPacketHandlingOutput(), with a
callback argument to handle any output
2. Calling SendPacketHandlingOutput() from
CommandObjectProcessGDBRemotePacketMonitor, providing a callback lamda
that uses an already-available output stream

It's a simpler and less intrusive solution, but will only apply to
"process plugin packet monitor" commands. Perhaps that's sufficient.

Any thoughts still appreciated.

If the rCmd can't be fixed to just return the text without using "O" packets, I would think a simpler solution might be to change the response packet code to take a boolean that says "handle_output". Then only the continue (c, s, vCont, etc) packets would set this to true, and the "rCmd" command could set this to true. This bool would need to be plumbed through to the SendPacketAndWaitForResponse(...) functions. We could have a default argument set to false so most code won't change, just the continue and rCmd packet senders.

Greg

Hi Greg,

I've been assuming that we can't force a change to openocd's behavior,
or at least that the easier path is to handle its current behavior. I
don't know why openocd sends O packets in response to an rCmd, but it
does and gdb is okay with it.

I'm still learning my way around the lldb code, but it looked like the
continue scenario has its own function,
SendContinuePacketAndWaitForResponse(), and with continue-specific
logic, there didn't seem to be an obvious way to leverage that code or
to have the continue commands share some new code.

I have a working option coded up, and can easily throw a patch up in
Phabricator if it'd be helpful to discuss the details. Let me know
how you'd like to proceed.

Thanks,
Owen

I dug into this a bit more, and these output reply packets seem to be
handled already, but only if the program is running.

Since the relevant openocd commands are often issued when the program
paused, the reply packets aren't processed as expected.

The spec does say that reply packets can happen "any time while the
program is running", so perhaps openocd is abusing the protocol, but
gdb handles the packets just fine when stopped.

Yes, LLDB is assuming that an "O" packet will only come during a continue command. "O" is for stdout output and it seems the rCmd assuming it will work. Why not just send back the text in response to the rCmd? Is some common code path being hit where it might send this text while running and also in response to the rCmd? I am confused by "O" packets are needed in response to the rCmd.

qRcmd was invented well before my time, but qRcmd provides support
for running random interpreter commands on the server, with the
resulting output being potentially long, unbounded. Thus sending the
text back in response to qRcmd would require an unbounded packet buffer
and would potentially hit the max packet size. So you'd need some
way to send partial output in chunks. Which ends up being exactly what
you get by reusing "O".

If the rCmd can't be fixed to just return the text without using "O" packets,

The documentation of the qRcmd packet explicitly specifies that output
should be sent via "O" packets:

General Query Packets (Debugging with GDB)

Sounds like OpenOCD is working as intended.

Pedro Alves

Then the right way to fix this is to somehow allow the rCmd to watch for the “O” packets in its responses. Since no other commands want this and the send continue packets use a special send packet and receive response, we might must want a SendPacketAndReceiveResponseWithOutputSupport(…) that rCmd will use. We could also add a bool to the stand send packet and receive response that indicates if “O” packet responses are possible, my only objection to that is it makes it seem like any command can just opt into getting “O” responses. If rCmd is the only other packet other than continue, I would do add the SendPacketAndReceiveResponseWithOutputSupport and call it explicitly from the rCmd handler. I am open to other suggestions.

Greg