/* **********************************************************
 * Copyright (c) 2010-2021 Google, Inc.  All rights reserved.
 * Copyright (c) 2002-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 _DR_IR_DECODE_H_
#define _DR_IR_DECODE_H_ 1

/**************************************************
 * DECODING ROUTINES
 */
/**
 * @file dr_ir_decode.h
 * @brief Decoding routines.
 */

DR_API
/**
 * Decodes only enough of the instruction at address \p pc to determine
 * its eflags usage, which is returned in \p usage as EFLAGS_ constants
 * or'ed together.
 * Returns the address of the next byte after the decoded instruction.
 * Returns NULL on decoding an invalid instruction.
 */
/* This corresponds to halfway between Level 1 and Level 2: a Level 1 decoding
 * plus eflags information (usually only at Level 2).  Levels are not exposed
 * in the API anymore, however.
 */
byte *
decode_eflags_usage(void *drcontext, byte *pc, uint *usage, dr_opnd_query_flags_t flags);

DR_API
/**
 * Decodes the instruction at address \p pc into \p instr, filling in the
 * instruction's opcode, eflags usage, prefixes, and operands.
 * The instruction's raw bits are set to valid and pointed at \p pc
 * (xref instr_get_raw_bits()).
 * Assumes that \p instr is already initialized, but uses the x86/x64 mode
 * for the thread \p dcontext rather than that set in instr.
 * If caller is re-using same instr_t struct over multiple decodings,
 * caller 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.
 */
/* This corresponds to a Level 3 decoding.  Levels are not exposed
 * in the API anymore, however.
 */
byte *
decode(void *drcontext, byte *pc, instr_t *instr);

DR_API
/**
 * Decodes the instruction at address \p copy_pc into \p instr as though
 * it were located at address \p orig_pc.  Any pc-relative operands have
 * their values calculated as though the instruction were actually at
 * \p orig_pc, though that address is never de-referenced.
 * The instruction's raw bits are not valid, but its application address field
 * (see instr_get_app_pc()) is set to \p orig_pc.
 * The instruction's opcode, eflags usage, prefixes, and operands are
 * all filled in.
 * Assumes that \p instr is already initialized, but uses the x86/x64 mode
 * for the thread \p dcontext rather than that set in instr.
 * If caller is re-using same instr_t struct over multiple decodings,
 * caller should call instr_reset() or instr_reuse().
 * Returns the address of the next byte after the decoded instruction
 * copy at \p copy_pc.
 * Returns NULL on decoding an invalid instr and sets opcode to OP_INVALID.
 */
/* This corresponds to a Level 3 decoding.  Levels are not exposed
 * in the API anymore, however.
 */
byte *
decode_from_copy(void *drcontext, byte *copy_pc, byte *orig_pc, instr_t *instr);

/* decode_as_bb() is defined in interp.c, but declared here so it will
 * be listed next to the other decode routines in the API headers.
 */
DR_API
/**
 * Client routine to decode instructions at an arbitrary app address,
 * following all the rules that DynamoRIO follows internally for
 * terminating basic blocks.  Note that DynamoRIO does not validate
 * that \p start_pc is actually the first instruction of a basic block.
 * \note Caller is reponsible for freeing the list and its instrs!
 */
instrlist_t *
decode_as_bb(void *drcontext, byte *start_pc);

DR_API
/**
 * Decodes the trace with tag \p tag, and returns an instrlist_t of
 * the instructions comprising that fragment.  If \p tag is not a
 * valid tag for an existing trace, the routine returns NULL.  Clients
 * can use dr_trace_exists_at() to determine whether the trace exists.
 * \note Unlike the instruction list presented by the trace event, the
 * list here does not include any existing client modifications.  If
 * client-modified instructions are needed, it is the responsibility
 * of the client to record or recreate that list itself.
 * \note This routine does not support decoding thread-private traces
 * created by other than the calling thread.
 */
instrlist_t *
decode_trace(void *drcontext, void *tag);

DR_API
/**
 * Given an OP_ constant, returns the first byte of its opcode when
 * encoded as an IA-32 instruction.
 */
byte
decode_first_opcode_byte(int opcode);

DR_API
/** Given an OP_ constant, returns the string name of its opcode. */
const char *
decode_opcode_name(int opcode);

#ifdef X64
DR_API
/**
 * The decode and encode routines use a per-thread persistent flag that
 * indicates whether to treat code as 32-bit (x86) or 64-bit (x64).  This
 * routine sets that flag to the indicated value and 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.
 *
 * \note For 64-bit DR builds only.
 *
 * \deprecated Replaced by dr_set_isa_mode().
 */
bool
set_x86_mode(void *drcontext, bool x86);

DR_API
/**
 * The decode and encode routines use a per-thread persistent flag that
 * indicates whether to treat code as 32-bit (x86) or 64-bit (x64).  This
 * routine returns the value of that flag.
 *
 * \note For 64-bit DR builds only.
 *
 * \deprecated Replaced by dr_get_isa_mode().
 */
bool
get_x86_mode(void *drcontext);
#endif /* X64 */

DR_API
/**
 * Given an application program counter value, returns the
 * corresponding value to use as an indirect branch target for the
 * given \p isa_mode.  For ARM's Thumb mode (#DR_ISA_ARM_THUMB), this
 * involves setting the least significant bit of the address.
 */
app_pc
dr_app_pc_as_jump_target(dr_isa_mode_t isa_mode, app_pc pc);

DR_API
/**
 * Given an application program counter value, returns the
 * corresponding value to use as a memory load target for the given \p
 * isa_mode, or for comparing to the application address inside a
 * basic block or trace.  For ARM's Thumb mode (#DR_ISA_ARM_THUMB),
 * this involves clearing the least significant bit of the address.
 */
app_pc
dr_app_pc_as_load_target(dr_isa_mode_t isa_mode, app_pc pc);

DR_API
/**
 * Calculates the size, in bytes, of the memory read or write of
 * the instr at \p pc.  If the instruction is a repeating string instruction,
 * considers only one iteration.
 * Returns the pc of the following instruction.
 * If the instruction at \p pc does not reference memory, or is invalid,
 * returns NULL.
 */
app_pc
decode_memory_reference_size(void *drcontext, app_pc pc, uint *size_in_bytes);

DR_API
/**
 * Decodes only enough of the instruction at address \p pc to determine its size.
 * Returns that size.
 * If \p num_prefixes is non-NULL, returns the number of prefix bytes.
 *
 * On x86, if \p 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; use decode_sizeof_ex() for that), or 0 if none.
 * The \p rip_rel_pos parameter is only implemented for x86, where the displacement
 * is always 4 bytes in size.
 *
 * May return 0 size for certain invalid instructions.
 */
int
decode_sizeof(void *drcontext, byte *pc, int *num_prefixes _IF_X86_64(uint *rip_rel_pos));

#ifdef X86
DR_API
/**
 * Decodes only enough of the instruction at address \p pc to determine its size.
 * Returns that size.
 * If \p num_prefixes is non-NULL, returns the number of prefix bytes.
 *
 * On x86, if \p rip_rel_pos is non-NULL, returns the offset into the instruction of a
 * rip-relative addressing displacement for data or control-transfer relative
 * addressing, or 0 if none.  This is only implemented for x86, where the displacement
 * is always 4 bytes for data but can be 1 byte for control.
 *
 * May return 0 size for certain invalid instructions.
 */
int
decode_sizeof_ex(void *drcontext, byte *pc, int *num_prefixes, uint *rip_rel_pos);
#endif /* X86 */

DR_API
/**
 * Decodes only enough of the instruction at address \p pc to determine its size.
 * Returns the address of the byte following the instruction.
 * May return NULL on decoding certain invalid instructions.
 */
/**
 * This corresponds to a Level 1 decoding.  Levels are not exposed
 * in the API anymore, however.
 */
byte *
decode_next_pc(void *drcontext, byte *pc);

DR_UNS_EXCEPT_TESTS_API
/* Decodes only enough of the instruction at address \p pc 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
 * \p instr are filled in.  If not, only the raw bits fields of \p instr are
 * filled in.
 *
 * 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.
 *
 * For x86, calls instr_set_rip_rel_pos().  Thus, if the raw bytes are
 * not modified prior to encode time, any rip-relative offset will be
 * automatically re-relativized (though encoding will fail if the new
 * encode location cannot reach the original target).
 *
 * Assumes that \p instr is already initialized, but uses the x86/x64 mode
 * for the thread \p dcontext rather than that set in instr.
 * If caller is re-using same instr struct over multiple decodings,
 * caller 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.
 */
/* This corresponds to a Level 3 decoding for control transfer
 * instructions but a Level 1 decoding plus arithmetic eflags
 * information for all other instructions.  Levels are not exposed
 * in the API anymore, however.
 */
byte *
decode_cti(void *drcontext, byte *pc, instr_t *instr);

#endif /* _DR_IR_DECODE_H_ */