blob: 09b4e0b4dc1650a00d4c508c1bd500a5aa5589ad [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 */
/* file "opnd.h" -- opnd_t definitions and utilities */
#ifndef _OPND_H_
#define _OPND_H_ 1
#ifdef WINDOWS
/* disabled warning for
* "nonstandard extension used : bit field types other than int"
* so we can use bitfields on our now-byte-sized reg_id_t type in opnd_t.
*/
# pragma warning(disable : 4214)
#endif
/* to avoid changing all our internal REG_ constants we define this for DR itself */
#define DR_REG_ENUM_COMPATIBILITY 1
/* 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
/* drpreinject.dll doesn't link in instr_shared.c so we can't include our inline
* functions. We want to use our inline functions for the standalone decoder
* and everything else, so we single out drpreinject.
*/
#ifdef RC_IS_PRELOAD
# undef DR_FAST_IR
#endif
#include "opnd_api.h"
/*************************
*** opnd_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
/* indexed by enum */
extern const char *const reg_names[];
extern const char *const d_r_reg_virtual_names[];
extern const reg_id_t dr_reg_fixer[];
extern const reg_id_t d_r_reg_id_to_virtual[];
#ifdef X86
# define REG_START_SPILL DR_REG_XAX
# define REG_STOP_SPILL DR_REG_XDI
#elif defined(AARCHXX)
/* We only normally use r0-r5 but we support more in translation code */
# define REG_START_SPILL DR_REG_R0
# define REG_STOP_SPILL DR_REG_R10 /* r10 might be used in syscall mangling */
#elif defined(RISCV64)
# define REG_START_SPILL DR_REG_A0
# define REG_STOP_SPILL DR_REG_A5
#endif /* RISCV64 */
#define REG_SPILL_NUM (REG_STOP_SPILL - REG_START_SPILL + 1)
#ifndef INT8_MIN
# define INT8_MIN SCHAR_MIN
# define INT8_MAX SCHAR_MAX
# define INT16_MIN SHRT_MIN
# define INT16_MAX SHRT_MAX
# define INT32_MIN INT_MIN
# define INT32_MAX INT_MAX
#endif
/* typedef is in globals.h */
#ifndef DR_FAST_IR
struct _opnd_t {
# ifdef X64
uint black_box_uint;
uint64 black_box_uint64;
# else
uint black_box_uint[3];
# endif
};
#endif
/* We assert that our fields are packed properly in d_r_arch_init().
* We could use #pragma pack to shrink x64 back down to 12 bytes (it's at 16
* b/c the struct is aligned to its max field align which is 8), but
* probably not much gain since in either case it's passed/returned as a pointer
* and the temp memory allocated is 16-byte aligned (on Windows; for
* Linux it is passed in two consecutive registers I believe, but
* still 12 bytes vs 16 makes no difference).
*/
#define EXPECTED_SIZEOF_OPND (3 * sizeof(uint) IF_X64(+4 /*struct size padding*/))
#ifdef X86
/* Debug registers are used for breakpoint with x86.
* DynamoRIO needs to keep track of their values process-wide.
*/
# define DEBUG_REGISTERS_NB 4
/* Dr7 flags mask to enable debug registers */
# define DEBUG_REGISTERS_FLAG_ENABLE_DR0 0x3
# define DEBUG_REGISTERS_FLAG_ENABLE_DR1 0xc
# define DEBUG_REGISTERS_FLAG_ENABLE_DR2 0x30
# define DEBUG_REGISTERS_FLAG_ENABLE_DR3 0xc0
extern app_pc d_r_debug_register[DEBUG_REGISTERS_NB];
/* Tells if instruction will trigger an exception because of debug register. */
static inline bool
debug_register_fire_on_addr(app_pc pc)
{
ASSERT(DEBUG_REGISTERS_NB == 4);
return (pc != NULL &&
(pc == d_r_debug_register[0] || pc == d_r_debug_register[1] ||
pc == d_r_debug_register[2] || pc == d_r_debug_register[3]));
}
#endif
/* functions to build an operand */
/* not exported */
opnd_t
opnd_create_immed_float_for_opcode(uint opcode);
/* predicate functions */
/* Check if the operand kind and size fields are valid */
bool
opnd_is_valid(opnd_t opnd);
/* not exported */
int
opnd_get_reg_dcontext_offs(reg_id_t reg);
int
opnd_get_reg_mcontext_offs(reg_id_t reg);
/* Assumes that \p reg is a DR_REG_ 32-bit register constant.
* Returns the corresponding DR_ISA_REGDEPS virtual register of \p reg, which holds 8-bit
* DR_REG_V values.
*/
reg_id_t
d_r_reg_to_virtual(reg_id_t reg);
/* internal version */
reg_t
reg_get_value_priv(reg_id_t reg, priv_mcontext_t *mc);
/* internal version */
void
reg_set_value_priv(reg_id_t reg, priv_mcontext_t *mc, reg_t value);
/* internal version */
app_pc
opnd_compute_address_priv(opnd_t opnd, priv_mcontext_t *mc);
app_pc
opnd_compute_address_helper(opnd_t opnd, priv_mcontext_t *mc, ptr_int_t scaled_index);
bool
opnd_is_abs_base_disp(opnd_t opnd);
#if defined(AARCH64)
/* Internal function shared with vector address calculation */
ptr_int_t
d_r_compute_scaled_index_aarch64(opnd_t opnd, reg_t index_val);
#endif
#ifndef STANDALONE_DECODER
opnd_t
opnd_create_dcontext_field(dcontext_t *dcontext, int offs);
opnd_t
opnd_create_dcontext_field_byte(dcontext_t *dcontext, int offs);
opnd_t
opnd_create_dcontext_field_sz(dcontext_t *dcontext, int offs, opnd_size_t sz);
/* basereg, if left as REG_NULL, is assumed to be xdi (xsi for upcontext) */
opnd_t
opnd_create_dcontext_field_via_reg_sz(dcontext_t *dcontext, reg_id_t basereg, int offs,
opnd_size_t sz);
opnd_t
opnd_create_dcontext_field_via_reg(dcontext_t *dcontext, reg_id_t basereg, int offs);
opnd_t
update_dcontext_address(opnd_t op, dcontext_t *old_dcontext, dcontext_t *new_dcontext);
opnd_t
opnd_create_tls_slot(int offs);
/* For size, use a OPSZ_ value from decode.h, typically OPSZ_1 or OPSZ_4 */
opnd_t
opnd_create_sized_tls_slot(int offs, opnd_size_t size);
#endif /* !STANDALONE_DECODER */
/* stack slot width */
#define XSP_SZ ((ssize_t)sizeof(reg_t))
/* This should be kept in sync w/ the defines in x86/x86.asm */
enum {
#ifdef X86
DR_SYSNUM_REG = DR_REG_EAX,
# ifdef X64
# ifdef UNIX
/* SysV ABI calling convention */
NUM_REGPARM = 6,
REGPARM_0 = REG_RDI,
REGPARM_1 = REG_RSI,
REGPARM_2 = REG_RDX,
REGPARM_3 = REG_RCX,
REGPARM_4 = REG_R8,
REGPARM_5 = REG_R9,
REGPARM_MINSTACK = 0,
REDZONE_SIZE = 128,
# else
/* Intel/Microsoft calling convention */
NUM_REGPARM = 4,
REGPARM_0 = REG_RCX,
REGPARM_1 = REG_RDX,
REGPARM_2 = REG_R8,
REGPARM_3 = REG_R9,
REGPARM_MINSTACK = 4 * sizeof(XSP_SZ),
REDZONE_SIZE = 0,
# endif
/* In fact, for Windows the stack pointer is supposed to be
* 16-byte aligned at all times except in a prologue or epilogue.
* The prologue will always adjust by 16*n+8 since push of retaddr
* always makes stack pointer not 16-byte aligned.
*/
REGPARM_END_ALIGN = 16,
# else
NUM_REGPARM = 0,
REGPARM_MINSTACK = 0,
REDZONE_SIZE = 0,
# ifdef MACOS
REGPARM_END_ALIGN = 16,
# else
REGPARM_END_ALIGN = sizeof(XSP_SZ),
# endif
# endif /* 64/32 */
#elif defined(AARCHXX)
REGPARM_0 = DR_REG_R0,
REGPARM_1 = DR_REG_R1,
REGPARM_2 = DR_REG_R2,
REGPARM_3 = DR_REG_R3,
# ifdef X64
DR_SYSNUM_REG = DR_REG_R8,
REGPARM_4 = DR_REG_R4,
REGPARM_5 = DR_REG_R5,
REGPARM_6 = DR_REG_R6,
REGPARM_7 = DR_REG_R7,
NUM_REGPARM = 8,
# else
DR_SYSNUM_REG = DR_REG_R7,
NUM_REGPARM = 4,
# endif /* 64/32 */
REDZONE_SIZE = 0,
REGPARM_MINSTACK = 0,
REGPARM_END_ALIGN = 8,
#elif defined(RISCV64)
DR_SYSNUM_REG = DR_REG_A7,
REGPARM_0 = DR_REG_A0,
REGPARM_1 = DR_REG_A1,
REGPARM_2 = DR_REG_A2,
REGPARM_3 = DR_REG_A3,
REGPARM_4 = DR_REG_A4,
REGPARM_5 = DR_REG_A5,
NUM_REGPARM = 6,
REDZONE_SIZE = 0,
REGPARM_MINSTACK = 0,
REGPARM_END_ALIGN = 8,
#endif
};
#ifdef X86
# define MCXT_FLD_FIRST_REG xdi
# define MCXT_FLD_SYSNUM_REG xax
#elif defined(AARCHXX)
# define MCXT_FLD_FIRST_REG r0
# ifdef X64
# ifdef MACOS
# define MCXT_FLD_SYSNUM_REG r16
# else
# define MCXT_FLD_SYSNUM_REG r8
# endif
# else
# define MCXT_FLD_SYSNUM_REG r7
# endif /* 64/32 */
#elif defined(RISCV64)
# define MCXT_FLD_FIRST_REG x0
# define MCXT_FLD_SYSNUM_REG a7
#endif
extern const reg_id_t d_r_regparms[];
/* arch-specific */
uint
opnd_immed_float_arch(uint opcode);
#ifdef AARCHXX
# define DR_REG_STOLEN_MIN IF_X64_ELSE(DR_REG_X9, DR_REG_R8) /* DR_REG_SYSNUM + 1 */
# define DR_REG_STOLEN_MAX IF_X64_ELSE(DR_REG_X29, DR_REG_R12)
/* DR's stolen register for TLS access. */
extern reg_id_t dr_reg_stolen;
#elif defined(RISCV64)
# define DR_REG_STOLEN_MIN DR_REG_X18 /* DR_REG_SYSNUM + 1 */
# define DR_REG_STOLEN_MAX DR_REG_X31
/* DR's stolen register for TLS access. */
extern reg_id_t dr_reg_stolen;
#elif defined(RISCV64)
/* DR's stolen register for TLS access */
# define DR_REG_STOLEN_MIN DR_REG_X18 /* DR_REG_SYSNUM + 1 */
# define DR_REG_STOLEN_MAX DR_REG_X31
extern reg_id_t dr_reg_stolen;
#endif
#ifdef AARCH64
# if !defined(DR_HOST_NOT_TARGET) && !defined(STANDALONE_DECODER) && \
!defined(BUILD_TESTS)
/* Size of the SVE Z vector registers in bytes. */
# define OPSZ_SVE_VECLEN_BYTES opnd_size_from_bytes(proc_get_vector_length_bytes())
/* Size of the SVE P predicate registers in bytes. */
# define OPSZ_SVE_PREDLEN_BYTES \
opnd_size_from_bytes(proc_get_vector_length_bytes() / 8)
# else
/* SVE vector length for off-line decoder set using dr_set_vector_length() or -vl
* option with drdisas,
* e.g.
* $ drdisas -vl 256 e58057a1 85865e6b
* e58057a1 str %z1 -> +0x05(%x29)[32byte]
* 85865e6b ldr +0x37(%x19)[32byte] -> %z11
* $
*/
/* Size of the SVE Z vector registers in bytes. */
# define OPSZ_SVE_VECLEN_BYTES opnd_size_from_bytes(dr_get_vector_length() / 8)
/* Size of the SVE P predicate registers in bytes. */
# define OPSZ_SVE_PREDLEN_BYTES \
opnd_size_from_bytes((dr_get_vector_length() / 8) / 8)
# endif
#endif /*AARCH64*/
#ifdef RISCV64
# if !defined(DR_HOST_NOT_TARGE) && !defined(STANDALONE_DECODER) && \
!defined(BUILD_TESTS)
/* Size of the RVV registers in bytes. */
# define OPSZ_RVV_VECLEN_BYTES opnd_size_from_bytes(proc_get_vector_length_bytes())
# else
# define OPSZ_RVV_VECLEN_BYTES opnd_size_from_bytes(dr_get_vector_length() / 8)
# endif
#endif
#endif /* _OPND_H_ */