Skip to content

init

The Pwndbg REPL that is the interface to all debugging on LLDB.

Pwndbg has an event system that allows it to react to events in the process being debugged, such as when new executable modules get added to the its address space, when the value of memory and registers change, and pretty much all possible changes to its execution state. We'd like to have the event system work the same way under LLDB as it does under GDB.

Fortunately for us, the events types that are native to LLDB map really well to the event types in GDB and Pwndbg. Very, very unfortunately for us, however, that's basically where our luck ends.

LLDB, as of version 18, only provides two ways to capture events: registering directly with the broadcaster, or registering globally. The former is not available to us in the standard LLDB REPL, as we don't get access to the process object until after it's been launched1. Likewise for the latter, as the interactive debugger will register to receive the global process state change events before everyone else, and LLDB doesn't allow for multiple listeners for the same event bits in the same event class2.

This leaves us with handling process management ourselves as the only option we really have to implement event dispatch in Pwndbg. Easy, right? We can just hijack the commands that deal with target and process creation, and leave everything else untouched. Unfortunately for us, again, shadowing builtin commands is simply not allowed3.

So, really, all that's left for us is either implement our own REPL, or get rid of the event system.

LLDB_EXCLUSIVE = [('script', lambda cmd: cmd.startswith('sc') and 'script'.startswith(cmd)), ('expression', lambda cmd: cmd.startswith('e') and 'expression'.startswith(cmd))] module-attribute

continue_ap = argparse.ArgumentParser(add_help=False) module-attribute

continue_unsupported = ['ignore-count'] module-attribute

gdb_remote_ap = argparse.ArgumentParser(add_help=False) module-attribute

process_connect_ap = argparse.ArgumentParser(add_help=False) module-attribute

process_launch_ap = argparse.ArgumentParser(add_help=False) module-attribute

process_launch_unsupported = ['disable-aslr', 'script-class', 'environment', 'plugin', 'shell-expand-args', 'arch', 'shell', 'stderr', 'stdin', 'structured-data-key', 'no-stdio', 'stdout', 'tty', 'structured-data-value', 'working-dir'] module-attribute

show_tip = pwndbg.config.add_param('show-tips', True, 'whether to display the tip of the day on startup') module-attribute

target_create_ap = argparse.ArgumentParser(add_help=False) module-attribute

target_create_unsupported = ['sysroot', 'arch', 'build', 'core', 'no-dependents', 'platform', 'remote-file', 'symfile', 'version'] module-attribute

EventRelay

Bases: EventHandler

The event system that is sensible for the REPL process driver to use isn't an exact match with the one used by the rest of Pwndbg. They're close, but there's a bit of work we have to do to properly convey certain events.

dbg = dbg instance-attribute

ignore_resumed = 0 instance-attribute

__init__(dbg)

created()

exited()

modules_loaded()

resumed()

suspended()

continue_process(driver, args, dbg)

Continues the execution of a process.

gdb_remote(driver, relay, args, dbg)

Like process_connect, but more lenient with the remote URL format.

lex_args(args)

Splits the arguments, respecting quotation marks.

make_pty()

We need to make a pseudo-terminal ourselves if we want the process to handle naturally for the user. Returns a tuple with the filaname and the file descriptor if successful.

parse(args, parser, unsupported)

Parses a list of string arguments into an object containing the parsed data.

process_connect(driver, relay, args, dbg)

Connects to the given remote process.

process_launch(driver, relay, args, dbg)

Launches a process with the given arguments.

run(startup=None, debug=False)

Runs the Pwndbg REPL under LLDB. Optionally enters the commands given in startup as part of the startup process.

show_greeting()

Show the Pwndbg greeting, the same way the GDB version of Pwndbg would. This one is considerably simpler than the GDB version, however, as we control the lifetime of the program, we know exactly when the greeting needs to be shown, so we don't bother with any of the lifetime checks.

target_create(args, dbg)

Creates a new target, registers it with the Pwndbg LLDB implementation, and sets up listeners for it.