Files
TheRock/rocm-systems/projects/rocprofiler-systems/external/dyninst/instructionAPI/h/Instruction.h
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

334 lines
16 KiB
C++

/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(INSTRUCTION_H)
#define INSTRUCTION_H
#include <stddef.h>
#include <string>
#include <string.h>
#include <vector>
#include <set>
#include <list>
#include "Expression.h"
#include "Operation_impl.h"
#include "Operand.h"
#include "InstructionCategories.h"
#include "ArchSpecificFormatters.h"
#include "util.h"
namespace Dyninst
{
namespace InstructionAPI
{
class InstructionDecoder;
/// 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:
/// - What %Operands are read/written?
/// - What registers are implicitly read/written?
/// - What memory locations are implicitly read/written?
/// - What are the possible control flow successors of this instruction?
///
/// Each %Operand is an AST built from %RegisterAST and %Immediate leaves. For each %Operand, you may determine:
/// - Registers read
/// - Registers written
/// - Whether memory is read or written
/// - Which memory addresses are read or written, given the state of all relevant registers
///
/// Instructions should be constructed from an \c unsigned \c char* pointing to machine language, using the
/// %InstructionDecoder class. See InstructionDecoder for more details.
///
class Instruction
{
/// Component version information corresponding to \c libInstructionAPI.so.(major).(minor).(maintenance)
/// Note that \c maintenance may be absent from the binary (in which case, it will be zero in the interface).
INSTRUCTION_EXPORT static void version(int& major, int& minor, int& maintenance);
union raw_insn_T
{
#if defined(__powerpc__) || defined(__powerpc64__)
unsigned int small_insn;
#else
uintptr_t small_insn;
#endif
unsigned char* large_insn;
};
public:
friend class InstructionDecoder_x86;
friend class InstructionDecoder_power;
friend class InstructionDecoder_aarch64;
friend class InstructionDecoder_amdgpu_gfx908;
friend class InstructionDecoder_amdgpu_gfx90a;
friend class InstructionDecoder_amdgpu_gfx940;
struct CFT
{
Expression::Ptr target;
bool isCall;
bool isIndirect;
bool isConditional;
bool isFallthrough;
CFT(Expression::Ptr t, bool call, bool indir, bool cond, bool ft) :
target(t), isCall(call), isIndirect(indir), isConditional(cond), isFallthrough(ft) {}
};
/// \param what Opcode of the instruction
/// \param operandSource Contains the %Expressions to be transformed into %Operands
/// \param size Contains the number of bytes occupied by the corresponding machine instruction
/// \param raw Contains a pointer to the buffer from which this instruction object
/// was decoded.
///
/// 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.
/// In the course of constructing an %Instruction, the %Expressions in \c operandSource
/// will be transformed to %Operand objects. This transformation will map the semantic information about
/// which operands are read and written
/// in the %Operation object \c what to the value computations in \c operandSource.
INSTRUCTION_EXPORT Instruction(Operation what, size_t size, const unsigned char* raw,
Dyninst::Architecture arch);
INSTRUCTION_EXPORT Instruction();
INSTRUCTION_EXPORT virtual ~Instruction();
INSTRUCTION_EXPORT Instruction(const Instruction& o);
INSTRUCTION_EXPORT const Instruction& operator=(const Instruction& rhs);
/// \return The %Operation used by the %Instruction
///
/// See Operation for details of the %Operation interface.
INSTRUCTION_EXPORT Operation& getOperation();
INSTRUCTION_EXPORT const Operation& getOperation() const;
/// The vector \c operands has the instruction's operands appended to it
/// in the same order that they were decoded.
INSTRUCTION_EXPORT void getOperands(std::vector<Operand>& operands) const;
/// Returns a vector of non-implicit operands in printed order
INSTRUCTION_EXPORT std::vector<Operand> getDisplayOrderedOperands() const;
/// The \c getOperand method returns the operand at position \c index, or
/// an empty operand if \c index does not correspond to a valid operand in this
/// instruction.
INSTRUCTION_EXPORT Operand getOperand(int index) const;
INSTRUCTION_EXPORT Operand getPredicateOperand() const;
INSTRUCTION_EXPORT bool hasPredicateOperand() const;
/// Returns a pointer to the buffer from which this instruction
/// was decoded.
INSTRUCTION_EXPORT unsigned char rawByte(unsigned int index) const;
/// Returns the size of the corresponding machine instruction, in bytes.
INSTRUCTION_EXPORT size_t size() const;
/// Returns a pointer to the raw byte representation of the corresponding
/// machine instruction.
INSTRUCTION_EXPORT const void* ptr() const;
/// \param regsWritten Insert the set of registers written by the instruction into \c regsWritten.
///
/// The list of registers returned in \c 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.
/// \c pop \c *eax, for example, writes to \c esp, reads \c esp, and reads \c eax,
/// but despite the fact that \c *eax is the destination operand, \c 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.
INSTRUCTION_EXPORT void getWriteSet(std::set<RegisterAST::Ptr>& regsWritten) const;
/// \param regsRead Insert the set of registers read by the instruction into \c 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.
INSTRUCTION_EXPORT void getReadSet(std::set<RegisterAST::Ptr>& regsRead) const;
/// \param candidate Subexpression to search for among the values read by this %Instruction object.
///
/// Returns true if \c candidate is read by this %Instruction.
INSTRUCTION_EXPORT bool isRead(Expression::Ptr candidate) const;
/// \param candidate Subexpression to search for among the values written by this %Instruction object.
///
/// Returns true if \c candidate is written by this %Instruction.
INSTRUCTION_EXPORT bool isWritten(Expression::Ptr candidate) const;
/// \return Returns true if the instruction reads at least one memory address as data.
///
/// If any operand containing a %Dereference object is read, the instruction
/// reads the memory at that address.
/// Also, on platforms where a stack pop is guaranteed to read memory,
/// \c readsMemory will return true for a pop operation.
INSTRUCTION_EXPORT bool readsMemory() const;
INSTRUCTION_EXPORT ArchSpecificFormatter& getFormatter() const;
/// \return Returns true if the instruction writes at least one memory address.
///
/// If any operand containing a %Dereference object is written, the instruction
/// writes the memory at that address.
/// Also, on platforms where a stack push is guaranteed to write memory,
/// \c writesMemory will return true for a push operation.
INSTRUCTION_EXPORT bool writesMemory() const;
/// \param memAccessors Addresses read by this instruction are inserted into \c memAccessors
///
/// The addresses read are in the form of %Expressions, 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 a %Expression tree containing
/// just the register that determines the address being accessed, not a tree representing a dereference of that register.
INSTRUCTION_EXPORT void getMemoryReadOperands(std::set<Expression::Ptr>& memAccessors) const;
/// \param memAccessors Addresses written by this instruction are inserted into \c memAccessors
///
/// The addresses written are in the same form as those returned by \c getMemoryReadOperands above.
INSTRUCTION_EXPORT void getMemoryWriteOperands(std::set<Expression::Ptr>& memAccessors) const;
/// \return An expression evaluating to the non-fallthrough control flow targets, if any, of this instruction.
///
/// When called on an explicitly control-flow altering instruction, returns the
/// non-fallthrough control flow destination. When called on any other instruction,
/// returns \c NULL.
///
/// For direct absolute branch instructions, \c getControlFlowTarget will return an immediate value.
/// For direct relative branch instructions, \c getControlFlowTarget will return the expression
/// \c 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 Expression and Dereference.
INSTRUCTION_EXPORT Expression::Ptr getControlFlowTarget() const;
/// \return False if control flow will unconditionally go to the result of
/// \c getControlFlowTarget after executing this instruction.
INSTRUCTION_EXPORT bool allowsFallThrough() const;
/// \return The instruction as a string of assembly language
///
/// \c format is principally a helper function; %Instructions are meant to be written to
/// output streams via \c operator<<. \c format is included in the public interface for
/// diagnostic purposes.
INSTRUCTION_EXPORT std::string format(Address addr = 0) const;
/// Returns true if this %Instruction object is valid. Invalid instructions indicate that
/// an %InstructionDecoder has reached the end of its assigned range, and that decoding should terminate.
INSTRUCTION_EXPORT bool isValid() const;
/// Returns true if this %Instruction object represents a legal instruction, as specified by the architecture
/// used to decode this instruction.
INSTRUCTION_EXPORT bool isLegalInsn() const;
INSTRUCTION_EXPORT Architecture getArch() const;
/// Currently, the valid categories are c_CallInsn, c_ReturnInsn, c_BranchInsn, c_CompareInsn,
/// and c_NoCategory, as defined in %InstructionCategories.h.
INSTRUCTION_EXPORT InsnCategory getCategory() const;
typedef std::list<CFT>::const_iterator cftConstIter;
INSTRUCTION_EXPORT cftConstIter cft_begin() const {
return m_Successors.begin();
}
INSTRUCTION_EXPORT cftConstIter cft_end() const {
return m_Successors.end();
}
INSTRUCTION_EXPORT bool operator<(const Instruction& rhs) const
{
if(m_size < rhs.m_size) return true;
if(m_size <= sizeof(m_RawInsn.small_insn)) {
return m_RawInsn.small_insn < rhs.m_RawInsn.small_insn;
}
return memcmp(m_RawInsn.large_insn, rhs.m_RawInsn.large_insn, m_size) < 0;
}
INSTRUCTION_EXPORT bool operator==(const Instruction& rhs) const {
if(m_size != rhs.m_size) return false;
if(m_size <= sizeof(m_RawInsn.small_insn)) {
return m_RawInsn.small_insn == rhs.m_RawInsn.small_insn;
}
return memcmp(m_RawInsn.large_insn, rhs.m_RawInsn.large_insn, m_size) == 0;
}
INSTRUCTION_EXPORT void updateMnemonic(std::string new_mnemonic) {
m_InsnOp.updateMnemonic(new_mnemonic);
}
typedef dyncompat::shared_ptr<Instruction> Ptr;
private:
void updateSize(const unsigned int new_size) {m_size = new_size;}
void decodeOperands() const;
void addSuccessor(Expression::Ptr e, bool isCall, bool isIndirect, bool isConditional, bool isFallthrough, bool isImplicit = false) const;
void appendOperand(Expression::Ptr e, bool isRead, bool isWritten, bool isImplicit = false, bool trueP = false, bool falseP = false) const;
void copyRaw(size_t size, const unsigned char* raw);
Expression::Ptr makeReturnExpression() const;
mutable std::list<Operand> m_Operands;
mutable Operation m_InsnOp;
bool m_Valid;
raw_insn_T m_RawInsn;
unsigned int m_size;
Architecture arch_decoded_from;
mutable std::list<CFT> m_Successors;
static int numInsnsAllocated;
// formatter is a non-owning pointer to a singleton object
ArchSpecificFormatter* formatter;
};
}
}
#endif //!defined(INSTRUCTION_H)