API reference#

pw_emu: Flexible emulators frontend

pw_emu.frontend.Emulator#

class pw_emu.frontend.Emulator(wdir: Path, config_path: Path | None = None)#

Launches, controls and interacts with an emulator instance.

__init__(wdir: Path, config_path: Path | None = None) None#
cont() None#

Resumes the emulator’s execution.

get_channel_addr(name: str) tuple#

Returns a pair of (host, port) for the channel. Raises InvalidChannelType if this is not a TCP channel.

get_channel_path(name: str) str#

Returns the channel path. Raises InvalidChannelType if this is not a pty channel.

get_channel_stream(name: str, timeout: float | None = None) RawIOBase#

Returns a file object for a given host-exposed device.

If timeout is None than reads and writes are blocking. If timeout is 0 the stream is operating in non-blocking mode. Otherwise read and write will timeout after the given value.

get_channel_type(name: str) str#

Returns the channel type

Currently pty and tcp are the only supported types.

get_channels() list[str]#

Returns the list of available channels.

get_gdb_cmd() list[str]#

Returns the gdb command for current target.

get_gdb_remote() str#

Returns a string that can be passed to the target remote gdb command.

get_property(path: str, prop: str) Any#

Returns the value of an emulator’s object property.

list_properties(path: str) list[dict]#

Returns the property list for an emulator object.

The object is identified by a full path. The path is target-specific and the format of the path is backend-specific.

QEMU path example: /machine/unattached/device[10]

renode path example: sysbus.uart

reset() None#

Performs a software reset.

run_gdb_cmds(commands: list[str], executable: str | None = None, pause: bool = False) CompletedProcess#

Connects to the target and runs the given commands silently in batch mode.

executable is optional but may be required by some gdb commands.

If pause is set, execution stops after running the given commands.

running() bool#

Checks if the main emulator process is already running.

set_emu(emu: str) None#

Sets the emulator type for this instance.

set_property(path: str, prop: str, value: Any) None#

Sets the value of an emulator’s object property.

start(
target: str,
file: Path | None = None,
pause: bool = False,
debug: bool = False,
foreground: bool = False,
args: str | None = None,
) None#

Starts the emulator for the given target.

If file is set the emulator loads the file before starting.

If pause is True the emulator pauses until the debugger is connected.

If debug is True the emulator runs in the foreground with debug output enabled. This is useful for seeing errors, traces, etc.

If foreground is True the emulator runs in the foreground, otherwise it starts in daemon mode. Foreground mode is useful when there is another process controlling the emulator’s life cycle, e.g. cuttlefish.

args are passed directly to the emulator.

stop()#

Stop the emulator.

pw_emu.frontend.TemporaryEmulator#

class pw_emu.frontend.TemporaryEmulator(config_path: Path | None = None, cleanup: bool = True)#

Temporary emulator instances.

Manages emulator instances that run in temporary working directories. The emulator instance is stopped and the working directory is cleared when the with block completes.

It also supports interoperability with the pw_emu cli, e.g. starting the emulator with the CLI and then controlling it from the Python API.

Usage example:

# programatically start and load an executable then access it
with TemporaryEmulator() as emu:
    emu.start(target, file)
    with emu.get_channel_stream(chan) as stream:
        ...
# or start it form the command line then access it
with TemporaryEmulator() as emu:
    build.bazel(
        ctx,
        "run",
        exec_path,
        "--run_under=pw emu start <target> --file "
    )
    with emu.get_channel_stream(chan) as stream:
        ...
__init__(config_path: Path | None = None, cleanup: bool = True) None#

pw_emu.core.Config#

class pw_emu.core.Config(config_path: Path | None = None, target: str | None = None, emu: str | None = None)#

Get and validate options from the configuration file.

__init__(config_path: Path | None = None, target: str | None = None, emu: str | None = None) None#

Loads the emulator configuration.

If no configuration file path is given, the root project configuration is used.

This method set ups the generic configuration (e.g. gdb).

It loads emulator target files and gathers them under the targets key for each emulator backend. The targets settings in the configuration file takes precedence over the loaded target files.

get(keys: list[str], optional: bool = True, entry_type: Type | None = None) Any#

Gets a config entry.

keys identifies the config entry, e.g. ['targets', 'test-target'] looks in the config dictionary for ['targets']['test-target'].

If the option is not found and optional is True it returns None if entry_type is None or a new (empty) object of type entry_type.

If the option is not found and optional is False it raises ConfigError.

If entry_type is not None it checks the option to be of that type. If it is not it will raise ConfigError.

get_emu(keys: list[str], optional: bool = True, entry_type: Type | None = None) Any#

Gets a config option starting at [emu].

get_target(keys: list[str], optional: bool = True, entry_type: Type | None = None) Any#

Gets a config option starting at ['targets'][target].

get_target_emu(keys: list[str], optional: bool = True, entry_type: Type | None = None) Any#

Gets a config option starting at ['targets'][target][emu].

set_target(target: str) None#

Sets the current target.

The current target is used by the pw_emu.core.Config.get_target() method.

pw_emu.core.Handles#

class pw_emu.core.Handles(emu: str, config: str)#

Running emulator handles.

__init__(emu: str, config: str) None#
add_channel_pty(name: str, path: str) None#

Adds a pty channel.

add_channel_tcp(name: str, host: str, port: int) None#

Adds a TCP channel.

add_proc(name: str, pid: int) None#

Adds a process ID.

save(wdir: Path) None#

Saves handles to the given working directory.

set_gdb_cmd(cmd: list[str]) None#

Sets the gdb command.

set_target(target: str) None#

Sets the target.

pw_emu.core.Connector#

class pw_emu.core.Connector(wdir: Path)#

Interface between a running emulator and the user-visible APIs.

__init__(wdir: Path) None#
abstract cont() None#

Resumes the emulator’s execution.

static get(wdir: Path) Any#

Returns a connector instance for a given emulator type.

get_channel_addr(name: str) tuple#

Returns a pair of (host, port) for the channel. Raises InvalidChannelType if this is not a tcp channel.

get_channel_path(name: str) str#

Returns the channel path. Raises InvalidChannelType if this is not a pty channel.

get_channel_stream(name: str, timeout: float | None = None) RawIOBase#

Returns a file object for a given host-exposed device.

If timeout is None then reads and writes are blocking. If timeout is 0 the stream is operating in non-blocking mode. Otherwise reads and writes will timeout after the given value.

get_channel_type(name: str) str#

Returns the channel type.

get_config_path() Path#

Returns the configuration path.

get_emu() str#

Returns the emulator type.

get_gdb_cmd() list[str]#

Returns the configured gdb command.

get_logs() str#

Returns the emulator logs.

get_procs() dict[str, pw_emu.core.Handles.Proc]#

Returns the running processes indexed by the process name.

abstract get_property(path: str, prop: str) Any#

Returns the value of an emulator’s object property.

abstract list_properties(path: str) list[Any]#

Returns the property list for an emulator object.

abstract reset() None#

Performs a software reset.

running() bool#

Checks if the main emulator process is already running.

abstract set_property(path: str, prop: str, value: str) None#

Sets the value of an emulator’s object property.

stop() None#

Stops the emulator.

pw_emu.core.Launcher#

class pw_emu.core.Launcher(emu: str, config_path: Path | None = None)#

Starts an emulator based on the target and configuration file.

__init__(emu: str, config_path: Path | None = None) None#

Initializes a Launcher instance.

_config#

Global, emulator and target configuration.

abstract _get_connector(wdir: Path) Connector#

Gets a connector for this emulator type.

_handles#

Handles for processes, channels, etc.

abstract _post_start() None#

Post-start work, finalize emulator handles.

Perform any post-start emulator initialization and finalize the emulator handles information.

Typically an internal monitor channel is used to inquire information about the the configured channels (e.g. TCP ports, pty paths) and pw_emu.core.Launcher._handles is updated via pw_emu.core.Handles.add_channel_tcp(), pw_emu.core.Handles.add_channel_pty(), etc.

abstract _pre_start(
target: str,
file: Path | None = None,
pause: bool = False,
debug: bool = False,
args: str | None = None,
) list[str]#

Pre-start work, returns command to start the emulator.

The target and emulator configuration can be accessed through pw_emu.core.Launcher._config with pw_emu.core.Config.get(), pw_emu.core.Config.get_target(), pw_emu.core.Config.get_emu(), pw_emu.core.Config.get_target_emu().

static get(emu: str, config_path: Path | None = None) Any#

Returns a launcher for a given emulator type.

start(
wdir: Path,
target: str,
file: Path | None = None,
pause: bool = False,
debug: bool = False,
foreground: bool = False,
args: str | None = None,
) Connector#

Starts the emulator for the given target.

If file is set the emulator loads that file before starting.

If pause is True the emulator gets paused.

If debug is True the emulator runs in the foreground with debug output enabled. This is useful for seeing errors, traces, etc.

If foreground is True the emulator is run in the foreground otherwise it is started in daemon mode. This is useful when there is another process controlling the emulator’s life cycle, e.g. cuttlefish.

args are passed directly to the emulator.

More pw_emu docs#

Get started & guides

How to set up and use pw_emu

CLI reference

Reference details about the pw_emu command line interface

API reference

Reference details about the pw_emu Python API

Configuration

Reference details about pw_emu declarative configuration

Design

Design details about pw_emu

SEED-0108: Emulators Frontend

The RFC explaining the initial design and motivations for pw_emu

Source code

Source code for pw_emu