Files
TheRock/rocm-systems/projects/rocprofiler-systems/external/dyninst/instructionAPI/doc/API/Instruction.tex
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

310 lines
11 KiB
TeX

\subsection{Instruction Class}
\label{sec:instruction}
The Instruction class is a generic instruction representation that contains
operands, read/write semantic information about those operands, and information
about what other registers and memory locations are affected by the operation
the instruction performs.
The purpose of an Instruction object is to join an Operation with a sequence of
Operands, and provide an interface for some common summary analyses (namely, the
read/write sets, memory access information, and control flow information).
The Operation contains knowledge about its mnemonic and sufficient semantic
details to answer the following questions:
\begin{itemize}
\item What Operands are read/written?
\item What registers are implicitly read/written?
\item What memory locations are implicitly read/written?
\item What are the possible control flow successors of this instruction?
\end{itemize}
Each Operand is an AST built from RegisterAST and Immediate leaves. For each Operand, you may determine:
\begin{itemize}
\item Registers read
\item Registers written
\item Whether memory is read or written
\item Which memory addresses are read or written, given the state of all relevant registers
\end{itemize}
Instructions should be constructed from an \code{unsigned} \code{char$\ast$}
pointing to machine language, using the InstructionDecoder class. See
InstructionDecoder for more details.
\begin{apient}
Instruction (Operation::Ptr what,
size_t size,
const unsigned char * raw,
Dyninst::Architecture arch)
\end{apient}
\apidesc{ \code{what} is the opcode of the instruction, \code{size}
contains the number of bytes occupied by the corresponding machine
instruction, and \code{raw} contains a pointer to the buffer from which
this \code{Instruction} object was decoded. The architecture is
specified by \code{arch}, and may be an element from the following
set: \code{\{Arch\_x86, Arch\_x86\_64, Arch\_ppc32, Arch\_ppc64\}}
(as defined in \code{dyn\_regs.h}).
Construct an Instruction from an Operation and a collection of Expressions.
This method is not intended to be used except by the InstructionDecoder
class, which serves as a factory class for producing Instruction objects.
While an Instruction object may be built ``by hand'' if
desired, using the decoding interface ensures that the operation and
operands are a sensible combination, and that the size reported is based on
the actual size of a legal encoding of the machine instruction represented.
}
\begin{apient}
const Operation & getOperation() const
\end{apient}
\apidesc{
Returns the \code{Operation} used by the \code{Instruction}. See
Section~\ref{sec:operation} for details of the \code{Operation} interface.
}
\begin{apient}
void getOperands(std::vector<Operand> & operands) const
\end{apient}
\apidesc{
The vector operands has the instruction's operands appended to it in the same
order that they
were decoded.
}
\begin{apient}
Operand getOperand(int index) const
\end{apient}
\apidesc{
The \code{getOperand} method returns the operand at position \code{index},
or an empty operand if \code{index} does not correspond to a valid operand
in this instruction.
}
\begin{apient}
unsigned char rawByte(unsigned int index) const
\end{apient}
\apidesc{
Returns the index$^{th}$ byte in the instruction.
}
\begin{apient}
size_t size() const
\end{apient}
\apidesc{
Returns the size of the corresponding machine instruction, in bytes.
}
\begin{apient}
const void * ptr() const
\end{apient}
\apidesc{
Returns a pointer to the raw byte representation of the corresponding machine
instruction.
}
\begin{apient}
void getWriteSet(std::set<RegisterAST::Ptr> & regsWritten) const
\end{apient}
\apidesc{
Insert the set of registers written by the instruction into
\code{regsWritten}. The list of registers returned in
\code{regsWritten} includes registers that are explicitly written as destination
operands (like the destination of a move). It also includes registers that are
implicitly written (like the stack pointer in a push or pop instruction). It
does not include any registers used only in computing the effective address of a
write. \code{pop} \code{$\ast$eax}, for example, writes to \code{esp}, reads
\code{esp}, and reads \code{eax}, but despite the fact that \code{$\ast$eax} is
the destination operand, \code{eax} is not itself written.
For both the write set and the read set (below), it is possible to determine
whether a register is accessed implicitly or explicitly by examining the
Operands. An explicitly accessed register appears as an operand that is written
or read; also, any registers used in any address calculations are explicitly
read. Any element of the write set or read set that is not explicitly written or
read is implicitly written or read.
}
\begin{apient}
void getReadSet(std::set<RegisterAST::Ptr> & regsRead) const
\end{apient}
\apidesc{
Insert the set of registers read by the instruction into \code{regsRead}.
If an operand is used to compute an effective address, the registers
involved are read but not written, regardless of the effect on the operand.
}
\begin{apient}
bool isRead(Expression::Ptr candidate) const
\end{apient}
\apidesc{
\code{candidate} is the subexpression to search for among the values read by
this \code{Instruction} object.
Returns \code{true} if \code{candidate} is read by this \code{Instruction}.
}
\begin{apient}
bool isWritten(Expression::Ptr candidate) const
\end{apient}
\apidesc{
\code{candidate} is the subexpression to search for among the values written by
this \code{Instruction} object.
Returns \code{true} if \code{candidate} is written by this \code{Instruction}.
}
\begin{apient}
bool readsMemory() const
\end{apient}
\apidesc{
Returns \code{true} if the instruction reads at least one memory address as
data.
If any operand containing a \code{Dereference} object is read, the
instruction reads the memory at that address. Also, on platforms where a
stack pop is guaranteed to read memory, \code{readsMemory} will return
\code{true} for a pop instruction.
}
\begin{apient}
bool writesMemory() const
\end{apient}
\apidesc{
Returns \code{true} if the instruction writes at least one memory address as
data.
If any operand containing a \code{Dereference} object is write, the
instruction writes the memory at that address. Also, on platforms where a
stack push is guaranteed to write memory, \code{writesMemory} will return
\code{true} for a pop instruction.
}
\begin{apient}
void getMemoryReadOperands(std::set<Expression::Ptr> & memAccessors) const
\end{apient}
\apidesc{
Addresses read by this instruction are inserted into \code{memAccessors}.
The addresses read are in the form of \code{Expression}s, which may be
evaluated once all of the registers that they use have had their values set.
Note that this method returns ASTs representing address computations, and
not address accesses. For instance, an instruction accessing memory through
a register dereference would return an \code{Expression} tree containing
just the register that determines the address being accessed, not a tree
representing a dereference of that register. Also note that the type of this
\code{Expression} is the type of an effective address (generally a word or
double word), not the type of the memory being accessed. For the memory being
accessed, use \code{getOperands} directly.
}
\begin{apient}
void getMemoryWriteOperands(std::set<Expression::Ptr> & memAccessors) const
\end{apient}
\apidesc{
Addresses written by this instruction are inserted into \code{memAccessors}.
The addresses written are in the same form as those returned by
\code{getMemoryReadOperands} above.
}
\begin{apient}
Expression::Ptr getControlFlowTarget() const
\end{apient}
\apidesc{
When called on an explicitly control-\/flow altering instruction, returns the
non-fallthrough control flow destination. When called on any other instruction,
returns \code{NULL}.
For direct absolute branch instructions, \code{getControlFlowTarget} will return
an immediate value. For direct relative branch instructions,
\code{getControlFlowTarget} will return the expression \code{PC} + offset. In
the case of indirect branches and calls, it returns a dereference of a register
(or possibly a dereference of a more complicated expression). In this case, data
flow analysis will often allow the determination of the possible targets of the
instruction. We do not do analysis beyond the single-instruction level in the
Instruction API; if other code performs this type of analysis, it may update the
information in the Dereference object using the setValue method in the
Expression interface. More details about this may be found in
Section~\ref{sec:expression} and Section~\ref{sec:dereference}.
Returns an \code{Expression} evaluating to the non-fallthrough control targets,
if any, of this instruction.
}
\begin{apient}
bool allowsFallThrough() const
\end{apient}
\apidesc{
Returns \code{false} if control flow will unconditionally go to the result
of \code{getControlFlowTarget} after executing this instruction.
}
\begin{apient}
std::string format(Address addr = 0)
\end{apient}
\apidesc{
Returns the instruction as a string of assembly language. If
\code{addr} is specified, the value of the program counter as used
by the instruction (e.g., a branch) is set to \code{addr}.
}
\begin{apient}
bool isValid() const
\end{apient}
\apidesc{
Returns \code{true} if this \code{Instruction} object is valid. Invalid
instructions indicate than an \code{InstructionDecoder} has reached the end
of its assigned range, and that decoding should terminate.
}
\begin{apient}
bool isLegalInsn() const
\end{apient}
\apidesc{
Returns \code{true} if this Instruction object represents a legal
instruction, as specified by the architecture used to decode this
instruction.
}
\begin{apient}
Architecture getArch() const
\end{apient}
\apidesc{Returns the architecture containing the instruction. As
above, this will be an element from the set \code{\{Arch\_x86,
Arch\_x86\_64, Arch\_ppc32, Arch\_ppc64\}}.}
\begin{apient}
InsnCategory getCategory() const
\end{apient}
\apidesc{
Currently, the valid categories are \code{c\_CallInsn},
\code{c\_ReturnInsn}, \code{c\_BranchInsn}, \code{c\_CompareInsn},
\code{c\_PrefetchInsn}, \code{c\_SysEnterInsn}, \code{c\_SyscallInsn},
\code{c\_VectorInsn}, and \code{c\_NoCategory}, as defined in
\code{InstructionCategories.h}.
}
\begin{apient}
struct CFT {
Expression::Ptr target;
bool isCall;
bool isIndirect;
bool isConditional;
bool isFallthrough;
}
typedef ... cftConstIter;
cftConstIter cft_begin() const;
cftConstIter cft_end() const;
\end{apient}
\apidesc{
On certain platforms (e.g., PowerPC with conditional call/return
instructions) the \code{getControlFlowTarget} function is
insufficient to represent the successors of an instruction. The
\code{cft\_begin} and \code{cft\_end} functions return iterators
into a list of all control flow target expressions as represented by
a list of \code{CFT} structures. In most cases,
\code{getControlFlowTarget} suffices.
}