@@ -91,7 +91,72 @@ debugger can have bugs, the reproducer can have bugs too.
9191Design
9292------
9393
94- Coming soon.
94+
95+ Replay
96+ ``````
97+
98+ Reproducers support two replay modes. The main and most common mode is active
99+ replay. It's called active, because it's LLDB that is driving replay by calling
100+ the captured SB API functions one after each other. The second mode is passive
101+ replay. In this mode, LLDB sits idle until an SB API function is called, for
102+ example from Python, and then replays just this individual call.
103+
104+ Active Replay
105+ ^^^^^^^^^^^^^
106+
107+ No matter how a reproducer was captured, they can always be replayed with the
108+ command line driver. When a reproducer is passed with the `--replay ` flag, the
109+ driver short-circuits and passes off control to the reproducer infrastructure,
110+ effectively bypassing its normal operation. This works because the driver is
111+ implemented using the SB API and is therefore nothing more than a sequence of
112+ SB API calls.
113+
114+ Replay is driven by the ``Registry::Replay ``. As long as there's data in the
115+ buffer holding the API data, the next SB API function call is deserialized.
116+ Once the function is known, the registry can retrieve its signature, and use
117+ that to deserialize its arguments. The function can then be invoked, most
118+ commonly through the synthesized default replayer, or potentially using a
119+ custom defined replay function. This process continues, until more data is
120+ available or a replay error is encountered.
121+
122+ During replay only a function's side effects matter. The result returned by the
123+ replayed function is ignored because it cannot be observed beyond the driver.
124+ This is sound, because anything that is passed into a subsequent API call will
125+ have been serialized as an input argument. This also works for SB API objects
126+ because the reproducers know about every object that has crossed the API
127+ boundary, which is true by definition for object return values.
128+
129+
130+ Passive Replay
131+ ^^^^^^^^^^^^^^
132+
133+ Passive replay exists to support running the API test suite against a
134+ reproducer. The API test suite is written in Python and tests the debugger by
135+ calling into its API from Python. To make this work, the API must transparently
136+ replay itself when called. This is what makes passive replay different from
137+ driver replay, where it is lldb itself that's driving replay. For passive
138+ replay, the driving factor is external.
139+
140+ In order to replay API calls, the reproducers need a way to intercept them.
141+ Every API call is already instrumented with an ``LLDB_RECORD_* `` macro that
142+ captures its input arguments. Furthermore, it also contains the necessary logic
143+ to detect which calls cross the API boundary and should be intercepted. We were
144+ able to reuse all of this to implement passive replay.
145+
146+ During passive replay is enabled, nothing happens until an SB API is called.
147+ Inside that API function, the macro detects whether this call should be
148+ replayed (i.e. crossed the API boundary). If the answer is yes, the next
149+ function is deserialized from the SB API data and compared to the current
150+ function. If the signature matches, we deserialize its input arguments and
151+ reinvoke the current function with the deserialized arguments. We don't need to
152+ do anything special to prevent us from recursively calling the replayed version
153+ again, as the API boundary crossing logic knows that we're still behind the API
154+ boundary when we re-invoked the current function.
155+
156+ Another big difference with driver replay is the return value. While this
157+ didn't matter for driver replay, it's key for passive replay, because that's
158+ what gets checked by the test suite. Luckily, the ``LLDB_RECORD_* `` macros
159+ contained sufficient type information to derive the result type.
95160
96161Testing
97162-------
0 commit comments