3 Plugin architecture
snare edited this page 2016-04-09 21:56:27 +10:00

Plugin architecture

Voltron uses a plugin architecture for implementing debugger host suppprt, API methods, and UI views. Much of the core of Voltron is implemented using this plugin architecture, and it can also be used to extend Voltron to support new debugger hosts and add new custom API methods and views.

Types of plugins

There are four types of plugins supported in Voltron.

View plugins

View plugins provide views that can be run from the voltron command-line entry point. Typically these are, as are the included views, terminal-based. These plugins define a view class, which is instantiated and run by the command-line entry point program. See the included views in voltron/plugins/views/*.py.

More information on building view plugins can be found here.

API plugins

API plugins implement an API method which is accessible via the various configured listeners. These define a request and response class, and interact with a package-wide instance of one of the above debugger adaptor plugins. When an incoming API request is received, its request field is used to look up the appropraite API plugin to handle the request. See the included core API plugins in voltron/plugins/api/*.py.

More information on building API plugins can be found here.

Web plugins

Web plugins provide views or other features that are accessible via the embedded web server. They typically define a Flask app or just provide a directory of static which is served by the embedded web server, and use JavaScript to talk to the API back end. No web plugins are included in the core at the moment, but see the examples directory.

More information on building web plugins can be found here.

See also the voltron-web package, which implements a basic web UI for Voltron that is useful for testing API requests.

Debugger adaptor plugins

Debugger adaptor plugins implement the majority of the support for a given debugger host platform. There are two core debugger adaptor plugins included with Voltron which provide support for LLDB and GDB. These plugins both implement a common set of methods that are used by the core API plugins. If you want to add support for a new debugger host, you'll need to look at the code for one of these plugins in voltron/plugins/debugger/{dbg_lldb|dbg_gdb}.py and implement the same methods. They are reasonably well-documented and should provide a reasonable starting point.

More information on building debugger adaptor plugins can be found here.

Anatomy of a plugin

The bare minimum for a Voltron plugin is a Python module containing a subclass of one of the plugin classes - APIPlugin, DebuggerAdaptorPlugin, ViewPlugin or WebPlugin (see voltron/plugin.py). The plugin class is the top-level object in a plugin. It usually has a name and references to other resources in the plugin. For example an APIPlugin has a name like wait, and references to an APIRequest subclass and an APIResponse subclass used to handle the API request. This is what a sample API plugin class might look like:

class SampleAPIPlugin(APIPlugin):
    name = 'sample'
    request_class = SampleAPIRequest
    response_class = SampleAPIResponse

The plugin class itself typically does not contain any methods, it is just used as the top-level object to reference a plugin. The common parent of all the plugin classes, Plugin (in Scruffy) utilises a metaclass, PluginRegistry, to collect all its subclasses as they're loaded by Scruffy. Voltron implements its own PluginManager class which is used as an interface to the PluginRegistry.

Installing plugins

User plugins directory

When Voltron is loaded into the debugger, the Scruffy environment is initialised and plugins are discovered in two locations: the plugins directory within the voltron package, and the user plugins directory in ~/.voltron/plugins. The latter is where custom plugins should be installed. These directories are searched recursively, and any Python module discovered within is loaded. Classes in these modules that inherit from one of the Voltron plugin classes will be recognised and loaded into the plugin registry.

Registering programmatically

Plugins can also be loaded and registered programmatically. This may be useful for custom clients that aren't using the standard view architecture, or for loading plugins from the debugger's init script.

After Voltron has been loaded into the debugger, a package-wide shared instance of the PluginManager class will be available at voltron.plugin.pm. This instance can be used to programmatically register plugins like so:

from myplugin import MyAPIPlugin, MyAPIRequest, MyAPIResponse
voltron.plugin.pm.register_plugin(MyAPIPlugin)

This will make an instance of the plugin class available through the shared PluginManager instance.

Accessing plugins

The shared PluginManager instance voltron.plugin.pm can also be used to access plugins programmatically from your custom plugins or Voltron clients. There are convenience methods in voltron/plugin.py to make this easier.

For example, to instantiate an API request:

req = api_request('disassemble', count=16)

An API response:

res = api_response('disassemble', disassembly="push r...")

To allocate a view class:

view = view('register')

To allocate a new debugger adaptor instance (this would only really be useful if you were building another tool on top of Voltron):

adaptor = debugger_adaptor('lldb')

If you want to access the plugin classes themselves directly, you can call the PluginManager methods:

plugin = voltron.plugin.pm.api_plugin_for_request('wait')

plugin = voltron.plugin.pm.debugger_plugin_for_host('lldb')

plugin = voltron.plugin.pm.view_plugin_with_name('register')

plugin = voltron.plugin.pm.web_plugin_with_name('angularview')

The package-wide debugger adaptor is located at voltron.debugger. This can be used from your custom API plugins to query the debugger host back end. See some of the core API plugins and the included LLDB and GDB host adaptor plugins for usage.