* 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.
*/
#ifndef _OPND_H_
#define _OPND_H_ 1
#ifdef WINDOWS
* "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
#define DR_REG_ENUM_COMPATIBILITY 1
* needs to avoid it.
*/
#ifdef DR_NO_FAST_IR
# undef DR_FAST_IR
# undef INSTR_INLINE
#else
# define DR_FAST_IR 1
#endif
* 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 ***
*************************/
* instr_shared.c, which wants to use C99 extern inline. Otherwise, DR_FAST_IR
* determines whether our instr routines are inlined.
*/
#ifndef INSTR_INLINE
# ifdef DR_FAST_IR
# define INSTR_INLINE inline
# else
# define INSTR_INLINE
# endif
#endif
extern const char *const reg_names[];
extern const reg_id_t dr_reg_fixer[];
#ifdef X86
# define REG_START_SPILL DR_REG_XAX
# define REG_STOP_SPILL DR_REG_XDI
#elif defined(AARCHXX)
# define REG_START_SPILL DR_REG_R0
# define REG_STOP_SPILL DR_REG_R10
#elif defined(RISCV64)
# define REG_START_SPILL DR_REG_A0
# define REG_STOP_SPILL DR_REG_A5
#endif
#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
#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 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 ))
#ifdef X86
* DynamoRIO needs to keep track of their values process-wide.
*/
# define DEBUG_REGISTERS_NB 4
# 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];
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
opnd_t
opnd_create_immed_float_for_opcode(uint opcode);
bool
opnd_is_valid(opnd_t opnd);
int
opnd_get_reg_dcontext_offs(reg_id_t reg);
int
opnd_get_reg_mcontext_offs(reg_id_t reg);
reg_t
reg_get_value_priv(reg_id_t reg, priv_mcontext_t *mc);
void
reg_set_value_priv(reg_id_t reg, priv_mcontext_t *mc, reg_t value);
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);
#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);
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);
opnd_t
opnd_create_sized_tls_slot(int offs, opnd_size_t size);
#endif
#define XSP_SZ ((ssize_t)sizeof(reg_t))
enum {
#ifdef X86
DR_SYSNUM_REG = DR_REG_EAX,
# ifdef X64
# ifdef UNIX
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
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
* 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
#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
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
#elif defined(RISCV64)
# define MCXT_FLD_FIRST_REG x0
# define MCXT_FLD_SYSNUM_REG a7
#endif
extern const reg_id_t d_r_regparms[];
uint
opnd_immed_float_arch(uint opcode);
#ifdef AARCHXX
# define DR_REG_STOLEN_MIN IF_X64_ELSE(DR_REG_X9, DR_REG_R8)
# define DR_REG_STOLEN_MAX IF_X64_ELSE(DR_REG_X29, DR_REG_R12)
extern reg_id_t dr_reg_stolen;
#endif
#endif