* Copyright (c) 2011-2022 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.
*/
#include "../globals.h"
#include "decode_fast.h"
#include "../link.h"
#include "arch.h"
#include "instr.h"
#include "instr_create_shared.h"
#include "decode.h"
#include "decode_private.h"
#include "disassemble.h"
#ifdef DEBUG
# 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
instructions so that we can determine the length of the decode
instruction. All code below based on tables in the ``Intel
Architecture Software Developer's Manual,'' Volume 2: Instruction
Set Reference, 1999.
This decoder assumes that we are running in 32-bit, flat-address mode.
*/
or secondary) opcode byte. The upper opcode nibble defines the rows,
starting with 0 at the top. The lower opcode nibble defines the
columns, starting with 0 at left. */
indexed by the 1st (primary) opcode byte. Zero entries are
reserved opcodes. */
static const byte fixed_length[256] = {
1, 1, 1, 1, 2, 5, 1, 1, 1,
1, 1, 1, 2, 5, 1, 1,
1, 1, 1, 1, 2, 5, 1, 1, 1,
1, 1, 1, 2, 5, 1, 1,
1, 1, 1, 1, 2, 5, 1, 1, 1,
1, 1, 1, 2, 5, 1, 1,
1, 1, 1, 1, 2, 5, 1, 1, 1,
1, 1, 1, 2, 5, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 5,
5, 2, 2, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2,
2, 5, 2, 2, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 7, 1, 1, 1, 1, 1,
5, 5, 5, 5, 1, 1, 1, 1, 2,
5, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 5,
5, 5, 5, 5, 5, 5, 5,
2, 2, 3, 1, 1, 1, 2, 5, 4,
1, 3, 1, 1, 2, 1, 1,
1, 1, 1, 1, 2, 2, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 5,
5, 7, 2, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1
};
depends upon the existence of an operand-size byte. The table is
indexed by the 1st (primary) opcode byte. Entries with non-zero
values indicate opcodes with a variable-length immediate field. We
use this table if we've seen a operand-size prefix byte to adjust
the fixed_length from dword to word.
*/
static const sbyte immed_adjustment[256] = {
0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0,
0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0,
0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0,
0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2,
0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#ifdef X64
static const sbyte immed_adjustment_intel64[256] = {
0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0,
0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0,
0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0,
0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2,
0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#endif
* depends upon the existence of an address-size byte. The table is
* indexed by the 1st (primary) opcode byte.
* The value here is doubled for x64 mode.
*/
static const sbyte disp_adjustment[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-2, -2, -2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#ifdef X64
* in x64 mode. We fit two types of adjustments in here:
* default-size adjustments (positive numbers) and rex.w-prefix-based
* adjustments (negative numbers, to be made positive when applied).
*/
static const sbyte x64_adjustment[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, -4, -4, -4, -4, -4, -4, -4, -4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#endif
* part of the x86 instruction length. */
static int
sizeof_modrm(dcontext_t *dcontext, byte *pc, bool addr16, byte **rip_rel_pc);
static int
sizeof_fp_op(dcontext_t *dcontext, byte *pc, bool addr16, byte **rip_rel_pc);
static int
sizeof_escape(dcontext_t *dcontext, byte *pc, bool addr16, byte **rip_rel_pc);
static int
sizeof_3byte_38(dcontext_t *dcontext, byte *pc, bool addr16, bool vex, byte **rip_rel_pc);
static int
sizeof_3byte_3a(dcontext_t *dcontext, byte *pc, bool addr16, byte **rip_rel_pc);
enum {
VARLEN_NONE,
VARLEN_MODRM,
VARLEN_FP_OP,
VARLEN_ESCAPE,
VARLEN_3BYTE_38_ESCAPE,
VARLEN_3BYTE_3A_ESCAPE,
VARLEN_RIP_REL_1BYTE,
VARLEN_RIP_REL_4BYTE,
};
#define m VARLEN_MODRM
#define f VARLEN_FP_OP
#define e VARLEN_ESCAPE
#define r1 VARLEN_RIP_REL_1BYTE
#define r4 VARLEN_RIP_REL_4BYTE
the variable part of the x86 instruction. This table
is indexed by the primary opcode. */
static const byte variable_length[256] = {
m, m, m, m, 0, 0, 0, 0, m, m, m, m, 0, 0, 0, e,
m, m, m, m, 0, 0, 0, 0, m, m, m, m, 0, 0, 0, 0,
m, m, m, m, 0, 0, 0, 0, m, m, m, m, 0, 0, 0, 0,
m, m, m, m, 0, 0, 0, 0, m, m, m, m, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, m, m, 0, 0, 0, 0, 0, m, 0, m, 0, 0, 0, 0,
r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1, r1,
m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
m, m, 0, 0, m, m, m, m, 0, 0, 0, 0, 0, 0, 0, 0,
m, m, m, m, 0, 0, 0, 0, f, f, f, f, f, f, f, f,
r1, r1, r1, r1, 0, 0, 0, 0, r4, r4, 0, r1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, m, m, 0, 0, 0, 0, 0, 0, m, m
};
#undef m
#undef f
#undef e
* This table is indexed by the 2nd opcode byte. Zero entries are
* reserved/bad opcodes.
* N.B.: none of these need adjustment for data16 or addr16.
*
* 0f0f has extra suffix opcode byte
* 0f78 has immeds depending on prefixes: handled in decode_sizeof()
*/
static const byte escape_fixed_length[256] = {
1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 2, 1, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1,
1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
};
#define m VARLEN_MODRM
#define e1 VARLEN_3BYTE_38_ESCAPE
#define e2 VARLEN_3BYTE_3A_ESCAPE
the variable part of the escaped x86 instruction. This table
is indexed by the 2nd opcode byte. */
static const byte escape_variable_length[256] = {
m, m, m, m, 0, 0, 0, 0, 0, 0, 0, 0, 0, m, 0, m,
m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m,
m, m, m, m, 0, 0, 0, 0, m, m, m, m, m, m, m, m,
0, 0, 0, 0, 0, 0, 0, 0, e1, 0, e2, 0, 0, 0, 0, 0,
m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m,
m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m,
m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m,
m, m, m, m, m, m, m, 0, m, m, m, m, m, m, m, m,
r4, r4, r4, r4, r4, r4, r4, r4, r4, r4, r4, r4, r4, r4, r4, r4,
m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m,
0, 0, 0, m, m, m, 0, 0, 0, 0, 0, m, m, m, m, m,
m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m,
m, m, m, m, m, m, m, m, 0, 0, 0, 0, 0, 0, 0, 0,
m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m,
m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m,
m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, 0
};
#undef m
#undef e
* This table is indexed by the 3rd opcode byte. Zero entries are
* reserved/bad opcodes.
* N.B.: ALL of these have modrm bytes, and NONE of these need adjustment for data16
* or addr16.
*/
#if 0
static const byte threebyte_38_fixed_length[256] = {
1,1,1,1, 1,1,1,1, 1,1,1,1, 0,0,0,0,
1,0,0,0, 1,1,0,1, 0,0,0,0, 1,1,1,0,
1,1,1,1, 1,1,0,0, 1,1,1,1, 0,0,0,0,
1,1,1,1, 1,1,0,1, 1,1,1,1, 1,1,1,1,
1,1,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1,1,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
};
#endif
#if 0
static const byte threebyte_3a_fixed_length[256] = {
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1,
0,0,0,0, 1,1,1,1, 1,1,1,1, 1,1,1,0,
1,1,1,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,1,1,1, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1,1,1,1, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
};
#endif
static const byte threebyte_38_vex_extra[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static const byte xop_9_extra[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static const byte xop_a_extra[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
* If num_prefixes is non-NULL, returns the number of prefix bytes.
* If rip_rel_pos is non-NULL, returns the offset into the instruction
* of a rip-relative addressing displacement (for data only: ignores
* control-transfer relative addressing), or 0 if none.
* May return 0 size for certain invalid instructions
*/
int
decode_sizeof_ex(void *drcontext, byte *start_pc, int *num_prefixes, uint *rip_rel_pos)
{
dcontext_t *dcontext = (dcontext_t *)drcontext;
byte *pc = start_pc;
uint opc = (uint)*pc;
int sz = 0;
ushort varlen;
bool word_operands = false;
bool qword_operands = false;
bool addr16 = false;
bool found_prefix = true;
bool rep_prefix = false;
bool evex_prefix = false;
byte reg_opcode;
byte *rip_rel_pc = NULL;
while (found_prefix) {
* prefixes that are part of the opcode xref PR 271878). We match
* read_instruction() in considering pre-prefix rex bytes as part of
* the following instr, event when ignored, rather then treating them
* as invalid. This in effect nops improperly placed rex prefixes which
* (xref PR 241563 and Intel Manual 2A 2.2.1) is the correct thing to do.
* Rex prefixes are 0x40-0x4f; >=0x48 has rex.w bit set.
*/
if (X64_MODE_DC(dcontext) && opc >= REX_PREFIX_BASE_OPCODE &&
opc <= (REX_PREFIX_BASE_OPCODE | REX_PREFIX_ALL_OPFLAGS)) {
if (opc >= (REX_PREFIX_BASE_OPCODE | REX_PREFIX_W_OPFLAG)) {
qword_operands = true;
if (word_operands)
word_operands = false;
}
opc = (uint) * (++pc);
sz += 1;
} else {
switch (opc) {
case DATA_PREFIX_OPCODE:
if (qword_operands)
qword_operands = false;
word_operands = true;
opc = (uint) * (++pc);
sz += 1;
break;
case REPNE_PREFIX_OPCODE:
case REP_PREFIX_OPCODE:
rep_prefix = true;
case RAW_PREFIX_lock:
case CS_SEG_OPCODE:
case DS_SEG_OPCODE:
case ES_SEG_OPCODE:
case FS_SEG_OPCODE:
case GS_SEG_OPCODE:
case SS_SEG_OPCODE:
opc = (uint) * (++pc);
sz += 1;
break;
case ADDR_PREFIX_OPCODE:
addr16 = true;
opc = (uint) * (++pc);
sz += 1;
break;
case EVEX_PREFIX_OPCODE: {
if (X64_MODE_DC(dcontext) || TEST(0x10, *(pc + 1))) {
evex_prefix = true;
}
}
case VEX_3BYTE_PREFIX_OPCODE:
case VEX_2BYTE_PREFIX_OPCODE: {
if (evex_prefix || X64_MODE_DC(dcontext) ||
TESTALL(MODRM_BYTE(3, 0, 0), *(pc + 1))) {
* - no vex-encoded instr size differs based on vex.w,
* so we don't bother to set qword_operands
* - no vex-encoded instr size differs based on prefixes,
* so we don't bother to decode vex.pp
*/
bool vex3 = (opc == VEX_3BYTE_PREFIX_OPCODE);
byte vex_mm = 0;
opc = (uint) * (++pc);
sz += 1;
if (vex3) {
vex_mm = (byte)(opc & 0x1f);
opc = (uint) * (++pc);
sz += 1;
} else if (evex_prefix) {
vex_mm = (byte)(opc & 0x3);
opc = (uint) * (++pc);
sz += 1;
opc = (uint) * (++pc);
sz += 1;
}
opc = (uint) * (++pc);
sz += 1;
if (num_prefixes != NULL)
*num_prefixes = sz;
bool implied_escape = (!vex3 && !evex_prefix) ||
((vex3 || evex_prefix) && (vex_mm == 1));
if (implied_escape) {
sz += sizeof_escape(dcontext, pc, addr16, &rip_rel_pc);
goto decode_sizeof_done;
} else if (vex_mm == 2) {
sz +=
sizeof_3byte_38(dcontext, pc - 1, addr16, true, &rip_rel_pc);
goto decode_sizeof_done;
} else if (vex_mm == 3) {
sz += sizeof_3byte_3a(dcontext, pc - 1, addr16, &rip_rel_pc);
goto decode_sizeof_done;
}
} else
found_prefix = false;
break;
}
case 0x8f: {
byte map_select = *(pc + 1) & 0x1f;
if (map_select >= 0x8) {
* differs vased on vex.w or vex.pp
*/
pc += 3;
sz += 3;
opc = (uint)*pc;
sz += 1;
if (num_prefixes != NULL)
*num_prefixes = sz;
sz += sizeof_modrm(dcontext, pc + 1, addr16, &rip_rel_pc);
if (map_select == 0x8) {
sz += 1;
} else if (map_select == 0x9)
sz += xop_9_extra[opc];
else if (map_select == 0xa)
sz += xop_a_extra[opc];
else {
ASSERT_CURIOSITY(false && "unknown XOP map_select");
}
goto decode_sizeof_done;
} else
found_prefix = false;
break;
}
default: found_prefix = false;
}
}
}
if (num_prefixes != NULL)
*num_prefixes = sz;
if (word_operands) {
#ifdef X64
* FIXME: what about 2-byte jcc?
*/
if (X64_MODE_DC(dcontext) && proc_get_vendor() == VENDOR_INTEL)
sz += immed_adjustment_intel64[opc];
else
#endif
sz += immed_adjustment[opc];
}
if (addr16) {
if (X64_MODE_DC(dcontext))
sz += 2 * disp_adjustment[opc];
else
sz += disp_adjustment[opc];
}
#ifdef X64
if (X64_MODE_DC(dcontext)) {
int adj64 = x64_adjustment[opc];
if (adj64 > 0)
sz += adj64;
else if (qword_operands)
sz += -adj64;
}
#endif
sz += fixed_length[opc];
varlen = variable_length[opc];
* since we need graceful failure
*/
if (varlen == VARLEN_MODRM)
sz += sizeof_modrm(dcontext, pc + 1, addr16, &rip_rel_pc);
else if (varlen == VARLEN_ESCAPE) {
sz += sizeof_escape(dcontext, pc + 1, addr16, &rip_rel_pc);
if (*(pc + 1) == 0x78) {
if (word_operands || rep_prefix) {
sz += 2;
}
}
} else if (varlen == VARLEN_FP_OP) {
sz += sizeof_fp_op(dcontext, pc + 1, addr16, &rip_rel_pc);
} else if (varlen == VARLEN_RIP_REL_1BYTE) {
rip_rel_pc = start_pc + sz - 1;
} else if (varlen == VARLEN_RIP_REL_4BYTE) {
rip_rel_pc = start_pc + sz - 4;
} else
CLIENT_ASSERT(varlen == VARLEN_NONE, "internal decoding error");
reg_opcode = (byte)(((*(pc + 1)) & 0x38) >> 3);
if (opc == 0xf6 && reg_opcode == 0) {
sz += 1;
} else if (opc == 0xf7 && reg_opcode == 0) {
if (word_operands)
sz += 2;
else
sz += 4;
}
if (opc == 0xc7 && *(pc + 1) == 0xf8)
rip_rel_pc = start_pc + sz - 4;
decode_sizeof_done:
if (rip_rel_pos != NULL) {
if (rip_rel_pc != NULL) {
CLIENT_ASSERT(CHECK_TRUNCATE_TYPE_uint(rip_rel_pc - start_pc),
"decode_sizeof: unknown rip_rel instr type");
*rip_rel_pos = (uint)(rip_rel_pc - start_pc);
} else
*rip_rel_pos = 0;
}
return sz;
}
int
decode_sizeof(void *drcontext, byte *start_pc,
int *num_prefixes _IF_X64(uint *rip_rel_pos))
{
dcontext_t *dcontext = (dcontext_t *)drcontext;
#ifdef X64
return decode_sizeof_ex(dcontext, start_pc, num_prefixes, rip_rel_pos);
#else
return decode_sizeof_ex(dcontext, start_pc, num_prefixes, NULL);
#endif
}
static int
sizeof_3byte_38(dcontext_t *dcontext, byte *pc, bool addr16, bool vex, byte **rip_rel_pc)
{
int sz = 1;
uint opc = *(++pc);
* use the threebyte_38_fixed_length[opc] entry and assume 1 */
if (vex)
sz += threebyte_38_vex_extra[opc];
sz += sizeof_modrm(dcontext, pc + 1, addr16, rip_rel_pc);
return sz;
}
static int
sizeof_3byte_3a(dcontext_t *dcontext, byte *pc, bool addr16, byte **rip_rel_pc)
{
pc++;
* use the threebyte_3a_fixed_length[opc] entry and assume 1 */
return 1 + sizeof_modrm(dcontext, pc + 1, addr16, rip_rel_pc) + 1;
}
* when you have identified the primary opcode as 0x0f. You pass this
* routine the next byte to determine the number of extra bytes in the
* entire instruction.
* May return 0 size for certain invalid instructions.
*/
static int
sizeof_escape(dcontext_t *dcontext, byte *pc, bool addr16, byte **rip_rel_pc)
{
uint opc = (uint)*pc;
int sz = escape_fixed_length[opc];
ushort varlen = escape_variable_length[opc];
* since we need graceful failure
*/
if (varlen == VARLEN_MODRM)
return sz + sizeof_modrm(dcontext, pc + 1, addr16, rip_rel_pc);
else if (varlen == VARLEN_3BYTE_38_ESCAPE) {
return sz + sizeof_3byte_38(dcontext, pc, addr16, false, rip_rel_pc);
} else if (varlen == VARLEN_3BYTE_3A_ESCAPE) {
return sz + sizeof_3byte_3a(dcontext, pc, addr16, rip_rel_pc);
} else if (varlen == VARLEN_RIP_REL_1BYTE) {
*rip_rel_pc = pc + sz - 1;
} else if (varlen == VARLEN_RIP_REL_4BYTE) {
*rip_rel_pc = pc + sz - 4;
} else
CLIENT_ASSERT(varlen == VARLEN_NONE, "internal decoding error");
return sz;
}
* this routine with the byte following the primary opcode byte when you
* know that the operation's next byte is a ModR/M byte. This routine
* passes back the size of the Eaddr specification in bytes based on the
* following encoding of Table 2-2.
*
* Mod R/M
* 0 1 2 3 4 5 6 7
* 0 1 1 1 1 * 5 1 1
* 1 2 2 2 2 3 2 2 2
* 2 5 5 5 5 6 5 5 5
* 3 1 1 1 1 1 1 1 1
* where (*) is 6 if base==5 and 2 otherwise.
*/
static int
sizeof_modrm(dcontext_t *dcontext, byte *pc, bool addr16, byte **rip_rel_pc)
{
int l = 0;
uint modrm = (uint)*pc;
int r_m = modrm & 0x7;
uint mod = modrm >> 6;
uint sib;
#ifdef X64
if (rip_rel_pc != NULL && X64_MODE_DC(dcontext) && mod == 0 && r_m == 5) {
*rip_rel_pc = pc + 1;
}
#endif
if (addr16 && !X64_MODE_DC(dcontext)) {
if (mod == 1)
return 2;
else if (mod == 2)
return 3;
else if (mod == 3)
return 1;
else {
CLIENT_ASSERT(mod == 0, "internal decoding error on addr16 prefix");
if (r_m == 6)
return 3;
else
return 1;
}
CLIENT_ASSERT(false, "internal decoding error on addr16 prefix");
}
* no change in disp sizes */
if (mod == 3)
return 1;
switch (mod) {
case 0: l = (r_m == 5) ? 5 : 1; break;
case 1: l = 2; break;
case 2: l = 5; break;
}
if (r_m == 4) {
l += 1;
sib = (uint)(*(pc + 1));
if ((sib & 0x7) == 5) {
if (mod == 0)
l += 4;
}
}
return l;
}
* this routine when you have identified the primary opcode as one in
* the range 0xb8 through 0xbf. You pass this routine the next byte
* to determine the number of extra bytes in the entire
* instruction. */
static int
sizeof_fp_op(dcontext_t *dcontext, byte *pc, bool addr16, byte **rip_rel_pc)
{
if (*pc > 0xbf)
return 1;
return sizeof_modrm(dcontext, pc, addr16, rip_rel_pc);
}
* would like to decode. Currently these are control-transfer
* instructions and interrupts.
* This table is indexed by the 1st (primary) opcode byte.
* A 0 indicates we are not interested, a 1 that we are.
* A 2 indicates a second opcode byte exists, a 3 indicates an opcode
* extension is present in the modrm byte.
*/
static const byte interesting[256] = {
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
0,
0,
0,
0,
0,
0,
1,
1,
1,
1,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
3,
0,
0,
0,
3,
0,
0,
1,
1,
1,
1,
0,
0,
0,
0,
1,
1,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
3,
};
* This table is indexed by the 1st (primary) opcode byte.
* We use the eflags constants from instr.h.
* We ignore writing some of the 6 as a conservative simplification.
* Also note that for some groups we assign values to invalid opcodes
* just for simplicity
*/
#define x 0
#define RC EFLAGS_READ_CF
#define RP EFLAGS_READ_PF
#define RZ EFLAGS_READ_ZF
#define RS EFLAGS_READ_SF
#define RO EFLAGS_READ_OF
#define R6 EFLAGS_READ_6
#define RB (EFLAGS_READ_CF | EFLAGS_READ_ZF)
#define RL (EFLAGS_READ_SF | EFLAGS_READ_OF)
#define RE (EFLAGS_READ_SF | EFLAGS_READ_OF | EFLAGS_READ_ZF)
#define R5O (EFLAGS_READ_6 & (~EFLAGS_READ_OF))
#define WC EFLAGS_WRITE_CF
#define WZ EFLAGS_WRITE_ZF
#define W6 EFLAGS_WRITE_6
#define W5 (EFLAGS_WRITE_6 & (~EFLAGS_WRITE_CF))
#define W5O (EFLAGS_WRITE_6 & (~EFLAGS_WRITE_OF))
#define BC (EFLAGS_WRITE_6 | EFLAGS_READ_CF)
#define BA (EFLAGS_WRITE_6 | EFLAGS_READ_AF)
#define BD (EFLAGS_WRITE_6 | EFLAGS_READ_CF | EFLAGS_READ_AF)
#define B6 (EFLAGS_WRITE_6 | EFLAGS_READ_6)
#define EFLAGS_6_ESCAPE -1
#define EFLAGS_6_SPECIAL -2
#define E EFLAGS_6_ESCAPE
#define S EFLAGS_6_SPECIAL
static const int eflags_6[256] = {
W6, W6, W6, W6, W6, W6, x, x, W6, W6, W6, W6, W6, W6, x, E,
BC, BC, BC, BC, BC, BC, x, x, BC, BC, BC, BC, BC, BC, x, x,
W6, W6, W6, W6, W6, W6, x, BD, W6, W6, W6, W6, W6, W6, x, BD,
W6, W6, W6, W6, W6, W6, x, BA, W6, W6, W6, W6, W6, W6, x, BA,
W5, W5, W5, W5, W5, W5, W5, W5, W5, W5, W5, W5, W5, W5, W5, W5,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, WZ, x, x, x, x, x, W6, x, W6, x, x, x, x,
RO, RO, RC, RC, RZ, RZ, RB, RB, RS, RS, RP, RP, RL, RL, RE, RE,
S, S, S, S, W6, W6, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, R6, W6, W5O, R5O,
x, x, x, x, x, x, W6, W6, W6, W6, x, x, x, x, W6, W6,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
S, S, x, x, x, x, x, x, x, x, x, x, R6, R6, R6, W6,
S, S, S, S, W6, W6, x, x, x, x, S, S, x, x, x, S,
RZ, RZ, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, WC, S, S, WC, WC, x, x, x, x, S, S,
};
*/
static const int escape_eflags_6[256] = {
x, x, WZ, WZ, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
W6, W6, W6, W6, x, x, x, x, x, x, x, x, x, x, W6, W6,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
RO, RO, RC, RC, RZ, RZ, RB, RB, RS, RS, RP, RP, RL, RL, RE, RE,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
RO, RO, RC, RC, RZ, RZ, RB, RB, RS, RS, RP, RP, RL, RL, RE, RE,
RO, RO, RC, RC, RZ, RZ, RB, RB, RS, RS, RP, RP, RL, RL, RE, RE,
x, x, x, W6, W6, W6, x, x, x, x, W6, W6, W6, W6, x, W6,
W6, W6, x, W6, x, x, x, x, x, x, W6, W6, W6, W6, x, x,
W6, W6, x, x, x, x, x, WZ, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
};
#undef x
#undef RC
#undef RP
#undef RZ
#undef RS
#undef RO
#undef R6
#undef RB
#undef RL
#undef RE
#undef R5O
#undef WC
#undef WZ
#undef W6
#undef W5
#undef W5O
#undef BC
#undef BA
#undef BD
#undef B6
#undef E
#undef S
* formal parameter pc should point to the beginning of the branch
* instruction containing the offset and having length len in bytes.
* The x86 architecture calculates offsets from the beginning of the
* instruction following the branch. */
static app_pc
convert_8bit_offset(byte *pc, byte offset, uint len)
{
return ((app_pc)pc) + (((int)(offset << 24)) >> 24) + len;
}
static bool
intercept_fip_save(byte *pc, byte byte0, byte byte1)
{
if ((byte0 == 0xdd && ((byte1 >> 3) & 0x7) == 6) ||
(byte0 == 0xd9 && ((byte1 >> 3) & 0x7) == 6) )
return true;
if (byte0 == 0x0f && byte1 == 0xae) {
int opc_ext;
byte byte2 = *(pc + 2);
opc_ext = (byte2 >> 3) & 0x7;
return opc_ext == 0 ||
opc_ext == 4 ||
opc_ext == 6;
}
if (byte0 == 0x0f && byte1 == 0xc7) {
int opc_ext;
byte byte2 = *(pc + 2);
opc_ext = (byte2 >> 3) & 0x7;
return opc_ext == 4;
}
return false;
}
static bool
get_implied_mm_e_vex_opcode_bytes(byte *pc, int prefixes, byte vex_mm, byte *byte0,
byte *byte1)
{
switch (vex_mm) {
case 1:
*byte0 = 0x0f;
*byte1 = *(pc + prefixes);
return true;
case 2:
*byte0 = 0x0f;
*byte1 = 0x38;
return true;
case 3:
*byte0 = 0x0f;
*byte1 = 0x3a;
return true;
default: return false;
}
}
* 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.
*
* Fills in the PREFIX_SEG_GS and PREFIX_SEG_FS prefix flags for all instrs.
* Does NOT fill in any other prefix flags unless this is a cti instr
* and the flags affect the instr.
*
* Assumes that instr is already initialized, but uses the x86/x64 mode
* for the current thread rather than that set in instr.
* If caller is re-using same instr struct over multiple decodings,
* should call instr_reset or instr_reuse.
* Returns the address of the byte following the instruction.
* Returns NULL on decoding an invalid instr and sets opcode to OP_INVALID.
*/
byte *
decode_cti(void *drcontext, byte *pc, instr_t *instr)
{
dcontext_t *dcontext = (dcontext_t *)drcontext;
byte byte0, byte1;
byte *start_pc = pc;
int prefixes;
int eflags;
int i;
byte modrm = 0;
* Since change/setting raw bits invalidates, we must set this
* on every return.
*/
uint rip_rel_pos;
int sz = decode_sizeof_ex(dcontext, pc, &prefixes, &rip_rel_pos);
if (sz == 0) {
instr_set_opcode(instr, OP_INVALID);
return NULL;
}
instr_set_opcode(instr, OP_UNDECODED);
IF_X64(instr_set_x86_mode(instr, get_x86_mode(dcontext)));
byte0 = *(pc + prefixes);
byte1 = *(pc + prefixes + 1);
* front, because any instr_set_src, instr_set_dst, or
* instr_set_opcode will kill original bits state
*/
* We rely on having these set during bb building.
* FIXME - could be done in decode_sizeof which is already walking these
* bytes, but would need to complicate its interface and prefixes are
* fairly rare to begin with.
*/
if (prefixes > 0) {
for (i = 0; i < prefixes; i++, pc++) {
switch (*pc) {
case FS_SEG_OPCODE: instr_set_prefix_flag(instr, PREFIX_SEG_FS); break;
case GS_SEG_OPCODE: instr_set_prefix_flag(instr, PREFIX_SEG_GS); break;
case VEX_2BYTE_PREFIX_OPCODE:
byte0 = 0x0f;
byte1 = *(pc + prefixes);
pc = start_pc + prefixes;
i = prefixes;
break;
case EVEX_PREFIX_OPCODE:
instr_set_prefix_flag(instr, PREFIX_EVEX);
case VEX_3BYTE_PREFIX_OPCODE: {
* bits in the second prefix byte. In theory, there are 5 VEX mm bits, but
* only 2 of them are used.
*/
byte vex_mm = (byte)(*(pc + 1) & 0x3);
if (!get_implied_mm_e_vex_opcode_bytes(pc, prefixes, vex_mm, &byte0,
&byte1)) {
instr_set_opcode(instr, OP_INVALID);
return NULL;
}
pc = start_pc + prefixes;
i = prefixes;
}
default: break;
}
}
}
* we do this even if -unsafe_ignore_eflags b/c it doesn't cost that
* much and we can use the analysis to detect any bb that reads a flag
* prior to writing it
* i#3267: eflags lookup possibly incorrect for instructions with VEX prefix.
* (and instructions with EVEX prefix once AVX512 has been added).
*/
eflags = eflags_6[byte0];
if (eflags == EFLAGS_6_ESCAPE) {
eflags = escape_eflags_6[byte1];
if (eflags == EFLAGS_6_SPECIAL)
modrm = *(pc + 2);
} else if (eflags == EFLAGS_6_SPECIAL) {
modrm = byte1;
}
if (eflags == EFLAGS_6_SPECIAL) {
* to distinguish
*/
int opc_ext = (modrm >> 3) & 7;
if (byte0 <= 0x84) {
if (opc_ext == 2 || opc_ext == 3)
eflags = EFLAGS_WRITE_6 | EFLAGS_READ_CF;
else
eflags = EFLAGS_WRITE_6;
} else if (byte0 <= 0xd3) {
if (opc_ext == 0 || opc_ext == 1)
eflags = EFLAGS_WRITE_CF | EFLAGS_WRITE_OF;
else if (opc_ext == 2 || opc_ext == 3)
eflags = EFLAGS_WRITE_CF | EFLAGS_WRITE_OF | EFLAGS_READ_CF;
else if (opc_ext == 4 || opc_ext == 5 || opc_ext == 7)
eflags = EFLAGS_WRITE_6;
else
eflags = 0;
} else if (byte0 <= 0xdf) {
if ((byte0 == 0xda || byte0 == 0xdb) && modrm >= 0xc0 && modrm <= 0xdf)
eflags = EFLAGS_READ_CF | EFLAGS_READ_PF | EFLAGS_READ_ZF;
else if ((byte0 == 0xdb || byte0 == 0xdf) && modrm >= 0xe8 && modrm <= 0xf7)
eflags = EFLAGS_WRITE_CF | EFLAGS_WRITE_PF | EFLAGS_WRITE_ZF;
else
eflags = 0;
} else if (byte0 <= 0xf7) {
if (opc_ext == 2)
eflags = 0;
else
eflags = EFLAGS_WRITE_6;
} else {
if (opc_ext == 0 || opc_ext == 1)
eflags = EFLAGS_WRITE_6 & (~EFLAGS_WRITE_CF);
else
eflags = 0;
}
}
instr->eflags = eflags;
instr_set_arith_flags_valid(instr, true);
if (interesting[byte0] == 0) {
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (start_pc + sz);
}
* performance improvement?
*/
if (prefixes > 0) {
* rather than handle them all here, just do full decode
* FIXME: if we start to see more and more jcc branch hints we
* may change our minds here! This is case 211206/6749.
*/
if (decode(dcontext, start_pc, instr) == NULL)
return NULL;
else
return (start_pc + sz);
}
#ifdef FOOL_CPUID
if (byte0 == 0x0f && byte1 == 0xa2) {
instr_set_opcode(instr, OP_cpuid);
instr_set_operands_valid(instr, false);
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (start_pc + sz);
}
#endif
if (byte0 == 0xeb) {
app_pc tgt = convert_8bit_offset(pc, byte1, 2);
instr_set_opcode(instr, OP_jmp_short);
instr_set_num_opnds(dcontext, instr, 0, 1);
instr_set_target(instr, opnd_create_pc(tgt));
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 2);
}
if ((byte0 & 0xf0) == 0x70) {
app_pc tgt = convert_8bit_offset(pc, byte1, 2);
* in opcode enum. */
instr_set_opcode(instr, OP_jo_short + (byte0 & 0x0f));
instr_set_num_opnds(dcontext, instr, 0, 1);
instr_set_target(instr, opnd_create_pc(tgt));
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 2);
}
if (byte0 == 0xe8) {
int offset = *((int *)(pc + 1));
app_pc tgt = pc + offset + 5;
instr_set_opcode(instr, OP_call);
instr_set_num_opnds(dcontext, instr, 2, 2);
instr_set_target(instr, opnd_create_pc(tgt));
instr_set_src(instr, 1, opnd_create_reg(REG_XSP));
instr_set_dst(instr, 0, opnd_create_reg(REG_XSP));
instr_set_dst(instr, 1,
opnd_create_base_disp(
REG_XSP, REG_NULL, 0, 0,
resolve_variable_size_dc(dcontext, 0, OPSZ_call, false)));
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 5);
}
if (byte0 == 0xe9) {
int offset = *((int *)(pc + 1));
app_pc tgt = pc + offset + 5;
instr_set_opcode(instr, OP_jmp);
instr_set_num_opnds(dcontext, instr, 0, 1);
instr_set_target(instr, opnd_create_pc(tgt));
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 5);
}
if ((byte0 == 0x0f) && ((byte1 & 0xf0) == 0x80)) {
int offset = *((int *)(pc + 2));
app_pc tgt = pc + offset + 6;
* in opcode enum. */
instr_set_opcode(instr, OP_jo + (byte1 & 0x0f));
instr_set_num_opnds(dcontext, instr, 0, 1);
instr_set_target(instr, opnd_create_pc(tgt));
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 6);
}
if (byte0 == 0xff) {
uint opc = (byte1 >> 3) & 0x7;
if (opc >= 2 && opc <= 5) {
*/
if (decode(dcontext, start_pc, instr) == NULL)
return NULL;
else
return (start_pc + sz);
}
}
if ((byte0 & 0xf0) == 0xc0) {
byte nibble1 = (byte)(byte0 & 0x0f);
switch (nibble1) {
case 2:
case 0xa:
CLIENT_ASSERT(prefixes == 0, "decode_cti: internal prefix error");
instr_set_opcode(instr, nibble1 == 2 ? OP_ret : OP_ret_far);
instr_set_num_opnds(dcontext, instr, 1, 3);
instr_set_dst(instr, 0, opnd_create_reg(REG_XSP));
instr_set_src(instr, 0, opnd_create_immed_int(*((short *)(pc + 1)), OPSZ_2));
instr_set_src(instr, 1, opnd_create_reg(REG_XSP));
instr_set_src(
instr, 2,
opnd_create_base_disp(
REG_XSP, REG_NULL, 0, 0,
resolve_variable_size_dc(
dcontext, 0, nibble1 == 2 ? OPSZ_ret : OPSZ_REXVARSTACK, false)));
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 3);
case 3:
instr_set_opcode(instr, OP_ret);
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 1);
case 0xb:
instr_set_opcode(instr, OP_ret_far);
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 1);
}
}
if ((byte0 & 0xf0) == 0xe0) {
byte nibble1 = (byte)(byte0 & 0x0f);
if (nibble1 == 0) {
instr_set_opcode(instr, OP_loopne);
} else if (nibble1 == 1) {
instr_set_opcode(instr, OP_loope);
} else if (nibble1 == 2) {
instr_set_opcode(instr, OP_loop);
} else if (nibble1 == 3) {
instr_set_opcode(instr, OP_jecxz);
} else if (nibble1 == 10) {
* this is rare so go ahead and do full decode
*/
if (decode(dcontext, start_pc, instr) == NULL)
return NULL;
else
return (start_pc + sz);
}
if (instr_opcode_valid(instr)) {
app_pc tgt = convert_8bit_offset(pc, byte1, 2);
instr_set_num_opnds(dcontext, instr, 0, 2);
CLIENT_ASSERT(prefixes == 0, "decoding internal inconsistency");
instr_set_src(instr, 1, opnd_create_reg(REG_XCX));
instr_set_target(instr, opnd_create_pc(tgt));
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 2);
}
}
if (byte0 == 0x9a) {
*/
if (decode(dcontext, start_pc, instr) == NULL)
return NULL;
else
return (start_pc + sz);
}
if (byte0 == 0xcd) {
instr_set_opcode(instr, OP_int);
instr_set_num_opnds(dcontext, instr, 2, 2);
instr_set_dst(instr, 0, opnd_create_reg(REG_XSP));
instr_set_dst(instr, 1, opnd_create_base_disp(REG_XSP, REG_NULL, 0, 0, OPSZ_4));
instr_set_src(instr, 0, opnd_create_immed_int((sbyte)byte1, OPSZ_1));
instr_set_src(instr, 1, opnd_create_reg(REG_XSP));
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 2);
}
if (byte0 == 0x0f &&
(byte1 == 0x34 || byte1 == 0x35 || byte1 == 0x05 || byte1 == 0x07)) {
if (byte1 == 0x34) {
instr_set_opcode(instr, OP_sysenter);
instr_set_num_opnds(dcontext, instr, 1, 0);
instr_set_dst(instr, 0, opnd_create_reg(REG_XSP));
} else if (byte1 == 0x35) {
instr_set_opcode(instr, OP_sysexit);
instr_set_num_opnds(dcontext, instr, 1, 0);
instr_set_dst(instr, 0, opnd_create_reg(REG_XSP));
} else if (byte1 == 0x05) {
instr_set_opcode(instr, OP_syscall);
instr_set_num_opnds(dcontext, instr, 1, 0);
instr_set_dst(instr, 0, opnd_create_reg(REG_XCX));
} else if (byte1 == 0x07) {
instr_set_opcode(instr, OP_sysret);
instr_set_num_opnds(dcontext, instr, 0, 0);
}
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 2);
}
if (byte0 == 0xcf) {
instr_set_opcode(instr, OP_iret);
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 1);
}
if (byte0 == 0x9d) {
reg_id_t stack_sized_reg = REG_XSP;
#ifdef X64
if (dr_get_isa_mode(dcontext) == DR_ISA_IA32) {
stack_sized_reg = REG_ESP;
}
#endif
instr_set_opcode(instr, OP_popf);
instr_set_raw_bits(instr, start_pc, sz);
instr_set_num_opnds(dcontext, instr, 1, 2);
instr_set_src(instr, 0, opnd_create_reg(stack_sized_reg));
instr_set_src(
instr, 1,
opnd_create_base_disp(
stack_sized_reg, REG_NULL, 0, 0,
resolve_variable_size_dc(dcontext, prefixes, OPSZ_VARSTACK, false)));
instr_set_dst(instr, 0, opnd_create_reg(stack_sized_reg));
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (pc + 1);
}
#ifdef UNIX
if (INTERNAL_OPTION(mangle_app_seg) && (byte0 == 0x8c || byte0 == 0x8e)) {
instr_set_opcode(instr, OP_mov_seg);
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (start_pc + sz);
}
#endif
* Rare enough that we do a full decode on an opcode match.
*/
if (intercept_fip_save(pc, byte0, byte1)) {
if (decode(dcontext, start_pc, instr) == NULL)
return NULL;
else
return (start_pc + sz);
}
instr_set_raw_bits(instr, start_pc, sz);
instr_set_rip_rel_pos(instr, rip_rel_pos);
return (start_pc + sz);
}
* Returns NULL on decoding an invalid instruction.
*/
byte *
decode_next_pc(void *drcontext, byte *pc)
{
dcontext_t *dcontext = (dcontext_t *)drcontext;
int sz = decode_sizeof(dcontext, pc, NULL _IF_X64(NULL));
if (sz == 0)
return NULL;
else
return pc + sz;
}
* at the raw bits for the instruction.
* This corresponds to a Level 1 decoding.
* Assumes that instr is already initialized, but uses the x86/x64 mode
* for the current thread rather than that set in instr.
* If caller is re-using same instr struct over multiple decodings,
* should call instr_reset or instr_reuse.
* Returns the address of the next byte after the decoded instruction.
* Returns NULL on decoding an invalid instr and sets opcode to OP_INVALID.
*/
byte *
decode_raw(dcontext_t *dcontext, byte *pc, instr_t *instr)
{
int sz = decode_sizeof(dcontext, pc, NULL _IF_X64(NULL));
IF_X64(instr_set_x86_mode(instr, get_x86_mode(dcontext)));
if (sz == 0) {
instr_set_opcode(instr, OP_INVALID);
return NULL;
}
instr_set_opcode(instr, OP_UNDECODED);
instr_set_raw_bits(instr, pc, sz);
return (pc + sz);
}