blob: 6552bb771549a22fb03eaa192bbbc3da491f0c85 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011-2022 Google, Inc. All rights reserved.
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2000-2001 Hewlett-Packard Company */
/* The machine-specific IR consists of instruction lists, instructions,
* operands, and opcodes. You can find related declarations and interface
* functions in corresponding headers.
*/
/* file "instr.h" -- instr_t specific definitions and utilities */
#ifndef _INSTR_H_
#define _INSTR_H_ 1
#include "opcode_api.h"
#include "opnd.h"
/* To avoid duplicating code we use our own exported macros, unless an includer
* needs to avoid it.
*/
#ifdef DR_NO_FAST_IR
# undef DR_FAST_IR
# undef INSTR_INLINE
#else
# define DR_FAST_IR 1
#endif
#include "instr_api.h" /* After the INSTR_INLINE, etc. above. */
/* can't include decode.h, it includes us, just declare struct */
struct instr_info_t;
/* If INSTR_INLINE is already defined, that means we've been included by
* instr_shared.c, which wants to use C99 extern inline. Otherwise, DR_FAST_IR
* determines whether our instr routines are inlined.
*/
/* Inlining macro controls. */
#ifndef INSTR_INLINE
# ifdef DR_FAST_IR
# define INSTR_INLINE inline
# else
# define INSTR_INLINE
# endif
#endif
/*************************
*** instr_t ***
*************************/
/* instr_t structure
* An instruction represented by instr_t can be in a number of states,
* depending on whether it points to raw bits that are valid,
* whether its operand and opcode fields are up to date, and whether
* its eflags field is up to date.
* Invariant: if opcode == OP_UNDECODED, raw bits should be valid.
* if opcode == OP_INVALID, raw bits may point to real bits,
* but they are not a valid instruction stream.
*
* CORRESPONDENCE WITH CGO LEVELS
* Level 0 = raw bits valid, !opcode_valid, decode_sizeof(instr) != instr->len
* opcode_valid is equivalent to opcode != OP_INVALID && opcode != OP_UNDECODED
* Level 1 = raw bits valid, !opcode_valid, decode_sizeof(instr) == instr->len
* Level 2 = raw bits valid, opcode_valid, !operands_valid
* (eflags info is auto-derived on demand so not an issue)
* Level 3 = raw bits valid, operands valid
* (we assume that if operands_valid then opcode_valid)
* Level 4 = !raw bits valid, operands valid
*
* Independent of these is whether its raw bits were allocated for
* the instr or not.
*/
/* flags */
enum {
/* these first flags are shared with the LINK_ flags and are
* used to pass on info to link stubs
*/
/* used to determine type of indirect branch for exits */
INSTR_DIRECT_EXIT = LINK_DIRECT,
INSTR_INDIRECT_EXIT = LINK_INDIRECT,
INSTR_RETURN_EXIT = LINK_RETURN,
/* JMP|CALL marks an indirect jmp preceded by a call (== a PLT-style ind call)
* so use EXIT_IS_{JMP,CALL} rather than these raw bits
*/
INSTR_CALL_EXIT = LINK_CALL,
INSTR_JMP_EXIT = LINK_JMP,
INSTR_IND_JMP_PLT_EXIT = (INSTR_JMP_EXIT | INSTR_CALL_EXIT),
INSTR_FAR_EXIT = LINK_FAR,
INSTR_BRANCH_SPECIAL_EXIT = LINK_SPECIAL_EXIT,
INSTR_BRANCH_PADDED = LINK_PADDED,
#ifdef X64
/* PR 257963: since we don't store targets of ind branches, we need a flag
* so we know whether this is a trace cmp exit, which has its own ibl entry
*/
INSTR_TRACE_CMP_EXIT = LINK_TRACE_CMP,
#endif
#ifdef WINDOWS
INSTR_CALLBACK_RETURN = LINK_CALLBACK_RETURN,
#else
INSTR_NI_SYSCALL_INT = LINK_NI_SYSCALL_INT,
#endif
INSTR_NI_SYSCALL = LINK_NI_SYSCALL,
INSTR_NI_SYSCALL_ALL = LINK_NI_SYSCALL_ALL,
/* meta-flag */
EXIT_CTI_TYPES = (INSTR_DIRECT_EXIT | INSTR_INDIRECT_EXIT | INSTR_RETURN_EXIT |
INSTR_CALL_EXIT | INSTR_JMP_EXIT | INSTR_FAR_EXIT |
INSTR_BRANCH_SPECIAL_EXIT | INSTR_BRANCH_PADDED |
#ifdef X64
INSTR_TRACE_CMP_EXIT |
#endif
#ifdef WINDOWS
INSTR_CALLBACK_RETURN |
#else
INSTR_NI_SYSCALL_INT |
#endif
INSTR_NI_SYSCALL),
/* instr_t-internal flags (not shared with LINK_) */
INSTR_OPERANDS_VALID = 0x00010000,
/* meta-flag */
INSTR_FIRST_NON_LINK_SHARED_FLAG = INSTR_OPERANDS_VALID,
INSTR_EFLAGS_VALID = 0x00020000,
INSTR_EFLAGS_6_VALID = 0x00040000,
INSTR_RAW_BITS_VALID = 0x00080000,
INSTR_RAW_BITS_ALLOCATED = 0x00100000,
/* This flag is in instr_api.h as it's needed for inlining support.
* INSTR_DO_NOT_MANGLE = 0x00200000,
*/
/* This flag is set by instr_noalloc_init() and used to identify the
* instr_noalloc_t "subclass" of instr_t. It should not be otherwise used.
*/
INSTR_IS_NOALLOC_STRUCT = 0x00400000,
/* used to indicate that an indirect call can be treated as a direct call */
INSTR_IND_CALL_DIRECT = 0x00800000,
#ifdef WINDOWS
/* used to indicate that a syscall should be executed via shared syscall */
INSTR_SHARED_SYSCALL = 0x01000000,
#else
/* Indicates an instruction that's part of the rseq endpoint. We use this in
* instrlist_t.flags (sort of the same namespace: INSTR_OUR_MANGLING is used there,
* but also EDI_VAL_*); we no longer use it on individual instructions since
* the label note field DR_NOTE_RSEQ now survives encoding.
*/
INSTR_RSEQ_ENDPOINT = 0x01000000,
#endif
/* This enum is also used for INSTR_OUR_MANGLING_EPILOGUE. Its semantics are
* orthogonal to this and must not overlap.
*/
INSTR_CLOBBER_RETADDR = 0x02000000,
/* Indicates that the instruction is part of an own mangling region's
* epilogue (xref i#3307). Currently, instructions with the
* INSTR_CLOBBER_RETADDR property are never in a mangling epilogue, which
* is why we are reusing its enum value here.
* */
INSTR_OUR_MANGLING_EPILOGUE = 0x02000000,
/* Signifies that this instruction may need to be hot patched and should
* therefore not cross a cache line. It is not necessary to set this for
* exit cti's or linkstubs since it is mainly intended for clients etc.
* Handling of this flag is not yet implemented */
INSTR_HOT_PATCHABLE = 0x04000000,
#ifdef DEBUG
/* case 9151: only report invalid instrs for normal code decoding */
INSTR_IGNORE_INVALID = 0x08000000,
#endif
/* Currently used for frozen coarse fragments with final jmps and
* jmps to ib stubs that are elided: we need the jmp instr there
* to build the linkstub_t but we do not want to emit it. */
INSTR_DO_NOT_EMIT = 0x10000000,
/* PR 251479: re-relativization support: is instr->rip_rel_pos valid? */
INSTR_RIP_REL_VALID = 0x20000000,
#ifdef X86
/* PR 278329: each instr stores its own mode */
INSTR_X86_MODE = 0x40000000,
#elif defined(ARM)
/* We assume we don't need to distinguish A64 from A32 as you cannot swap
* between them in user mode. Thus we only need one flag.
* XXX: we might want more power for drdecode, though the global isa_mode
* should be sufficient there.
*/
INSTR_THUMB_MODE = 0x40000000,
#endif
/* PR 267260: distinguish our own mangling from client-added instrs */
INSTR_OUR_MANGLING = 0x80000000,
};
#define DR_TUPLE_TYPE_BITS 4
#define DR_TUPLE_TYPE_BITPOS (32 - DR_TUPLE_TYPE_BITS)
/* AVX-512 tuple type attributes as specified in Intel's tables. */
typedef enum _dr_tuple_type_t {
DR_TUPLE_TYPE_NONE = 0,
#ifdef X86
DR_TUPLE_TYPE_FV = 1,
DR_TUPLE_TYPE_HV = 2,
DR_TUPLE_TYPE_FVM = 3,
DR_TUPLE_TYPE_T1S = 4,
DR_TUPLE_TYPE_T1F = 5,
DR_TUPLE_TYPE_T2 = 6,
DR_TUPLE_TYPE_T4 = 7,
DR_TUPLE_TYPE_T8 = 8,
DR_TUPLE_TYPE_HVM = 9,
DR_TUPLE_TYPE_QVM = 10,
DR_TUPLE_TYPE_OVM = 11,
DR_TUPLE_TYPE_M128 = 12,
DR_TUPLE_TYPE_DUP = 13,
#endif
} dr_tuple_type_t;
/* These aren't composable, so we store them in as few bits as possible.
* The top 5 prefix bits hold the value (x86 needs 17 values).
* XXX: if we need more space we could compress the x86 values: they're
* all pos/neg pairs so we could store the pos/neg bit just once.
* XXX: if we want a slightly faster predication check we could take
* a dedicated PREFIX_PREDICATED bit.
*/
#define PREFIX_PRED_BITS 5
#define PREFIX_PRED_BITPOS (32 - PREFIX_PRED_BITS)
#define PREFIX_PRED_MASK \
(((1U << PREFIX_PRED_BITS) - 1) << PREFIX_PRED_BITPOS) /*0xf8000000 */
bool
instr_branch_is_padded(instr_t *instr);
void
instr_branch_set_padded(instr_t *instr, bool val);
/* Returns true iff \p instr has been marked as a special fragment
* exit cti.
*/
bool
instr_branch_special_exit(instr_t *instr);
/* If \p val is true, indicates that \p instr is a special exit cti.
* If \p val is false, indicates otherwise.
*/
void
instr_branch_set_special_exit(instr_t *instr, bool val);
/* not exported */
void
instr_shift_raw_bits(instr_t *instr, ssize_t offs);
int
instr_exit_branch_type(instr_t *instr);
void
instr_exit_branch_set_type(instr_t *instr, uint type);
const struct instr_info_t *
instr_get_instr_info(instr_t *instr);
const struct instr_info_t *
get_instr_info(int opcode);
/******************************************************************
* Eflags validity is not exported! It's hidden. Calling get_eflags or
* get_arith_flags will make them valid if they're not.
*/
bool
instr_arith_flags_valid(instr_t *instr);
/* Sets instr's arithmetic flags (the 6 bottom eflags) to be valid if
* valid is true, invalid otherwise. */
void
instr_set_arith_flags_valid(instr_t *instr, bool valid);
/* Returns true iff instr's eflags are up to date. */
bool
instr_eflags_valid(instr_t *instr);
/* Sets instr's eflags to be valid if valid is true, invalid otherwise. */
void
instr_set_eflags_valid(instr_t *instr, bool valid);
uint
instr_eflags_conditionally(uint full_eflags, dr_pred_type_t pred,
dr_opnd_query_flags_t flags);
/*
******************************************************************/
bool
instr_predicate_reads_srcs(dr_pred_type_t pred);
bool
instr_predicate_writes_eflags(dr_pred_type_t pred);
/***********************************************************************/
/* decoding routines */
DR_UNS_API
/**
* If instr is at Level 0 (i.e., a bundled group of instrs as raw bits),
* expands instr into a sequence of Level 1 instrs using decode_raw() which
* are added in place to ilist.
* Returns the replacement of instr, if any expansion is performed
* (in which case the old instr is destroyed); otherwise returns
* instr unchanged.
*/
instr_t *
instr_expand(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr);
DR_UNS_API
/**
* Returns true if instr is at Level 0 (i.e. a bundled group of instrs
* as raw bits).
*/
bool
instr_is_level_0(instr_t *inst);
DR_UNS_API
/**
* If the next instr is at Level 0 (i.e., a bundled group of instrs as raw bits),
* expands it into a sequence of Level 1 instrs using decode_raw() which
* are added in place to ilist. Then returns the new next instr.
*/
instr_t *
instr_get_next_expanded(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr);
DR_UNS_API
/**
* If the prev instr is at Level 0 (i.e., a bundled group of instrs as raw bits),
* expands it into a sequence of Level 1 instrs using decode_raw() which
* are added in place to ilist. Then returns the new prev instr.
*/
instr_t *
instr_get_prev_expanded(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr);
DR_UNS_API
/**
* If instr is not already at the level of decode_cti, decodes enough
* from the raw bits pointed to by instr to bring it to that level.
* Assumes that instr is a single instr (i.e., NOT Level 0).
*
* decode_cti decodes only enough of instr to determine
* its size, its effects on the 6 arithmetic eflags, and whether it is
* a control-transfer instruction. If it is, the operands fields of
* instr are filled in. If not, only the raw bits fields of instr are
* filled in. This corresponds to a Level 3 decoding for control
* transfer instructions but a Level 1 decoding plus arithmetic eflags
* information for all other instructions.
*/
void
instr_decode_cti(dcontext_t *dcontext, instr_t *instr);
DR_UNS_API
/**
* If instr is not already at the level of decode_opcode, decodes enough
* from the raw bits pointed to by instr to bring it to that level.
* Assumes that instr is a single instr (i.e., NOT Level 0).
*
* decode_opcode decodes the opcode and eflags usage of the instruction
* (if the eflags usage varies with operand values, the maximal value
* will be set).
* This corresponds to a Level 2 decoding.
*/
void
instr_decode_opcode(dcontext_t *dcontext, instr_t *instr);
DR_UNS_API
/**
* If instr is not already fully decoded, decodes enough
* from the raw bits pointed to by instr to bring it Level 3.
* Assumes that instr is a single instr (i.e., NOT Level 0).
*/
void
instr_decode(dcontext_t *dcontext, instr_t *instr);
/* Calls instr_decode() with the current dcontext. *Not* exported. Mostly
* useful as the slow path for IR routines that get inlined.
*/
instr_t *
instr_decode_with_current_dcontext(instr_t *instr);
DR_UNS_API
/**
* If the first instr is at Level 0 (i.e., a bundled group of instrs as raw bits),
* expands it into a sequence of Level 1 instrs using decode_raw() which
* are added in place to ilist. Then returns the new first instr.
*/
instr_t *
instrlist_first_expanded(dcontext_t *dcontext, instrlist_t *ilist);
DR_UNS_API
/**
* If the last instr is at Level 0 (i.e., a bundled group of instrs as raw bits),
* expands it into a sequence of Level 1 instrs using decode_raw() which
* are added in place to ilist. Then returns the new last instr.
*/
instr_t *
instrlist_last_expanded(dcontext_t *dcontext, instrlist_t *ilist);
DR_UNS_API
/**
* If the translation pointer is set for \p instr, returns that
* else returns NULL.
* \note The translation pointer is not automatically set when
* decoding instructions from raw bytes (via decode(), e.g.); it is
* set for instructions in instruction lists generated by DR (see
* dr_register_bb_event()).
*
*/
app_pc
instr_get_translation(instr_t *instr);
DR_UNS_API
/**
* Brings all instrs in ilist up to the decode_cti level, and
* hooks up intra-ilist cti targets to use instr_t targets, by
* matching pc targets to each instruction's raw bits.
*
* decode_cti decodes only enough of instr to determine
* its size, its effects on the 6 arithmetic eflags, and whether it is
* a control-transfer instruction. If it is, the operands fields of
* instr are filled in. If not, only the raw bits fields of instr are
* filled in. This corresponds to a Level 3 decoding for control
* transfer instructions but a Level 1 decoding plus arithmetic eflags
* information for all other instructions.
*/
void
instrlist_decode_cti(dcontext_t *dcontext, instrlist_t *ilist);
/***********************************************************************/
/* utility functions */
#ifdef X86
/* We're not exposing the low-level rip_rel_pos routines directly to clients,
* who should only use this level 1-3 feature via decode_cti + encode.
*/
/* Returns true iff instr's raw bits are valid and the offset within
* those raw bits of a rip-relative displacement is set (to 0 if there
* is no such displacement).
*/
bool
instr_rip_rel_valid(instr_t *instr);
/* Sets whether instr's rip-relative displacement offset is valid. */
void
instr_set_rip_rel_valid(instr_t *instr, bool valid);
/* Assumes that instr_rip_rel_valid() is true.
* Returns the offset within the encoded bytes of instr of the
* displacement used for rip-relative addressing; returns 0
* if instr has no rip-relative operand.
* There can be at most one rip-relative operand in one instruction.
*/
uint
instr_get_rip_rel_pos(instr_t *instr);
/* Sets the offset within instr's encoded bytes of instr's
* rip-relative displacement (the offset should be 0 if there is no
* rip-relative operand) and marks it valid. \p pos must be less
* than 256.
*/
void
instr_set_rip_rel_pos(instr_t *instr, uint pos);
#endif /* X86 */
/* not exported: for PR 267260 */
bool
instr_is_our_mangling(instr_t *instr);
/* Sets whether instr came from our mangling. */
void
instr_set_our_mangling(instr_t *instr, bool ours);
/* Returns whether instr came from our mangling and is in epilogue. This routine
* requires the caller to already know that instr is our_mangling.
*/
bool
instr_is_our_mangling_epilogue(instr_t *instr);
/* Sets whether instr came from our mangling and is in epilogue. */
void
instr_set_our_mangling_epilogue(instr_t *instr, bool epilogue);
/* Sets that instr is in our mangling epilogue as well as the translation pointer
* for instr, by adding the translation pointer of mangle_instr to its length.
* Returns the instr.
*/
instr_t *
instr_set_translation_mangling_epilogue(dcontext_t *dcontext, instrlist_t *ilist,
instr_t *instr);
app_pc
instr_compute_address_priv(instr_t *instr, priv_mcontext_t *mc);
bool
instr_compute_address_ex_priv(instr_t *instr, priv_mcontext_t *mc, uint index,
OUT app_pc *addr, OUT bool *write, OUT uint *pos);
/* Get a label instructions callback function */
instr_label_callback_t
instr_get_label_callback(instr_t *instr);
byte *
remangle_short_rewrite(dcontext_t *dcontext, instr_t *instr, byte *pc, app_pc target);
bool
instr_saves_float_pc(instr_t *instr);
#ifdef AARCH64
bool
instr_is_icache_op(instr_t *instr);
#endif
#ifdef ARM
bool
instr_is_pop(instr_t *instr);
bool
instr_reads_gpr_list(instr_t *instr);
bool
instr_writes_gpr_list(instr_t *instr);
bool
instr_reads_reg_list(instr_t *instr);
bool
instr_writes_reg_list(instr_t *instr);
#endif
#ifdef X86
bool
instr_can_set_single_step(instr_t *instr);
/* Returns true if \p instr is part of Intel's AVX-512 instructions that may write to a
* zmm or opmask register. It approximates this by checking whether PREFIX_EVEX is set. If
* not set, it checks the destinations of \p instr. The decoded instr should be
* available for inspection as this is invoked only when some client is present.
*/
bool
instr_may_write_zmm_or_opmask_register(instr_t *instr);
#endif
/* Given a machine state, returns whether or not the cbr instr would be taken
* if the state is before execution (pre == true) or after (pre == false).
* (not exported since machine state isn't)
*/
bool
instr_cbr_taken(instr_t *instr, priv_mcontext_t *mcontext, bool pre);
/* utility routines that are in optimize.c */
opnd_t
instr_get_src_mem_access(instr_t *instr);
void
d_r_loginst(dcontext_t *dcontext, uint level, instr_t *instr, const char *string);
void
d_r_logopnd(dcontext_t *dcontext, uint level, opnd_t opnd, const char *string);
DR_UNS_API
/**
* Convenience routine to create a nop of a certain size. If \p raw
* is true, sets raw bytes rather than filling in the operands or opcode.
*/
instr_t *
instr_create_nbyte_nop(dcontext_t *dcontext, uint num_bytes, bool raw);
/* build instructions from raw bits */
DR_UNS_API
/**
* Convenience routine that returns an initialized instr_t with invalid operands
* and allocated raw bits with 1 byte (byte).
*/
instr_t *
instr_create_raw_1byte(dcontext_t *dcontext, byte byte);
DR_UNS_API
/**
* Convenience routine that returns an initialized instr_t with invalid operands
* and allocated raw bits with 2 bytes (byte1, byte2).
*/
instr_t *
instr_create_raw_2bytes(dcontext_t *dcontext, byte byte1, byte byte2);
DR_UNS_API
/**
* Convenience routine that returns an initialized instr_t with invalid operands
* and allocated raw bits with 3 bytes (byte1, byte2, byte3).
*/
instr_t *
instr_create_raw_3bytes(dcontext_t *dcontext, byte byte1, byte byte2, byte byte3);
DR_UNS_API
/**
* Convenience routine that returns an initialized instr_t with invalid operands
* and allocated raw bits with 4 bytes (byte1, byte2, byte3, byte4).
*/
instr_t *
instr_create_raw_4bytes(dcontext_t *dcontext, byte byte1, byte byte2, byte byte3,
byte byte4);
DR_UNS_API
/**
* Convenience routine that returns an initialized instr_t with invalid operands
* and allocated raw bits with 5 bytes (byte1, byte2, byte3, byte4, byte5).
*/
instr_t *
instr_create_raw_5bytes(dcontext_t *dcontext, byte byte1, byte byte2, byte byte3,
byte byte4, byte byte5);
DR_UNS_API
/**
* Convenience routine that returns an initialized instr_t with invalid operands
* and allocated raw bits with 6 bytes (byte1, byte2, byte3, byte4, byte5, byte6).
*/
instr_t *
instr_create_raw_6bytes(dcontext_t *dcontext, byte byte1, byte byte2, byte byte3,
byte byte4, byte byte5, byte byte6);
DR_UNS_API
/**
* Convenience routine that returns an initialized instr_t with invalid operands
* and allocated raw bits with 7 bytes (byte1, byte2, byte3, byte4, byte5, byte6,
* byte7).
*/
instr_t *
instr_create_raw_7bytes(dcontext_t *dcontext, byte byte1, byte byte2, byte byte3,
byte byte4, byte byte5, byte byte6, byte byte7);
DR_UNS_API
/**
* Convenience routine that returns an initialized instr_t with invalid operands
* and allocated raw bits with 7 bytes (byte1, byte2, byte3, byte4, byte5, byte6,
* byte7, byte8).
*/
instr_t *
instr_create_raw_8bytes(dcontext_t *dcontext, byte byte1, byte byte2, byte byte3,
byte byte4, byte byte5, byte byte6, byte byte7, byte byte8);
/* arch-specific routines */
int
instr_length_arch(dcontext_t *dcontext, instr_t *instr);
bool
opc_is_not_a_real_memory_load(int opc);
bool
instr_compute_address_VSIB(instr_t *instr, priv_mcontext_t *mc, size_t mc_size,
dr_mcontext_flags_t mc_flags, opnd_t curop, uint index,
OUT bool *have_addr, OUT app_pc *addr, OUT bool *write);
uint
instr_branch_type(instr_t *cti_instr);
#ifdef AARCH64
const char *
get_opcode_name(int opc);
#endif
/* these routines can assume that instr's opcode is valid */
bool
instr_is_call_arch(instr_t *instr);
bool
instr_is_cbr_arch(instr_t *instr);
bool
instr_is_mbr_arch(instr_t *instr);
bool
instr_is_ubr_arch(instr_t *instr);
/* private routines for spill code */
instr_t *
instr_create_save_to_dcontext(dcontext_t *dcontext, reg_id_t reg, int offs);
instr_t *
instr_create_save_immed32_to_dcontext(dcontext_t *dcontext, int immed, int offs);
instr_t *
instr_create_save_immed16_to_dcontext(dcontext_t *dcontext, int immed, int offs);
instr_t *
instr_create_save_immed8_to_dcontext(dcontext_t *dcontext, int immed, int offs);
instr_t *
instr_create_save_immed_to_dc_via_reg(dcontext_t *dcontext, reg_id_t basereg, int offs,
ptr_int_t immed, opnd_size_t sz);
instr_t *
instr_create_restore_from_dcontext(dcontext_t *dcontext, reg_id_t reg, int offs);
instr_t *
instr_create_save_to_dc_via_reg(dcontext_t *dcontext, reg_id_t basereg, reg_id_t reg,
int offs);
instr_t *
instr_create_restore_from_dc_via_reg(dcontext_t *dcontext, reg_id_t basereg, reg_id_t reg,
int offs);
instr_t *
instr_create_jump_via_dcontext(dcontext_t *dcontext, int offs);
instr_t *
instr_create_save_dynamo_stack(dcontext_t *dcontext);
instr_t *
instr_create_restore_dynamo_stack(dcontext_t *dcontext);
bool
instr_raw_is_tls_spill(byte *pc, reg_id_t reg, ushort offs);
bool
instr_is_tls_spill(instr_t *instr, reg_id_t reg, ushort offs);
bool
instr_is_tls_xcx_spill(instr_t *instr);
/* Pass REG_NULL to not care about the reg */
bool
instr_is_tls_restore(instr_t *instr, reg_id_t reg, ushort offs);
bool
instr_is_DR_reg_spill_or_restore(void *drcontext, instr_t *instr, bool *tls OUT,
bool *spill OUT, reg_id_t *reg OUT, uint *offs OUT);
#ifdef AARCHXX
bool
instr_reads_thread_register(instr_t *instr);
bool
instr_is_stolen_reg_move(instr_t *instr, bool *save, reg_id_t *reg);
#endif
#ifdef AARCH64
bool
instr_writes_thread_register(instr_t *instr);
#endif
/* N.B. : client meta routines (dr_insert_* etc.) should never use anything other
* then TLS_XAX_SLOT unless the client has specified a slot to use as we let the
* client use the rest. */
instr_t *
instr_create_save_to_tls(dcontext_t *dcontext, reg_id_t reg, ushort offs);
instr_t *
instr_create_restore_from_tls(dcontext_t *dcontext, reg_id_t reg, ushort offs);
/* For -x86_to_x64, we can spill to 64-bit extra registers (xref i#751). */
instr_t *
instr_create_save_to_reg(dcontext_t *dcontext, reg_id_t reg1, reg_id_t reg2);
instr_t *
instr_create_restore_from_reg(dcontext_t *dcontext, reg_id_t reg1, reg_id_t reg2);
#ifdef X86_64
byte *
instr_raw_is_rip_rel_lea(byte *pc, byte *read_end);
#endif
/* even on x64, displacements are 32 bits, so we keep the "int" type and 4-byte size
*/
#define PC_RELATIVE_TARGET(addr) (*((int *)(addr)) + (addr) + 4)
/* length of our mangling of jecxz/loop*, beyond a possible addr prefix byte */
#ifdef X86
# define CTI_SHORT_REWRITE_LENGTH 9
#else
/* cbz/cbnz + b */
# define CTI_SHORT_REWRITE_LENGTH 6
# define CTI_SHORT_REWRITE_B_OFFS 2
#endif
#ifdef X86
enum {
RAW_OPCODE_nop = 0x90,
RAW_OPCODE_jmp_short = 0xeb,
RAW_OPCODE_call = 0xe8,
RAW_OPCODE_ret = 0xc3,
RAW_OPCODE_jmp = 0xe9,
RAW_OPCODE_push_imm32 = 0x68,
RAW_OPCODE_pop_eax = 0x58,
RAW_OPCODE_jcc_short_start = 0x70,
RAW_OPCODE_jne_short = 0x75,
RAW_OPCODE_jcc_short_end = 0x7f,
RAW_OPCODE_jcc_byte1 = 0x0f,
RAW_OPCODE_jcc_byte2_start = 0x80,
RAW_OPCODE_jcc_byte2_end = 0x8f,
RAW_OPCODE_loop_start = 0xe0,
RAW_OPCODE_loop_end = 0xe3,
RAW_OPCODE_lea = 0x8d,
RAW_OPCODE_SIGILL = 0x0b0f,
RAW_PREFIX_jcc_not_taken = 0x2e,
RAW_PREFIX_jcc_taken = 0x3e,
RAW_PREFIX_lock = 0xf0,
RAW_PREFIX_xacquire = 0xf2,
RAW_PREFIX_xrelease = 0xf3,
};
enum { /* FIXME: vs RAW_OPCODE_* enum */
CS_SEG_OPCODE = RAW_PREFIX_jcc_not_taken,
DS_SEG_OPCODE = RAW_PREFIX_jcc_taken,
ES_SEG_OPCODE = 0x26,
FS_SEG_OPCODE = 0x64,
GS_SEG_OPCODE = 0x65,
SS_SEG_OPCODE = 0x36,
/* For Windows, we piggyback on native TLS via gs for x64 and fs for x86.
* For Linux, we steal a segment register, and so use fs for x86 (where
* pthreads uses gs) and gs for x64 (where pthreads uses fs) (presumably
* to avoid conflicts w/ wine).
*/
# ifdef X64
TLS_SEG_OPCODE = GS_SEG_OPCODE,
# else
TLS_SEG_OPCODE = FS_SEG_OPCODE,
# endif
DATA_PREFIX_OPCODE = 0x66,
ADDR_PREFIX_OPCODE = 0x67,
REPNE_PREFIX_OPCODE = 0xf2,
REP_PREFIX_OPCODE = 0xf3,
REX_PREFIX_BASE_OPCODE = 0x40,
REX_PREFIX_W_OPFLAG = 0x8,
REX_PREFIX_R_OPFLAG = 0x4,
REX_PREFIX_X_OPFLAG = 0x2,
REX_PREFIX_B_OPFLAG = 0x1,
REX_PREFIX_ALL_OPFLAGS = 0xf,
MOV_REG2MEM_OPCODE = 0x89,
MOV_MEM2REG_OPCODE = 0x8b,
MOV_XAX2MEM_OPCODE = 0xa3, /* no ModRm */
MOV_MEM2XAX_OPCODE = 0xa1, /* no ModRm */
MOV_IMM2XAX_OPCODE = 0xb8, /* no ModRm */
MOV_IMM2XBX_OPCODE = 0xbb, /* no ModRm */
MOV_IMM2MEM_OPCODE = 0xc7, /* has ModRm */
JECXZ_OPCODE = 0xe3,
JMP_SHORT_OPCODE = 0xeb,
JMP_OPCODE = 0xe9,
JNE_OPCODE_1 = 0x0f,
SAHF_OPCODE = 0x9e,
LAHF_OPCODE = 0x9f,
SETO_OPCODE_1 = 0x0f,
SETO_OPCODE_2 = 0x90,
ADD_AL_OPCODE = 0x04,
INC_MEM32_OPCODE_1 = 0xff, /* has /0 as well */
MODRM16_DISP16 = 0x06, /* see vol.2 Table 2-1 for modR/M */
SIB_DISP32 = 0x25, /* see vol.2 Table 2-1 for modR/M */
RET_NOIMM_OPCODE = 0xc3,
RET_IMM_OPCODE = 0xc2,
MOV_IMM_EDX_OPCODE = 0xba,
VEX_2BYTE_PREFIX_OPCODE = 0xc5,
VEX_3BYTE_PREFIX_OPCODE = 0xc4,
EVEX_PREFIX_OPCODE = 0x62,
};
#elif defined(ARM)
enum {
CBZ_BYTE_A = 0xb1, /* this assumes the top bit of the disp is 0 */
CBNZ_BYTE_A = 0xb9, /* this assumes the top bit of the disp is 0 */
};
#elif defined(AARCH64)
enum {
RAW_NOP_INST = 0xd503201f,
};
#endif
#include "instr_inline_api.h"
#endif /* _INSTR_H_ */