Plugin interface

Talvos provides a simple plugin interface to enable a wide range of dynamic analysis tools to be created. This interface provides a callback mechanism by which a Talvos plugin can receive notifications when various events occur during emulation.

A Talvos plugin should be created as a dynamic library. During initialization, Talvos will load any libraries listed in the TALVOS_PLUGINS environment variable (semicolon separated). These libraries should each contain an implementation of a class which extends the talvos::Plugin base class, overriding any callback methods that are interesting to the plugin. See the documentation for the Plugin class for a full list of available callback methods.

A Talvos plugin library should also provide a function with the following signature:

extern "C"
{
  Plugin *talvosCreatePlugin(talvos::Device *Dev);
}

This function will be called when a Talvos device is created, and should return an instance of the plugin’s derived Plugin class. Additionally, a plugin library can implement the following cleanup function which is called when a Talvos device is destroyed:

extern "C"
{
  void talvosDestroyPlugin(talvos::Plugin *P);
}

If a Plugin is not thread-safe, it should indicate this by overriding the isThreadSafe() function and returning false.

Example (instruction tracing)

The following code listing is a complete example of a Talvos plugin that prints each instruction executed during emulation, along with the global invocation ID.

#include <iostream>

#include "talvos/Device.h"
#include "talvos/Instruction.h"
#include "talvos/Invocation.h"
#include "talvos/Plugin.h"

using namespace talvos;

class Tracer : public Plugin
{
public:
  void instructionExecuted(const Invocation *Invoc,
                           const Instruction *Inst) override
  {
    std::cout << Invoc->getGlobalId() << ": ";
    Inst->print(std::cout);
    std::cout << std::endl;
  }
};

extern "C"
{
  Plugin *talvosCreatePlugin(Device *Device)
  {
    return new Tracer;
  }

  void talvosDestroyPlugin(Plugin *P)
  {
    delete P;
  }
}

On a Unix system, this is compiled with the following command (assuming that the Talvos include/ and lib/ directories are in the relevant search paths):

c++ -std=c++14 tracer.cpp -shared -o libtracer.so -ltalvos

Emulating a simple vector addition shader with this plugin loaded provides the following output:

$ TALVOS_PLUGINS=libtracer.so talvos-cmd vecadd.tcf
(0,0,0):   %24 = OpAccessChain %19 %2 %21
(0,0,0):   %25 = OpLoad %12 %24
(0,0,0):   %26 = OpAccessChain %13 %9 %21 %25
(0,0,0):   %27 = OpLoad %12 %26
(0,0,0):   %28 = OpAccessChain %13 %10 %21 %25
(0,0,0):   %29 = OpLoad %12 %28
(0,0,0):   %30 = OpIAdd %12 %29 %27
(0,0,0):   %31 = OpAccessChain %13 %11 %21 %25
(0,0,0):         OpStore %31 %30
(0,0,0):         OpReturn
(1,0,0):   %24 = OpAccessChain %19 %2 %21
(1,0,0):   %25 = OpLoad %12 %24
(1,0,0):   %26 = OpAccessChain %13 %9 %21 %25
(1,0,0):   %27 = OpLoad %12 %26
(1,0,0):   %28 = OpAccessChain %13 %10 %21 %25
(1,0,0):   %29 = OpLoad %12 %28
(1,0,0):   %30 = OpIAdd %12 %29 %27
(1,0,0):   %31 = OpAccessChain %13 %11 %21 %25
(1,0,0):         OpStore %31 %30
(1,0,0):         OpReturn
# etc