Using the Live Recorder API

Depending on your license, Live Recorder can be provided as a library that can be linked into your application in order to give it the ability to record itself.

At its simplest, Live Recorder can be used as follows:

#include "undolr.h"

int main(int argc, char** argv)
{
    if (argv != 2) return -1;

    undolr_error_t lre;
    int e = undolr_start(&lre);
    if (e) return e;

    e = undolr_save_on_termination(argv[1]);
    if (e) return e;

    // ...your code here...

    return 0;
}

This program will immediately start recording its execution, and the recording will end when the program terminates, at which point a recording will be saved to the file specified in argv[1]. Here’s an example invocation:

./example recording.undo

Recordings produced by Live Recorder can then be loaded into UndoDB.

Integrating Live Recorder

You can find the Live Recorder libraries and header file in the undolr subdirectory of an UndoDB release:

undodb-<version>/
    ...
    undolr/
        libundolr_x64.a
        libundolr_x64.so
        README
        undolr.h
        ...

Header file

Live Recorder has just a single header file, undolr.h. Simply include this header file into your application to get access to the undolr_* APIs.

Linking

Live Recorder is available as both a statically linked library (libundolr_<arch>.a) and a dynamically linked library (libundolr_<arch>.so). There are no extra dependencies, so the build command will be similar to:

gcc -g -o example example.c libundolr_x64.a

or:

gcc -g -no-pie -o example example.c libundolr_x64.a

with some recent versions of GCC.

APIs

Note

See the undolr.h header file for the most detailed information about available APIs.

  • undolr_start - Start recording the execution of the program. The time at which this is called will be the earliest point in time in the recording.
  • undolr_save - Save a recording currently in progress to the specified file, and hence stop recording. The time at which this is called will be the latest point in time in the recording.
  • undolr_stop - Stop recording the execution of the program. The time at which this is called will be the latest point in time in any recording subsequently made by undolr_save_async.
  • undolr_save_async - Save a recording that has already been stopped by undolr_stop. This function returns quickly, and the recording is saved asynchronously.
  • undolr_poll_saving_complete - Query the API to determine whether a save started with undolr_save_async has finished.
  • undolr_get_select_descriptor - Returns a file descriptor which can be selected on for read. When a byte is available on the descriptor, asynchronous save state may have updated.
  • undolr_discard - Free up resources associated with a stopped recording.
  • undolr_save_on_termination - Request that a recording is saved once the the program terminates. The time at which the program terminates will be the latest point in time in the recording.
  • undolr_save_on_termination_cancel - Cancel a previous request to undolr_save_on_termination().

Debugging a Live Recording without symbols

Debug symbols often contain sensitive information which makes it desirable to strip them from your binaries. If an Undo Live Recording is made from an executable without symbols then the debug session you will get from loading the recording will also be lacking symbolic information.

The use of GDB’s symbol-file command can be used to combine a Live Recording without symbols with a special file that does not need to be released to your customers.

Example

Build an UndoLR enabled binary that includes symbols:

$ gcc -std=c99 -g test.c -I undolr/ undolr/libundolr_x64.a -o test

This particular example builds a binary called test, that will dump out a recording file called example.undo.

We now want to create a seperate file containing only the debug information. The following line creates such a file from our test binary, with the name test.debug:

$ objcopy --only-keep-debug test test.debug

We’re now free to strip all the debug information out of the test binary:

$ strip -s test

Next up, we run test to create our recording.

$ ./test
Dumping recording file "example.undo"

Loading the recording up shows that no debug symbols are in the recording file:

$ udb --undodb-load recording.undo
...
udb: Have loaded Undo Recording:
udb:     example.undo
udb: Note that the debuggee is currently at the beginning of
udb: the recording. You can use the "continue" command to
udb: run to the end of the recording.
(udb) backtrace
#0  0x00000000004028e7 in ?? ()
#1  0x00007f9834695ec5 in ?? ()
#2  0x0000000000000000 in ?? ()

And using the symbol file command to load the debug information gives:

(udb) symbol-file test.debug
Reading symbols from a.debug...done.
(udb) backtrace
#0  0x00000000004028e7 in main () at test.c:80
(udb)