Skip to content

Commit

Permalink
Add instructionAPI/Visit.h
Browse files Browse the repository at this point in the history
  • Loading branch information
hainest committed Apr 3, 2024
1 parent 912e970 commit d358cb1
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 108 deletions.
95 changes: 95 additions & 0 deletions docs/instructionAPI/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,98 @@ memory values into an operand, regardless of whether those values are
known at the time an instruction is decoded. More details on this
mechanism may be found in Section `3.5 <#sec:expression>`__.

Visitor Paradigm
----------------

An alternative to the bind/eval mechanism is to use a *visitor*
over an expression tree. The visitor concept applies a user-specified
visitor class to all nodes in an expression tree (in a post-order
traversal). The visitor paradigm can be used as a more efficient
replacement for bind/eval, to identify whether an expression has a
desired pattern, or to locate children of an expression tree.

A user provides implementations of the four ``visit`` methods. When
applied to an ``Expression`` (via the ``Expression::apply`` method) the
InstructionAPI will perform a post-order traversal of the tree, calling
the appropriate ``visit`` method at each node.

As a simple example, the following code prints out the name of each
register used in an ``Expression``:


.. code-block:: cpp
#include "Instruction.h"
#include "Operand.h"
#include "Expression.h"
#include "Register.h"
#include "Visitor.h"
#include <iostream>
using namespace std;
using namespace Dyninst;
using namespace InstructionAPI;
class PrintVisitor : public Visitor {
public:
PrintVisitor() {};
~PrintVisitor() {};
virtual void visit(BinaryFunction* b) {};
virtual void visit(Immediate* i) {};
virtual void visit(RegisterAST* r) {
cout << "\tVisiting register " << r->getID().name() << endl;
}
virtual void visit(Dereference* d) {};
};
void printRegisters(Instruction::Ptr insn) {
PrintVisitor pv;
std::vector<Operand> operands;
insn->getOperands(operands);
// c++11x allows auto to determine the type of a variable;
// if not using c++11x, use 'std::vector<Operand>::iterator' instead.
// For gcc, use the -std=c++0x argument.
for (auto iter = operands.begin(); iter != operands.end(); ++iter) {
cout << "Registers used for operand" << endl;
(*iter).getValue()->apply(&pv);
}
}
Visitors may also set and use internal state. For example, the following
visitor (presented without surrounding use code) matches x86 and x86-64
instructions that add 0 to a register (effectively a noop).

.. code-block:: cpp
class nopVisitor : public Visitor
{
public:
nopVisitor() : foundReg(false), foundImm(false), foundBin(false), isNop(true) {}
virtual ~nopVisitor() {}
bool foundReg;
bool foundImm;
bool foundBin;
bool isNop;
virtual void visit(BinaryFunction*)
{
if (foundBin) isNop = false;
if (!foundImm) isNop = false;
if (!foundReg) isNop = false;
foundBin = true;
}
virtual void visit(Immediate *imm)
{
if (imm != 0) isNop = false;
foundImm = true;
}
virtual void visit(RegisterAST *)
{
foundReg = true;
}
virtual void visit(Dereference *)
{
isNop = false;
}
};
117 changes: 19 additions & 98 deletions docs/instructionAPI/public/Visitor.h.rst
Original file line number Diff line number Diff line change
@@ -1,109 +1,30 @@
.. _`sec:Visitor.h`:

Visitor.h
=========
#########

.. cpp:namespace:: Dyninst::InstructionAPI

Visitor Paradigm
----------------

An alternative to the bind/eval mechanism is to use a *visitor*
over an expression tree. The visitor concept applies a user-specified
visitor class to all nodes in an expression tree (in a post-order
traversal). The visitor paradigm can be used as a more efficient
replacement for bind/eval, to identify whether an expression has a
desired pattern, or to locate children of an expression tree.

A visitor is a user-defined class that inherits from the ``Visitor``
class defined in ``Visitor.h``. That class is repeated here for
reference:

class Visitor public: Visitor() virtual  Visitor() virtual void
visit(BinaryFunction\* b) = 0; virtual void visit(Immediate\* i) = 0;
virtual void visit(RegisterAST\* r) = 0; virtual void
visit(Dereference\* d) = 0;;

A user provides implementations of the four ``visit`` methods. When
applied to an ``Expression`` (via the ``Expression::apply`` method) the
InstructionAPI will perform a post-order traversal of the tree, calling
the appropriate ``visit`` method at each node.

As a simple example, the following code prints out the name of each
register used in an ``Expression``:


.. code-block:: cpp
.. cpp:class:: Visitor

#include "Instruction.h"
#include "Operand.h"
#include "Expression.h"
#include "Register.h"
#include "Visitor.h"
#include <iostream>
**Performs postfix-order traversal of an AST**

using namespace std;
using namespace Dyninst;
using namespace InstructionAPI;
.. cpp:function:: virtual ~Visitor() = default
.. cpp:function:: Visitor& operator=(const Visitor&) = default
.. cpp:function:: virtual void visit(BinaryFunction* b) = 0
.. cpp:function:: virtual void visit(Immediate* i) = 0
.. cpp:function:: virtual void visit(RegisterAST* r) = 0
.. cpp:function:: virtual void visit(Dereference* d) = 0

class PrintVisitor : public Visitor {
public:
PrintVisitor() {};
~PrintVisitor() {};
virtual void visit(BinaryFunction* b) {};
virtual void visit(Immediate* i) {};
virtual void visit(RegisterAST* r) {
cout << "\tVisiting register " << r->getID().name() << endl;
}
virtual void visit(Dereference* d) {};
};

void printRegisters(Instruction::Ptr insn) {
PrintVisitor pv;
std::vector<Operand> operands;
insn->getOperands(operands);
// c++11x allows auto to determine the type of a variable;
// if not using c++11x, use 'std::vector<Operand>::iterator' instead.
// For gcc, use the -std=c++0x argument.
for (auto iter = operands.begin(); iter != operands.end(); ++iter) {
cout << "Registers used for operand" << endl;
(*iter).getValue()->apply(&pv);
}
}
.. _`sec:visitor-notes`:

Visitors may also set and use internal state. For example, the following
visitor (presented without surrounding use code) matches x86 and x86-64
instructions that add 0 to a register (effectively a noop).
Notes
=====

.. code-block:: cpp
This class specifies the interface users should extend to create their own
visitors to perform specific tasks.

class nopVisitor : public Visitor
{
public:
nopVisitor() : foundReg(false), foundImm(false), foundBin(false), isNop(true) {}
virtual ~nopVisitor() {}
bool foundReg;
bool foundImm;
bool foundBin;
bool isNop;
virtual void visit(BinaryFunction*)
{
if (foundBin) isNop = false;
if (!foundImm) isNop = false;
if (!foundReg) isNop = false;
foundBin = true;
}
virtual void visit(Immediate *imm)
{
if (imm != 0) isNop = false;
foundImm = true;
}
virtual void visit(RegisterAST *)
{
foundReg = true;
}
virtual void visit(Dereference *)
{
isNop = false;
}
};
Any state the visitor needs to preserve between nodes must be kept within the user's class.
Visitors are invoked by calling :cpp:func:`Expression::apply`. The individual ``visit`` methods
should not be invoked by user code.
10 changes: 0 additions & 10 deletions instructionAPI/h/Visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,6 @@ namespace InstructionAPI

class Visitor
{
/// A %Visitor performs postfix-order traversal of the AST represented by
/// an %Expression. The %Visitor class specifies the interface from which
/// users may derive %Visitors that perform specific tasks.
///
/// The %visit method must be overridden for each type of %Expression node
/// (%BinaryFunction, %Immediate, %RegisterAST, and %Dereference). Any state that
/// the %Visitor needs to preserve between nodes must be kept within the class.
/// %Visitors are invoked by calling %Expression::apply(%Visitor* v); the %visit method
/// should not be invoked by user code ordinarily.

public:
virtual ~Visitor() = default;
Visitor& operator=(const Visitor&) = default;
Expand Down

0 comments on commit d358cb1

Please sign in to comment.