This is an archive of the discontinued LLVM Phabricator instance.

[lldb] Fork/vfork support via gdb-remote protocol [WIP]
AbandonedPublic

Authored by mgorny on Apr 4 2021, 12:54 PM.

Details

Summary

Initial work on moving fork support from server to gdb-remote protocol. If fork-events (vfork-events) extension is supported, the server reports them to the client as fork (vfork) stop reason. The client currently replies with a detach packet.

To be honest, I'm not 100% sure about the API. I've tried to come up with some compromise between doing things right and avoiding too much complexity. The fork/vfork-related logic is supported only by the gdb-remote plugin. Currently only fork is implemented, on Linux, and breakpoints are not handled yet.

Diff Detail

Event Timeline

mgorny requested review of this revision.Apr 4 2021, 12:54 PM
mgorny created this revision.
mgorny updated this revision to Diff 335765.Apr 7 2021, 2:39 AM

Added breakpoint cleanup via gdb-remote protocol. Only minimal code coverage so far. If this approach is okay, I guess I'll add subprocess guards to all server commands.

mgorny added inline comments.Apr 7 2021, 11:02 AM
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
455

Kamil noticed that this will also catch vfork-events+. I suppose I'll rewrite this function to iterate over split data as well.

labath added a comment.Apr 8 2021, 5:04 AM

This is going to be pretty big, so I'd say we start splitting this up. The client & server bits can go into separate patches, and it would make things simpler if the qSupported emission and parsing also got its own patches, as that is going to be a lot less controversial.

I'm going to have more questions, but let me start with this: What should the (v)fork-events extension actually mean? In the client, I guess it demonstrates its willingness to receive the appropriate type of event. But what should it mean on the server? Is it like "I promise to stop on every (v)fork", or just something like "hey, I know this word"? The second meaning only makes sense if these (v)fork-events come with some new protocol extensions/packets that the client can use when communicating with the server. Such is the case with the multiprocess extension (new thread id syntax), but I am not aware of anything similar in for these features. Are there any? The gdb documentation (This feature indicates whether GDB supports fork event extensions to the remote protocol. GDB does not use such extensions unless the stub also reports that it supports them by including ‘fork-events+’ in its ‘qSupported’ reply. ) seems to indicate they might exist, but I am not sure what would they be...

If there aren't any, then it would probably be better to use the first "definition" of the feature (or something similar), as the client can legitimately be interested in whether it will be able to intercept forks or not. And if that's the case, then we should first consult the relevant NativeProcess class before we reply (v)fork-events+.

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
455

Yeah, that should have been done a long time ago.

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
1314–1322

Ideally, all of these would be handled in the GDBRemoteCommunicationServerLLGS class, since these features are meaningless for the platform server. Then you also wouldn't need to define the m_(v)fork_events_supported members in this class.

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
152

A SmallVector as a return type is fairly odd. One tends to use SmallVectorImpl by-ref argument in this case, but a plain std::vector result is also fine.

lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
2342–2344

description = llvm::formatv("{0} {1}", pid_tid->first, pid_tid->second).str()

I'm going to have more questions, but let me start with this: What should the (v)fork-events extension actually mean? In the client, I guess it demonstrates its willingness to receive the appropriate type of event. But what should it mean on the server? Is it like "I promise to stop on every (v)fork", or just something like "hey, I know this word"? The second meaning only makes sense if these (v)fork-events come with some new protocol extensions/packets that the client can use when communicating with the server. Such is the case with the multiprocess extension (new thread id syntax), but I am not aware of anything similar in for these features. Are there any? The gdb documentation (This feature indicates whether GDB supports fork event extensions to the remote protocol. GDB does not use such extensions unless the stub also reports that it supports them by including ‘fork-events+’ in its ‘qSupported’ reply. ) seems to indicate they might exist, but I am not sure what would they be...

If there aren't any, then it would probably be better to use the first "definition" of the feature (or something similar), as the client can legitimately be interested in whether it will be able to intercept forks or not. And if that's the case, then we should first consult the relevant NativeProcess class before we reply (v)fork-events+.

Reading GDB code, the server indicates fork-events+ only if the target explicitly supports it. In case of Linux, it even goes as far as to perform a runtime test for fork reporting but I don't think we want to go that far. The support for particular kind of events is reported independently of whether client indicated support.

On client end, the server indication seems to be used to determine whether 'inserting' fork catchpoint succeeds or fails (it does not perform any comm itself since catchpoints just react to fork events from server). If I'm reading the code correctly, it also ignores fork/vfork events if qSupported did not indicate support earlier, though tbh I don't think that makes much sense — I suppose it just leads to UB since server sent a stop and we do nothing about it.

mgorny marked 2 inline comments as done.

The server-side qSupported handling is now split into D100140, and all relevant remarks were addressed there.

mgorny marked an inline comment as done.Apr 8 2021, 3:24 PM

Client-side qSupported processing is now refactored in D100146.

mgorny added a comment.Apr 8 2021, 4:23 PM

And now moved Extension API to D100153. I've added an API to query features supported by platform plugin, so now server doesn't report them unless they're actually going to be used.

mgorny added a comment.Apr 9 2021, 7:05 AM

I've decided to take another approach for tracking forked processes. Rather than keeping them inside NativeProcess* and exposing via API to LLGS, I've decided to push them via NativeDelegate straight into LLGS and maintain there. This is now D100191.

I've also split the fundamental support for new stop reasons into D100196.

mgorny abandoned this revision.Apr 11 2021, 5:08 AM

Let's close this as all the features are now part of other diffs.