Automation API: extending UDB

The debugger_extensions package provides functionalities which can be used from inside the debugger.

Most of the functionalities as provided through the udb object (see the documentation on its interface for details) in the debugger_extensions module, but the module also provides other utility functions and types.

Inferface for the udb object

The following classes represent the interface of the udb object in the debugger_extensions module and they cannot be instantiated by the user.

class debugger_extensions.controller.Udb

The main component to control UDB.

get_event_log_extent()

Gets the range of bbcounts available in recorded history.

Returns:A named tuple representing the range of bbcounts. The first element (also accessible as min_bbcount) is the oldest point in recorded history. The second element (also accessible as max_bbcount) is the most recent point in recorded history.
get_signal_info()

Returns the details of the latest signal sent to the debugged program.

Returns:An object describing the latest signal delivered or None if this information is not available, for instance because no program is running.
Return type:(debugger_extensions.SigInfo | None)
class debugger_extensions.controller.Time

Groups methods related to times in execution history.

Access this as udb.time. For instance, to go to the end of the execution history, do:

from undodb.debugger_extensions import udb

udb.time.goto_end()

For details on how UDB represents time, see UDB time notation.

auto_reverting()

Context manager to automatically revert to the current time at the beginning of the block when execution leaves it.

This can be used to do some goto or similar operations and then revert the time:

with udb.time.auto_reverting():
    udb.time.goto_start()
    ...
    udb.time.goto(...)
    ...
    ...
get() → udbpy.gdb_extensions.udb_time.RecordingTime

Gets the current time in execution history.

Returns:The current time in execution history.
Return type:debugger_extensions.RecordingTime
goto(time: Union[udbpy.gdb_extensions.udb_time.RecordingTime, int]) → None

Goes to the specified time in execution history.

Parameters:time (debugger_extensions.RecordingTime | int) – The time to go to. It can be either a debugger_extensions.RecordingTime or, for convenience, just an integer representing the bbcount.
goto_end()

Go to the latest time in recording history.

goto_start()

Goes to the earliest time in recording history.

class debugger_extensions.controller.Recording

Groups methods related to recording files.

Access this as udb.recording. For instance, to load a recording, do:

from undodb.debugger_extensions import udb

udb.recording.load('recording_file_name.undo')
load(recording_filename: str) → None

Loads the recording for the execution of a program from the specified file.

This method corresponds to the functionality provided by the uload command.

Parameters:recording_filename (str) – The path of the file to load.
Raises:debugger_extensions.LoadError – If the loading of the recording fails.
save(recording_filename: str) → None

Saves the current execution history to the specified file.

This method corresponds to the functionality provided by the usave command.

Parameters:recording_filename (str) – The path of the recording file to load.
Raises:SaveError – If the saving fails.

The debugger_extensions package

Package for code available only to extensions running inside UDB.

debugger_extensions.udb

The main object used to access UDB functionalities, see the documentation on its interface.

class debugger_extensions.RecordingTime

A time in execution history.

For details on how UDB represents time, see UDB time notation.

bbcount

The basic block count (bbcount) for this time.

Type:int
pc

The PC (program counter) for this time or None if the PC is not specified.

Type:int
to_string(include_pc: bool = True, extend_pc: bool = False) → str

Converts this time into a string suitable for displaying to the user.

This is equivalent to using str, unless any argument is specified.

Parameters:
  • include_pc (bool) – If true, then the returned string contains the PC, if it’s available, otherwise the PC is omitted.
  • extend_pc (bool) – If true, then the PC part of the return values is padded with zeroes to make all the PCs from different times the same width.
Returns:

A string representation of the time.

Return type:

str

class debugger_extensions.SigInfo

Information about a signal delivered to a program.

This class reflects the siginfo_t C structure (see man 2 sigaction), but also contain UDB specific fields.

si_signo

The number of the received signal.

Type:int
si_code

Extra information about the signal whose value depends on the value of si_signo. See the sigaction man page for details.

Type:int
from_event_replay

True if the signal was replayed from an event that happened during the recording of the program. False if the signal corresponds to a real signal delivered to the program. This is useful, for instance, to distinguish if a SIGINT corresponds the the user pressing CTRL-C while replaying a recording or if the signal was recorded at execution time.

Type:bool
exception debugger_extensions.NotRunningError(msg: Optional[str] = None)

An exception raised when trying to execute an operation which requires the debuggee to be running, but is not currently running.

exception debugger_extensions.LoadError(filename: str, msg: str)

An error occurred while trying to load a recording.

exception debugger_extensions.SaveError(filename: str, msg: str)

An error occurred while trying to save a recording.

Utilities built around the gdb module

Utility functions built around GDB and the gdb module.

debugger_extensions.debugger_utils.execute_to_string(cmd: str) → str

Wrapper for the gdb.execute(..., to_string=True) function but dealing correctly with edge cases like echo mode.

debugger_extensions.debugger_utils.suspend_breakpoints(normal_breakpoints=True, watchpoints=True)

Context manager to temporarily disable breakpoints.

The breakpoints which were previously enabled are automatically restored when the context manager block is left.

It is safe to create or delete breakpoints inside the block.

By default, all types of breakpoints, that is, both watchpoints and normal breakpoints, are disabled. See the normal_breakpoints and watchpoints arguments to change this behaviour.

Example:

with debugger_utils.suspend_breakpoints():
    # No breakpoints (of any type) here.
    ...

# Previosuly enabled breakpoints restored here.

To disable only normal breakpoints but not watchpoints:

with debugger_utils.suspend_breakpoints(watchpoints=False):
    # No normal breakpoints here, but watchpoints still enabled.
    ...

# Normal breakpoints restored here. The watchpoints were never affected.
Parameters:
  • normal_breakpoints (bool) – Whether normal breakpoints (both software and hardware) should be disabled or not.
  • watchpoints (bool) – Whether watchpoints (all types, including read, write and read/write ones) should be disabled.
debugger_extensions.debugger_utils.temporary_parameter(parameter, temporary_value)

Context manager that executes its block with the parameter called parameter (see gdb.parameter) temporarily set to temporary_value.

For instance, to temporarily disable pagination and then restore it to its initial value at the end of the block execution, do:

with debugger_utils.temporary_parameter('pagination', False):
    ...

Controlling input and output

Utility functions to deal with I/O in the debugger.

class debugger_extensions.debugger_io.CollectOutput

Context manager that captures all the output produced during the execution of its block. The accumulated output is acessible via the output property.

The context manager redirects both the output produced by UDB directly and direct writes to sys.stdout or sys.stderr.

For instance:

with CollectOutput() as collector:
    gdb.execute('echo He')
    print(collector.output) # Will print "He"

    gdb.execute('echo llo')
    print(collector.output) # Will print "Hello"

print(collector.output) # Will print "Hello"

It’s safe to nest multiple CollectOutput instances. The output will be collected only by the most nested instance of CollectOutput:

with CollectOutput() as outer:
    gdb.execute('echo Hello ')

    with CollectOutput() as inner:
        gdb.execute(r'echo Something else')

    gdb.execute('echo world')

print(outer.output) # Will print "Hello world"
print(inner.output) # Will print "Something else"

If you need the output to go to a file, use RedirectOutput instead.

output

Get the output collected up so far.

It’s safe to access this both within the with block and after the block terminated.

class debugger_extensions.debugger_io.RedirectOutput(path: str, overwrite: bool = True)

Context manager that redirects all the output produced during the execution of its block to a file.

The context manager redirects both the output produced by UDB directly and direct writes to sys.stdout or sys.stderr.

For instance:

with RedirectOutput('some_file.txt'):
    gdb.execute('echo Hello\n')

Will write Hello\n to some_file.txt.

It’s safe to nest multiple RedirectOutput instances. The output will be redirected to the file specified by the most nested instance of RedirectOutput

If you want to redirect the output for later use in your code but you don’t need it to be in a file, use CollectOutput instead.

Parameters:
  • path (str) – Path to a file to redirect output to.
  • overwrite (bool) – Whether to overwrite the content of the file or not.
debugger_extensions.debugger_io.redirect_to_launcher_output()

Context manager that redirects all the output produced during the execution of its block to the standard output of the UdbLauncher.

This is useful to discard all the output from a UDB launched through the UdbLauncher except for the parts printed inside this context manager.

For instance, you could start UDB like this:

launcher = udb_launcher.UdbLauncher()
launcher.add_extension('code_to_run_inside_undodb')
launcher.run_debugger(output=os.devnull)

This makes all the normal output from UDB be redirected to /dev/null. If you have some output you want to preserve coming from the extension running inside UDB, you can do this:

with launcher.redirect_to_launcher_output():
    print('This will come out instead of ending up in /dev/null!')
    gdb.execute('echo And this too!\n')

If UDB was not launched through UdbLauncher, then the output is not redirected and is printed to the normal standard output.