blob: 8379562188c913ef2dde538828f8d23ea6b044fa [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011-2024 Google, Inc. All rights reserved.
* Copyright (c) 2001-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) 2001 Hewlett-Packard Company */
/* decode_shared.c -- shared decoding data */
#include "../globals.h"
#include "arch.h"
#include "instr.h"
#include "decode.h"
#ifdef DEBUG
/* case 10450: give messages to clients */
/* we can't undef ASSERT b/c of DYNAMO_OPTION */
# undef ASSERT_TRUNCATE
# undef ASSERT_BITFIELD_TRUNCATE
# undef ASSERT_NOT_REACHED
# define ASSERT_TRUNCATE DO_NOT_USE_ASSERT_USE_CLIENT_ASSERT_INSTEAD
# define ASSERT_BITFIELD_TRUNCATE DO_NOT_USE_ASSERT_USE_CLIENT_ASSERT_INSTEAD
# define ASSERT_NOT_REACHED DO_NOT_USE_ASSERT_USE_CLIENT_ASSERT_INSTEAD
#endif
/* Arch-specific routines */
#ifdef DEBUG
void
encode_debug_checks(void);
void
decode_debug_checks_arch(void);
#endif
const char *const size_names[] = {
"OPSZ_NA",
"OPSZ_lea",
"OPSZ_1",
"OPSZ_2",
"OPSZ_4",
"OPSZ_6",
"OPSZ_8",
"OPSZ_10",
"OPSZ_16",
"OPSZ_14",
"OPSZ_28",
"OPSZ_94",
"OPSZ_108",
"OPSZ_512",
"OPSZ_2_short1",
"OPSZ_4_short2",
"OPSZ_4_rex8_short2",
"OPSZ_4_rex8",
"OPSZ_6_irex10_short4",
"OPSZ_8_short2",
"OPSZ_8_short4",
"OPSZ_28_short14",
"OPSZ_108_short94",
"OPSZ_4x8",
"OPSZ_6x10",
"OPSZ_4x8_short2",
"OPSZ_4x8_short2xi8",
"OPSZ_4_short2xi4",
"OPSZ_1_reg4",
"OPSZ_2_reg4",
"OPSZ_4_reg16",
"OPSZ_xsave",
"OPSZ_12",
"OPSZ_32",
"OPSZ_40",
"OPSZ_32_short16",
"OPSZ_8_rex16",
"OPSZ_8_rex16_short4",
"OPSZ_12_rex40_short6",
"OPSZ_16_vex32",
"OPSZ_15",
"OPSZ_3",
"OPSZ_1b",
"OPSZ_2b",
"OPSZ_3b",
"OPSZ_4b",
"OPSZ_5b",
"OPSZ_6b",
"OPSZ_7b",
"OPSZ_9b",
"OPSZ_10b",
"OPSZ_11b",
"OPSZ_12b",
"OPSZ_20b",
"OPSZ_25b",
"OPSZ_VAR_REGLIST",
"OPSZ_20",
"OPSZ_24",
"OPSZ_36",
"OPSZ_44",
"OPSZ_48",
"OPSZ_52",
"OPSZ_56",
"OPSZ_60",
"OPSZ_64",
"OPSZ_68",
"OPSZ_72",
"OPSZ_76",
"OPSZ_80",
"OPSZ_84",
"OPSZ_88",
"OPSZ_92",
"OPSZ_96",
"OPSZ_100",
"OPSZ_104",
"OPSZ_112",
"OPSZ_116",
"OPSZ_120",
"OPSZ_124",
"OPSZ_128",
"OPSZ_SCALABLE",
"OPSZ_SCALABLE_PRED",
"OPSZ_16_vex32_evex64",
"OPSZ_vex32_evex64",
"OPSZ_16_of_32_evex64",
"OPSZ_32_of_64",
"OPSZ_4_of_32_evex64",
"OPSZ_8_of_32_evex64",
"OPSZ_8x16",
"OPSZ_256",
"OPSZ_192",
"OPSZ_1_of_4",
"OPSZ_2_of_4",
"OPSZ_1_of_8",
"OPSZ_2_of_8",
"OPSZ_4_of_8",
"OPSZ_1_of_16",
"OPSZ_2_of_16",
"OPSZ_4_of_16",
"OPSZ_4_rex8_of_16",
"OPSZ_8_of_16",
"OPSZ_12_of_16",
"OPSZ_12_rex8_of_16",
"OPSZ_14_of_16",
"OPSZ_15_of_16",
"OPSZ_16_of_32",
"OPSZ_half_16_vex32",
"OPSZ_half_16_vex32_evex64",
"OPSZ_quarter_16_vex32",
"OPSZ_quarter_16_vex32_evex64",
"OPSZ_eighth_16_vex32",
"OPSZ_eighth_16_vex32_evex64",
};
/* AArch64 SVE or RISC-V Vector's vector length in bits. */
int vector_length;
/* AArch64 SVE valid vector lengths. */
int sve_vector_lengths[] = { 128, 256, 384, 512, 640, 768, 896, 1024,
1152, 1280, 1408, 1536, 1664, 1792, 1920, 2048 };
bool
dr_set_vector_length(int vl)
{
#if defined(AARCH64)
for (int i = 0; i < sizeof(sve_vector_lengths) / sizeof(sve_vector_lengths[0]); i++) {
if (vl == sve_vector_lengths[i]) {
vector_length = vl;
return true;
}
}
#elif defined(RISCV64)
const int riscv_vlen_min = 64;
const int riscv_vlen_max = 65536;
if (vl >= riscv_vlen_min && vl <= riscv_vlen_max && IS_POWER_OF_2(vl)) {
vector_length = vl;
return true;
}
#endif
/* Make unusual values visible in case our internal uses mess up. */
ASSERT_CURIOSITY(false);
return false;
}
int
dr_get_vector_length(void)
{
return vector_length;
}
/* point at this when you need a canonical invalid instr
* type is OP_INVALID so can be copied to instr->opcode
*/
#define xx 0 /* TYPE_NONE */, OPSZ_NA
const instr_info_t invalid_instr = { OP_INVALID,
0x000000,
#ifdef X86
DR_INSTR_CATEGORY_UNCATEGORIZED,
#endif
"(bad)",
xx,
xx,
xx,
xx,
xx,
0,
0,
0 };
#undef xx
/* PR 302344: used for shared traces -tracedump_origins where we
* need to change the mode but we have no dcontext.
* We update this in d_r_decode_init() once we have runtime options,
* but this is the only version for drdecodelib.
*/
static dr_isa_mode_t initexit_isa_mode = DEFAULT_ISA_MODE_STATIC;
/* The decode and encode routines use a per-thread persistent flag that
* indicates which processor mode to use. This routine sets that flag to the
* indicated value and optionally returns the old value. Be sure to restore the
* old value prior to any further application execution to avoid problems in
* mis-interpreting application code.
*/
bool
dr_set_isa_mode(void *drcontext, dr_isa_mode_t new_mode,
dr_isa_mode_t *old_mode_out DR_PARAM_OUT)
{
dcontext_t *dcontext = (dcontext_t *)drcontext;
dr_isa_mode_t old_mode;
/* We would disallow but some early init routines need to use global heap */
if (dcontext == GLOBAL_DCONTEXT)
dcontext = get_thread_private_dcontext();
/* Support GLOBAL_DCONTEXT or NULL for standalone/static modes */
if (dcontext == NULL || dcontext == GLOBAL_DCONTEXT) {
#if !defined(STANDALONE_DECODER)
CLIENT_ASSERT(!dynamo_initialized || dynamo_exited || dcontext == GLOBAL_DCONTEXT,
"internal isa mode error");
#endif
old_mode = initexit_isa_mode;
if (is_isa_mode_legal(new_mode))
initexit_isa_mode = new_mode;
} else {
old_mode = dcontext->isa_mode;
if (is_isa_mode_legal(new_mode))
dcontext->isa_mode = new_mode;
}
if (old_mode_out != NULL)
*old_mode_out = old_mode;
return is_isa_mode_legal(new_mode);
}
/* The decode and encode routines use a per-thread persistent flag that
* indicates which processor mode to use. This routine returns the value of
* that flag.
*/
dr_isa_mode_t
dr_get_isa_mode(void *drcontext)
{
dcontext_t *dcontext = (dcontext_t *)drcontext;
#if !defined(STANDALONE_DECODER) && defined(DEBUG)
dcontext_t *orig_dcontext = dcontext;
#endif
/* We would disallow but some early init routines need to use global heap */
if (dcontext == GLOBAL_DCONTEXT)
dcontext = get_thread_private_dcontext();
/* Support GLOBAL_DCONTEXT or NULL for standalone/static modes */
if (dcontext == NULL || dcontext == GLOBAL_DCONTEXT) {
#if !defined(STANDALONE_DECODER)
CLIENT_ASSERT(!dynamo_initialized || dynamo_exited ||
orig_dcontext == GLOBAL_DCONTEXT,
"internal isa mode error");
#endif
return initexit_isa_mode;
} else
return dcontext->isa_mode;
}
#ifdef DEBUG
void
decode_debug_checks(void)
{
CLIENT_ASSERT(sizeof(size_names) / sizeof(size_names[0]) == OPSZ_LAST_ENUM,
"size_names missing an entry");
encode_debug_checks();
decode_debug_checks_arch();
}
#endif
void
d_r_decode_init(void)
{
/* DEFAULT_ISA_MODE is no longer constant so we set it here */
initexit_isa_mode = DEFAULT_ISA_MODE;
DODEBUG({ decode_debug_checks(); });
}