ROSE  0.11.145.0
Classes | Public Types | Protected Member Functions | List of all members
Rose::BinaryAnalysis::Partitioner2::Engine Class Reference

Description

Base class for engines driving the partitioner.

The Partitioner2::Engine is an abstract base class whose derived classes implement the algorithms for creating functions, basic blocks, instructions, control flow graphs (CFGs), address usage maps (AUMs), static data blocks, and everything else that can be stored in a Partitioner.

Although subclasses can be instantiated directly, it is often easier to do so through the base class's factory methods. For instance, a tool that operates on various kinds of specimens would want to decide what engine subclass to instantiate based on the types of specimens that are being analyzed. The ROSE library defines a few sublcasses, and the factory mechanism allows external tools to register their own subclasses.

Factories

Using the engine factories is a two-step process: first the subclasses are registered with the ROSE library, then the ROSE library chooses which engine should be instantiated and does so.

A subclass is registered by instantiating a "factory instance" of the subclass and calling registerFactory, which takes shared ownership of the factory instance. Additional member functions such as deregisterFactory and registeredFactories can be used to manipulate the factory list. The engine types that are built into ROSE are registered automatically and appear at the beginning of the list.

To directly instantiate an instance of a subclass without going through the factory mechanism, one calls the static instance method of the subclass. The instance method allocates a new instance in the heap and returns a shared-ownership pointer to the new instance. This is how almost all binary analysis works in ROSE.

On the other hand, to instantiate an engine using the factory method, one calls the Engine::forge static member function. The words "forge" and "factory" both start with "f" as a reminder that they go together in this API. The forge method will scan the list of registered factories from the end toward the beginning and the first factory whose matchFactory predicate returns true will be the type of engine to be used. The engine actually returned is not the registered factory directly, but the result of calling instanceFromFactory on the registered factory.

Command-line parsing

Every engine instance has a settings property. Currently this is shared by all engine types, but in the future we may make this more extensible. Every engine supports ROSE's command-line parsing (Sawyer::CommandLine) to modify its settings from the command-line. There is a chicken-or-egg dilemma with command-line parsing: in order to choose the correct engine type, we need to find the command-line positional arguments that describe the specimen; in order to find the positional arguments, we need to be able to accurately parse the command-line switches; in order to parse the engine-specific command-line switches, we need to know which engine will be used for the parsing.

The solution that ROSE uses isn't perfect, but works well in practice. Each engine type is able to register its command-line switches as a switch group within a command-line parser. As long as the switches don't conflict with each other, or can be disambiguated to not conflict, we're able to parse the command-line switches as the union of all the switches from all known engine types. Switches can be disambiguated by giving each engine type its own switch group name (i.e., optional switch prefix). For example, the JVM engine might use "--[jvm-]foo" while the binary machine engine uses "--[binary-]foo".

In order to choose a matching factory from the list of factories, ROSE constructs a temporary command-line parser that handles the switches from all known engines and binds the parser to the registered factories (i.e., the presence of a switch modifies the settings in the factory instance). ROSE then parses the command-line to find the specimen positional arguments which it uses to choose a factory instance. Once the factory instance is chosen, ROSE instantiates a regular instance from the factory and constructs a new command-line parser with just that engine's switches, and bound to the engine being returned. Later, when the tool parses the command-line for real and applies the parse result, the returned engine's settings are updated.

Although this mechanism for handling engine-specific command-line switches is not perfect, we think it will provide a means by which tools can define their own command-line switches, and other factories besides Partitioner2::Engine can operate in similar ways.

Basic usage

An engine drives the process of building a Partitioner2::Partitioner which is then used as an efficient means of obtaining information that's needed during analysis. Although every engine can operate in a different way, there's a common API that's intended to be quite general. The engine API is divided into abstraction layers. The most abstract layer consists of functions that do the most things in one step, from parsing of command-lines to generation of the Partitioner and/or abstract syntax tree (AST). The next layer of less abstract functions does smaller parts, such as parsing containers like ELF or PE, loading parts of specimen files into memory, finding related specimens like shared libraries, linking specimens together into a common address space, organizing instructions into basic blocks and functions, creating an AST, etc. Finally, at the least level of abstraction, many of the functions are specific enough to be defined only in subclasses.

Here's an example of basic usage of the engine to instantiate and populate a Partitioner that can be used for analysis. First, the tool needs to define the necessary classes, which it can do by including either the top-level "Partitioner2.h" header, or the headers for the individual Partitioner2 types.

#include <rose.h>
#include <Rose/BinaryAnalysis/Partitioner2.h>
using namespace Rose;

Most tools, after initializing the ROSE library, will create a command-line parser to parse the tool's own switches.

int main(int argc, char *argv[]) {
ROSE_INITIALIZE;
std::string purpose = "disassembles a binary specimen";
std::string description =
"This tool disassembles the specified specimen and presents the "
"results as a pseudo assembly listing, that is, a listing intended "
"for human consumption rather than assembly.";
ToolSettings settings;
Sawyer::CommandLine::Parser parser = buildSwitchParser(settings);

In order for the tool to choose the correct engine, it needs to be able to find the positional command-line arguments that describe the specimen. The tool could do all its own command-line parsing and adjust the values in a Partitioner2::Settings object which it ultimately copies into an engine instance, or it could use ROSE's command-line parsing mechanism. We'll show the latter since we already started creating such a parser above.

Since we're using ROSE to parse the command-line, we pass the command-line and our partial command-line parser to the forge method like this:

P2::Engine::Ptr engine = P2::Engine::forge(argc, argv, parser);

When the forge call returns, it also adjusts the parser so it knows how to parse the command-line switches that are specific to the returned engine type, and those switches are bound to the settings in that returned engine instance. Thus the tool is now able to parse the command-line, update the settings in the engine, and obtain the positional arguments that describe the specimen.

std::vector<std::string> specimen = parser.parse(argc, argv).apply().unreachedArgs();

Finally, now that the engine has been obtained, the tool can cause the engine to produce a fully initialized Partitioner, or do any of the other things that an engine is designed to do.

P2::Partitioner::Ptr partitioner = engine.partition(specimen);

On the other hand, if you perform your own command-line parser then you'll have the engine settings and the specimen arguments already parsed, in which case you can create the engine with fewer steps:

int main(int argc, char *argv[]) {
P2::Engine::Settings settings;
std::vector<std::string> specimen = parseCommandLine(settings);
auto engine = P2::Engine::forge(specimen);
auto partitioner = engine->partition(specimen);

See also

See also Partitioner2::EngineBinary, Partitioner2::EngineJvm, and the documentation for non-ROSE engines.

Definition at line 155 of file Partitioner2/Engine.h.

#include <Rose/BinaryAnalysis/Partitioner2/Engine.h>

Inheritance diagram for Rose::BinaryAnalysis::Partitioner2::Engine:
Inheritance graph
[legend]
Collaboration diagram for Rose::BinaryAnalysis::Partitioner2::Engine:
Collaboration graph
[legend]

Classes

class  AllPositionalArguments
 Return all positional arguments as the specimen. More...
 
class  BasicBlockFinalizer
 
class  CodeConstants
 
class  Exception
 Errors from the engine. More...
 
class  FirstPositionalArguments
 Up to first N arguments are the specimen. More...
 
class  GroupedPositionalArguments
 Nth group of arguments are the specimen. More...
 
class  PositionalArgumentParser
 How to parse positional command-line arguments. More...
 
struct  Settings
 Settings for the engine. More...
 

Public Types

using Ptr = EnginePtr
 Shared ownership pointer. More...
 

Protected Member Functions

 Engine ()=delete
 Default constructor. More...
 
 Engine (const Engine &)=delete
 
Engineoperator= (const Engine &)=delete
 
 Engine (const std::string &name, const Settings &settings)
 Allocating instance constructors are implemented by the non-abstract subclasses. More...
 

Additional Inherited Members

- Public Member Functions inherited from Sawyer::SharedObject
 SharedObject ()
 Default constructor. More...
 
 SharedObject (const SharedObject &)
 Copy constructor. More...
 
virtual ~SharedObject ()
 Virtual destructor. More...
 
SharedObjectoperator= (const SharedObject &)
 Assignment. More...
 
- Public Member Functions inherited from Sawyer::SharedFromThis< Engine >
SharedPointer< Engine > sharedFromThis ()
 Create a shared pointer from this. More...
 
SharedPointer< const Engine > sharedFromThis () const
 Create a shared pointer from this. More...
 

Member Typedef Documentation

Shared ownership pointer.

Definition at line 161 of file Partitioner2/Engine.h.

Constructor & Destructor Documentation

Rose::BinaryAnalysis::Partitioner2::Engine::Engine ( )
protecteddelete

Default constructor.

Constructor is deleted and class noncopyable.

Rose::BinaryAnalysis::Partitioner2::Engine::Engine ( const std::string &  name,
const Settings settings 
)
protected

Allocating instance constructors are implemented by the non-abstract subclasses.


The documentation for this class was generated from the following file: