[lldb/Docs] Document active and passive replay.

Document reproducer replay and its two modes.

Differential revision: https://reviews.llvm.org/D77771
This commit is contained in:
Jonas Devlieghere 2020-04-14 08:39:46 -07:00
parent 7bf166665e
commit c5a3991895
1 changed files with 66 additions and 1 deletions

View File

@ -91,7 +91,72 @@ debugger can have bugs, the reproducer can have bugs too.
Design
------
Coming soon.
Replay
``````
Reproducers support two replay modes. The main and most common mode is active
replay. It's called active, because it's LLDB that is driving replay by calling
the captured SB API functions one after each other. The second mode is passive
replay. In this mode, LLDB sits idle until an SB API function is called, for
example from Python, and then replays just this individual call.
Active Replay
^^^^^^^^^^^^^
No matter how a reproducer was captured, they can always be replayed with the
command line driver. When a reproducer is passed with the `--replay` flag, the
driver short-circuits and passes off control to the reproducer infrastructure,
effectively bypassing its normal operation. This works because the driver is
implemented using the SB API and is therefore nothing more than a sequence of
SB API calls.
Replay is driven by the ``Registry::Replay``. As long as there's data in the
buffer holding the API data, the next SB API function call is deserialized.
Once the function is known, the registry can retrieve its signature, and use
that to deserialize its arguments. The function can then be invoked, most
commonly through the synthesized default replayer, or potentially using a
custom defined replay function. This process continues, until more data is
available or a replay error is encountered.
During replay only a function's side effects matter. The result returned by the
replayed function is ignored because it cannot be observed beyond the driver.
This is sound, because anything that is passed into a subsequent API call will
have been serialized as an input argument. This also works for SB API objects
because the reproducers know about every object that has crossed the API
boundary, which is true by definition for object return values.
Passive Replay
^^^^^^^^^^^^^^
Passive replay exists to support running the API test suite against a
reproducer. The API test suite is written in Python and tests the debugger by
calling into its API from Python. To make this work, the API must transparently
replay itself when called. This is what makes passive replay different from
driver replay, where it is lldb itself that's driving replay. For passive
replay, the driving factor is external.
In order to replay API calls, the reproducers need a way to intercept them.
Every API call is already instrumented with an ``LLDB_RECORD_*`` macro that
captures its input arguments. Furthermore, it also contains the necessary logic
to detect which calls cross the API boundary and should be intercepted. We were
able to reuse all of this to implement passive replay.
During passive replay is enabled, nothing happens until an SB API is called.
Inside that API function, the macro detects whether this call should be
replayed (i.e. crossed the API boundary). If the answer is yes, the next
function is deserialized from the SB API data and compared to the current
function. If the signature matches, we deserialize its input arguments and
reinvoke the current function with the deserialized arguments. We don't need to
do anything special to prevent us from recursively calling the replayed version
again, as the API boundary crossing logic knows that we're still behind the API
boundary when we re-invoked the current function.
Another big difference with driver replay is the return value. While this
didn't matter for driver replay, it's key for passive replay, because that's
what gets checked by the test suite. Luckily, the ``LLDB_RECORD_*`` macros
contained sufficient type information to derive the result type.
Testing
-------