blob: 9d7664483c594e809aa04811bce281cb4d534d91 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2010-2023 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.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2002-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2002 Hewlett-Packard Company */
#ifndef _DR_DEFINES_H_
#define _DR_DEFINES_H_ 1
/****************************************************************************
* GENERAL TYPEDEFS AND DEFINES
*/
/**
* @file dr_defines.h
* @brief Basic defines and type definitions.
*/
#ifdef WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <winbase.h>
#else
# include <stdio.h>
# include <stdlib.h>
#endif
#include <stdarg.h> /* for varargs */
#ifndef DYNAMORIO_INTERNAL
/* A client's target operating system and architecture must be specified. */
# if !defined(LINUX) && !defined(WINDOWS) && !defined(MACOS)
# error Target operating system unspecified: define WINDOWS, LINUX, or MACOS
# endif
# if defined(X86_32) || defined(X86_64)
# define X86
# if (defined(X86_64) && defined(X86_32)) || defined(ARM_32) || \
defined(ARM_64) || defined(RISCV_64)
# error Target architecture over-specified: must define only one
# endif
# elif defined(ARM_32)
# define ARM
# define AARCHXX
# if defined(X86_32) || defined(X86_64) || defined(ARM_64) || defined(RISCV_64)
# error Target architecture over-specified: must define only one
# endif
# elif defined(ARM_64)
# define AARCH64
# define AARCHXX
# if defined(X86_32) || defined(X86_64) || defined(ARM_32) || defined(RISCV_64)
# error Target architecture over-specified: must define only one
# endif
# elif defined(RISCV_64)
# define RISCV64
# if defined(X86_32) || defined(X86_64) || defined(ARM_32) || defined(ARM_64)
# error Target architecture over-specified: must define only one
# endif
# else
# error Target architecture unknown: define X86_32, X86_64, ARM_32, ARM_64 or \
RISCV_64
# endif
# define DR_API /* Ignore for clients. */
# define DR_UNS_EXCEPT_TESTS_API /* Ignore for clients. */
#endif
#if (defined(X86_64) || defined(ARM_64) || defined(RISCV_64)) && !defined(X64)
# define X64
#endif
#if (defined(LINUX) || defined(MACOS)) && !defined(UNIX)
# define UNIX
#endif
/* XXX: Defining c++ keywords "inline", "true", and "false" cause clang-format to not
* behave properly. It indents the guard. There seems to be no workaround.
*/
/* clang-format off */
# ifndef __cplusplus
# ifdef WINDOWS
# define inline __inline
# else
# define inline __inline__
# endif
# ifndef DR_DO_NOT_DEFINE_bool
# ifdef DR__Bool_EXISTS
/* prefer _Bool as it avoids truncation casting non-zero to zero */
typedef _Bool bool;
# else
/* char-sized for compatibility with C++ */
typedef char bool;
# endif
# endif
# ifndef true
# define true (1)
# endif
# ifndef false
# define false (0)
# endif
# endif
# ifdef UNIX
# include <sys/types.h> /* for pid_t (non-glibc, e.g. musl) */
# endif
# ifdef WINDOWS
/* allow nameless struct/union */
# pragma warning(disable : 4201)
/* VS2005 warns about comparison operator results being cast to bool (i#523) */
# if _MSC_VER >= 1400 && _MSC_VER < 1500
# pragma warning(disable : 4244)
# endif
# endif
/* clang-format on */
#ifdef WINDOWS
# define DR_EXPORT __declspec(dllexport)
# define LINK_ONCE __declspec(selectany)
# define ALIGN_VAR(x) __declspec(align(x))
# define INLINE_FORCED __forceinline
# define WEAK /* no equivalent, but .obj overrides .lib */
# define NOINLINE __declspec(noinline)
#else
/* We assume gcc is being used. If the client is using -fvisibility
* (in gcc >= 3.4) to not export symbols by default, setting
* USE_VISIBILITY_ATTRIBUTES will properly export.
*/
# ifdef USE_VISIBILITY_ATTRIBUTES
# define DR_EXPORT __attribute__((visibility("default")))
# else
# define DR_EXPORT
# endif
# define LINK_ONCE __attribute__((weak))
# define ALIGN_VAR(x) __attribute__((aligned(x)))
# define INLINE_FORCED inline
# define WEAK __attribute__((weak))
# define NOINLINE __attribute__((noinline))
#endif
/* We want a consistent size so we stay away from MAX_PATH.
* MAX_PATH is 260 on Windows, but 4096 on Linux: should up this.
* XXX: should undef MAX_PATH and define it to an error-producing value
* and clean up all uses of it
*/
/**
* Maximum file path length define meant to replace platform-specific defines
* such as MAX_PATH and PATH_MAX.
* Currently, internal stack size limits prevent this from being much larger
* on UNIX.
*/
#ifdef WINDOWS
# define MAXIMUM_PATH 260
#else
# define MAXIMUM_PATH 512
#endif
#ifndef NULL
# ifdef __cplusplus
# define NULL nullptr
# else
# define NULL ((void *)0)
# endif
#endif
/* on Windows where bool is char casting can truncate non-zero to zero
* so we use this macro
*/
#define CAST_TO_bool(x) (!!(x))
#ifndef DR_DO_NOT_DEFINE_uint
typedef unsigned int uint;
#endif
#ifndef DR_DO_NOT_DEFINE_ushort
typedef unsigned short ushort;
#endif
#ifndef DR_DO_NOT_DEFINE_byte
typedef unsigned char byte;
#endif
#ifndef DR_DO_NOT_DEFINE_sbyte
typedef signed char sbyte;
#endif
typedef byte *app_pc;
typedef void (*generic_func_t)();
#ifdef DR_DEFINE_FOR_uint64
# undef DR_DO_NOT_DEFINE_uint64
#endif
#ifdef DR_DEFINE_FOR_int64
# undef DR_DO_NOT_DEFINE_int64
#endif
#ifdef WINDOWS
# ifndef DR_DEFINE_FOR_uint64
# define DR_DEFINE_FOR_uint64 unsigned __int64
# endif
# ifndef DR_DEFINE_FOR_int64
# define DR_DEFINE_FOR_int64 __int64
# endif
# ifdef X64
typedef __int64 ssize_t;
# else
typedef int ssize_t;
# endif
# define _SSIZE_T_DEFINED
# ifndef INT64_FORMAT
# define INT64_FORMAT "I64"
# endif
#else /* Linux */
# ifdef X64
# ifndef DR_DEFINE_FOR_uint64
# define DR_DEFINE_FOR_uint64 unsigned long int
# endif
# ifndef DR_DEFINE_FOR_int64
# define DR_DEFINE_FOR_int64 long int
# endif
# ifndef INT64_FORMAT
# define INT64_FORMAT "l"
# endif
# else
# ifndef DR_DEFINE_FOR_uint64
# define DR_DEFINE_FOR_uint64 unsigned long long int
# endif
# ifndef DR_DEFINE_FOR_int64
# define DR_DEFINE_FOR_int64 long long int
# endif
# ifndef INT64_FORMAT
# define INT64_FORMAT "ll"
# endif
# endif
#endif
#ifndef DR_DO_NOT_DEFINE_int64
typedef DR_DEFINE_FOR_int64 int64;
#endif
#ifndef DR_DO_NOT_DEFINE_uint64
typedef DR_DEFINE_FOR_uint64 uint64;
#endif
/* a register value: could be of any type; size is what matters. */
#ifdef X64
typedef uint64 reg_t;
#else
typedef uint reg_t;
#endif
/* integer whose size is based on pointers: ptr diff, mask, etc. */
typedef reg_t ptr_uint_t;
#ifdef X64
typedef int64 ptr_int_t;
#else
typedef int ptr_int_t;
#endif
/* for memory region sizes, use size_t */
/**
* Application offset from module base.
* PE32+ modules are limited to 2GB, but not ELF x64 med/large code model.
*/
typedef size_t app_rva_t;
#define PTR_UINT_0 ((ptr_uint_t)0U)
#define PTR_UINT_1 ((ptr_uint_t)1U)
#define PTR_UINT_MINUS_1 ((ptr_uint_t)-1)
#ifdef WINDOWS
typedef ptr_uint_t thread_id_t;
typedef ptr_uint_t process_id_t;
#elif defined(MACOS)
typedef uint64 thread_id_t;
typedef pid_t process_id_t;
#else /* Linux */
typedef pid_t thread_id_t;
typedef pid_t process_id_t;
#endif
#define INVALID_PROCESS_ID PTR_UINT_MINUS_1
#ifndef DYNAMORIO_INTERNAL
# ifdef WINDOWS
/* since a FILE cannot be used outside of the DLL it was created in,
* we have to use HANDLE on Windows
* we hide the distinction behind the file_t type
*/
typedef HANDLE file_t;
/** The sentinel value for an invalid file_t. */
# define INVALID_FILE INVALID_HANDLE_VALUE
/* dr_get_stdout_file and dr_get_stderr_file return errors as
* INVALID_HANDLE_VALUE. We leave INVALID_HANDLE_VALUE as is,
* since it equals INVALID_FILE
*/
/** The file_t value for standard output. */
# define STDOUT (dr_get_stdout_file())
/** The file_t value for standard error. */
# define STDERR (dr_get_stderr_file())
/** The file_t value for standard input. */
# define STDIN (dr_get_stdin_file())
# endif
#endif
#ifdef UNIX
typedef int file_t;
/** The sentinel value for an invalid file_t. */
# define INVALID_FILE -1
/** Allow use of stdout after the application closes it. */
extern file_t our_stdout;
/** Allow use of stderr after the application closes it. */
extern file_t our_stderr;
/** Allow use of stdin after the application closes it. */
extern file_t our_stdin;
/** The file_t value for standard output. */
# define STDOUT our_stdout
/** The file_t value for standard error. */
# define STDERR our_stderr
/** The file_t value for standard error. */
# define STDIN our_stdin
#endif
/* Note that we considered using a 128-bit GUID for the client ID,
* but decided it was unnecessary since the client registration
* routine will complain about conflicting IDs. Also, we're storing
* this value in the registry, so no reason to make it any longer
* than we have to.
*/
/**
* ID used to uniquely identify a client. This value is set at
* client registration and passed to the client in dr_client_main().
*/
typedef uint client_id_t;
#ifndef DR_FAST_IR
/**
* Internal structure of opnd_t is below abstraction layer.
* But compiler needs to know field sizes to copy it around
*/
typedef struct {
# ifdef X64
uint black_box_uint;
uint64 black_box_uint64;
# else
uint black_box_uint[3];
# endif
} opnd_t;
/**
* Internal structure of instr_t is below abstraction layer, but we
* provide its size so that it can be used in stack variables
* instead of always allocated on the heap.
*/
typedef struct {
# ifdef X64
uint black_box_uint[28];
# else
uint black_box_uint[19];
# endif
} instr_t;
#else
struct _opnd_t;
typedef struct _opnd_t opnd_t;
struct _instr_t;
typedef struct _instr_t instr_t;
#endif
#ifndef DR_PARAM_IN
# define DR_PARAM_IN /* marks input param */
#endif
#ifndef DR_PARAM_OUT
# define DR_PARAM_OUT /* marks output param */
#endif
#ifndef DR_PARAM_INOUT
# define DR_PARAM_INOUT /* marks input+output param */
#endif
#ifdef X86
# define IF_X86(x) x
# define IF_X86_ELSE(x, y) x
# define IF_X86_(x) x,
# define _IF_X86(x) , x
# define IF_NOT_X86(x)
# define IF_NOT_X86_(x)
# define _IF_NOT_X86(x)
#else
# define IF_X86(x)
# define IF_X86_ELSE(x, y) y
# define IF_X86_(x)
# define _IF_X86(x)
# define IF_NOT_X86(x) x
# define IF_NOT_X86_(x) x,
# define _IF_NOT_X86(x) , x
#endif
#ifdef ARM
# define IF_ARM(x) x
# define IF_ARM_ELSE(x, y) x
# define IF_ARM_(x) x,
# define _IF_ARM(x) , x
# define IF_NOT_ARM(x)
# define _IF_NOT_ARM(x)
#else
# define IF_ARM(x)
# define IF_ARM_ELSE(x, y) y
# define IF_ARM_(x)
# define _IF_ARM(x)
# define IF_NOT_ARM(x) x
# define _IF_NOT_ARM(x) , x
#endif
#ifdef AARCH64
# define IF_AARCH64(x) x
# define IF_AARCH64_ELSE(x, y) x
# define IF_AARCH64_(x) x,
# define _IF_AARCH64(x) , x
# define IF_NOT_AARCH64(x)
# define _IF_NOT_AARCH64(x)
#else
# define IF_AARCH64(x)
# define IF_AARCH64_ELSE(x, y) y
# define IF_AARCH64_(x)
# define _IF_AARCH64(x)
# define IF_NOT_AARCH64(x) x
# define _IF_NOT_AARCH64(x) , x
#endif
#ifdef AARCHXX
# define IF_AARCHXX(x) x
# define IF_AARCHXX_ELSE(x, y) x
# define IF_AARCHXX_(x) x,
# define _IF_AARCHXX(x) , x
# define IF_NOT_AARCHXX(x)
# define _IF_NOT_AARCHXX(x)
#else
# define IF_AARCHXX(x)
# define IF_AARCHXX_ELSE(x, y) y
# define IF_AARCHXX_(x)
# define _IF_AARCHXX(x)
# define IF_NOT_AARCHXX(x) x
# define _IF_NOT_AARCHXX(x) , x
#endif
#ifdef RISCV64
# define IF_RISCV64(x) x
# define IF_RISCV64_ELSE(x, y) x
# define IF_RISCV64_(x) x,
# define _IF_RISCV64(x) , x
# define IF_NOT_RISCV64(x)
# define _IF_NOT_RISCV64(x)
#else
# define IF_RISCV64(x)
# define IF_RISCV64_ELSE(x, y) y
# define IF_RISCV64_(x)
# define _IF_RISCV64(x)
# define IF_NOT_RISCV64(x) x
# define _IF_NOT_RISCV64(x) , x
#endif
#if defined(AARCHXX) || defined(RISCV64)
# define IF_AARCHXX_OR_RISCV64(x) x
# define IF_AARCHXX_OR_RISCV64_ELSE(x, y) x
# define IF_AARCHXX_OR_RISCV64_(x) x,
# define _IF_AARCHXX_OR_RISCV64(x) , x
# define IF_NOT_AARCHXX_AND_NOT_RISCV64(x)
# define _IF_NOT_AARCHXX_AND_NOT_RISCV64(x)
#else
# define IF_AARCHXX_OR_RISCV64(x)
# define IF_AARCHXX_OR_RISCV64_ELSE(x, y) y
# define IF_AARCHXX_OR_RISCV64_(x)
# define _IF_AARCHXX_OR_RISCV64(x)
# define IF_NOT_AARCHXX_AND_NOT_RISCV64(x) x
# define _IF_NOT_AARCHXX_AND_NOT_RISCV64(x) , x
#endif
#if defined(AARCH64) || defined(RISCV64)
# define IF_AARCH64_OR_RISCV64(x) x
# define IF_AARCH64_OR_RISCV64_ELSE(x, y) x
# define IF_AARCH64_OR_RISCV64_(x) x,
# define _IF_AARCH64_OR_RISCV64(x) , x
# define IF_NOT_AARCH64_AND_NOT_RISCV64(x)
# define _IF_NOT_AARCH64_AND_NOT_RISCV64(x)
#else
# define IF_AARCH64_OR_RISCV64(x)
# define IF_AARCH64_OR_RISCV64_ELSE(x, y) y
# define IF_AARCH64_OR_RISCV64_(x)
# define _IF_AARCH64_OR_RISCV64(x)
# define IF_NOT_AARCH64_AND_NOT_RISCV64(x) x
# define _IF_NOT_AARCH64_AND_NOT_RISCV64(x) , x
#endif
#ifdef ANDROID
# define IF_ANDROID(x) x
# define IF_ANDROID_ELSE(x, y) x
# define IF_NOT_ANDROID(x)
#else
# define IF_ANDROID(x)
# define IF_ANDROID_ELSE(x, y) y
# define IF_NOT_ANDROID(x) x
#endif
#ifdef X64
# define IF_X64(x) x
# define IF_X64_ELSE(x, y) x
# define IF_X64_(x) x,
# define _IF_X64(x) , x
# define IF_NOT_X64(x)
# define _IF_NOT_X64(x)
#else
# define IF_X64(x)
# define IF_X64_ELSE(x, y) y
# define IF_X64_(x)
# define _IF_X64(x)
# define IF_NOT_X64(x) x
# define _IF_NOT_X64(x) , x
#endif
#if defined(X86) && !defined(X64)
# define IF_X86_32(x) x
#else
# define IF_X86_32(x)
#endif
#if defined(X86) && defined(X64)
# define IF_X86_64(x) x
# define IF_X86_64_ELSE(x, y) x
# define IF_X86_64_(x) x,
# define _IF_X86_64(x) , x
# define IF_NOT_X86_64(x)
# define _IF_NOT_X86_64(x)
#else
# define IF_X86_64(x)
# define IF_X86_64_ELSE(x, y) y
# define IF_X86_64_(x)
# define _IF_X86_64(x)
# define IF_NOT_X86_64(x) x
# define _IF_NOT_X86_64(x) , x
#endif
#if defined(X64) || defined(ARM)
# define IF_X64_OR_ARM(x) x
# define IF_NOT_X64_OR_ARM(x)
#else
# define IF_X64_OR_ARM(x)
# define IF_NOT_X64_OR_ARM(x) x
#endif
#if defined(X86) || defined(AARCH64)
# define IF_X86_OR_AARCH64(x) x
# define IF_NOT_X86_OR_AARCH64(x)
#else
# define IF_X86_OR_AARCH64(x)
# define IF_NOT_X86_OR_AARCH64(x) x
#endif
/* Convenience defines for cross-platform printing.
* For printing pointers: if using system printf, for %p gcc prepends 0x and uses
* lowercase while cl does not prepend, puts leading 0's, and uses uppercase.
* Also, the C standard does not allow min width for %p.
* However, with our own d_r_vsnprintf, we are able to use %p and thus satisfy
* format string compiler warnings.
* Two macros:
* - PFMT == Pointer Format == with leading zeros
* - PIFMT == Pointer Integer Format == no leading zeros
* Convenience macros to shrink long lines:
* - PFX == Pointer Format with leading 0x
* - PIFX == Pointer Integer Format with leading 0x
* For printing memory region sizes:
* - SZFMT == Size Format
* - SSZFMT == Signed Size Format
* For printing 32-bit integers as hex we use %x. We could use a macro
* there and then disallow %x, to try and avoid 64-bit printing bugs,
* but it wouldn't be a panacea.
*/
#define UINT64_FORMAT_CODE INT64_FORMAT "u"
#define INT64_FORMAT_CODE INT64_FORMAT "d"
#define UINT64_FORMAT_STRING "%" UINT64_FORMAT_CODE
#define INT64_FORMAT_STRING "%" INT64_FORMAT_CODE
#define HEX64_FORMAT_STRING "%" INT64_FORMAT "x"
#define ZHEX64_FORMAT_STRING "%016" INT64_FORMAT "x"
#ifdef UNIX
# define ZHEX32_FORMAT_STRING "%08x"
# define HEX32_FORMAT_STRING "%x"
#else
# ifdef X64
# define ZHEX32_FORMAT_STRING "%08I32x"
# define HEX32_FORMAT_STRING "%I32x"
# else
# define ZHEX32_FORMAT_STRING "%08x"
# define HEX32_FORMAT_STRING "%x"
# endif
#endif
#ifdef X64
# define PFMT ZHEX64_FORMAT_STRING
# define PIFMT HEX64_FORMAT_STRING
# define SZFMT INT64_FORMAT_STRING
# define SSZFMT INT64_FORMAT_STRING
# define SZFC UINT64_FORMAT_CODE
# define SSZFC INT64_FORMAT_CODE
#else
# define PFMT ZHEX32_FORMAT_STRING
# define PIFMT HEX32_FORMAT_STRING
# define SZFMT "%u"
# define SSZFMT "%d"
# define SZFC "u"
# define SSZFC "d"
#endif
#define PFX "%p" /**< printf format code for pointers */
#define PIFX "0x" PIFMT /**< printf format code for pointer-sized integers */
#ifndef INFINITE
# define INFINITE 0xFFFFFFFF
#endif
/* printf codes for {thread,process}_id_t */
#ifdef WINDOWS
# define PIDFMT SZFMT /**< printf format code for process_id_t */
# define TIDFMT SZFMT /**< printf format code for thread_id_t */
#else
# define PIDFMT "%d" /**< printf format code for process_id_t */
# ifdef MACOS
# define TIDFMT \
UINT64_FORMAT_STRING /**< printf format code for thread_id_t \
*/
# else
# define TIDFMT "%d" /**< printf format code for thread_id_t */
# endif
#endif
/** 128-bit XMM register. */
typedef union _dr_xmm_t {
#ifdef X64
uint64 u64[2]; /**< Representation as 2 64-bit integers. */
#endif
uint u32[4]; /**< Representation as 4 32-bit integers. */
byte u8[16]; /**< Representation as 16 8-bit integers. */
reg_t reg[IF_X64_ELSE(2, 4)]; /**< Representation as 2 or 4 registers. */
} dr_xmm_t;
/** 256-bit YMM register. */
typedef union _dr_ymm_t {
/* We avoid having 8-byte-aligned fields here for 32-bit: they cause
* cl to add padding in app_state_at_intercept_t and unprotected_context_t,
* which messes up our interception stack layout and our x86.asm offsets.
* We don't access these very often, so we just omit this field.
*
* With the new dr_mcontext_t's size field pushing its ymm field to 0x44
* having an 8-byte-aligned field here adds 4 bytes padding.
* We could shrink PRE_XMM_PADDING for client header files but simpler
* to just have u64 only be there for 64-bit for clients.
* We do the same thing for dr_xmm_t just to look consistent.
*/
#ifndef DYNAMORIO_INTERNAL
# ifdef X64
uint64 u64[4]; /**< Representation as 4 64-bit integers. */
# endif
#endif
uint u32[8]; /**< Representation as 8 32-bit integers. */
byte u8[32]; /**< Representation as 32 8-bit integers. */
reg_t reg[IF_X64_ELSE(4, 8)]; /**< Representation as 4 or 8 registers. */
} dr_ymm_t;
/** 512-bit ZMM register. */
typedef union _dr_zmm_t {
#ifndef DYNAMORIO_INTERNAL
# ifdef X64
uint64 u64[8]; /**< Representation as 8 64-bit integers. */
# endif
#endif
uint u32[16]; /**< Representation as 16 32-bit integers. */
byte u8[64]; /**< Representation as 64 8-bit integers. */
reg_t reg[IF_X64_ELSE(8, 16)]; /**< Representation as 8 or 16 registers. */
} dr_zmm_t;
/* The register may be only 16 bits wide on systems without AVX512BW, but can be up to
* MAX_KL = 64 bits.
*/
/** AVX-512 OpMask (k-)register. */
typedef uint64 dr_opmask_t;
#if defined(AARCHXX)
/**
* 512-bit ARM Scalable Vector Extension (SVE) vector registers Zn.
* Low 128 bits of Zn overlap with existing ARM Advanced SIMD (NEON) Vn registers.
* The SVE specification defines the following valid vector lengths:
* 128 256 384 512 640 768 896 1024 1152 1280 1408 1536 1664 1792 1920 2048
* We currently support 512-bit maximum due to DR's stack size limitation,
* (machine context stored in the stack). In AArch64, align to 16 bytes for
* better performance. In AArch32, we're not using any uint64 fields here to
* avoid alignment padding in sensitive structs. We could alternatively use
* pragma pack.
*/
# ifdef X64
typedef union ALIGN_VAR(16) _dr_simd_t {
byte b; /**< Byte (8 bit, Bn) scalar element of Vn, Zn, or Pn. */
ushort h; /**< Halfword (16 bit, Hn) scalar element of Vn, Zn and Pn. */
uint s; /**< Singleword (32 bit, Sn) scalar element of Vn, Zn and Pn. */
uint64 d; /**< Doubleword (64 bit, Dn) scalar element of Vn, Zn and Pn. */
uint q[4]; /**< The full 128 bit Vn register, Qn as q[3]:q[2]:q[1]:q[0]. */
uint u32[16]; /**< The full 512 bit Zn register as Singleword (32-bit) elements. */
uint64 u64[8]; /**< The full 512 bit Zn register as Doubleword (64-bit) elements. */
} dr_simd_t;
/**
* 64-bit Arm Scalable Vector Extension (SVE) predicate register Pn.
* SVE Pn registers are used to hold mask values that control the operation of some SVE
* instructions. Pn registers have one bit for every byte of a Zn register to the size
* of a Pn register is always 1/8 the size of a Zn register.
* DynamoRIO currently supports up to 512-bit Zn registers and 64-bit Pn registers.
*/
typedef union _dr_svep_t {
ushort u16[4]; /**< The full 64-bit Pn or FFR register as 16-bit elements. */
uint u32[2]; /**< The full 64-bit Pn or FFR register as 32-bit elements. */
uint64 u64[1]; /**< The full 64-bit Pn or FFR register as 64-bit elements. */
} dr_svep_t;
/**
* 64-bit Arm Scalable Vector Extension (SVE) First Fault Register (FFR).
* FFR is a special purpose predicate register used by some SVE instructions.
*/
typedef dr_svep_t dr_ffr_t;
# else
typedef union _dr_simd_t {
uint s[4]; /**< Representation as 4 32-bit Sn elements. */
uint d[4]; /**< Representation as 2 64-bit Dn elements: d[3]:d[2]; d[1]:d[0]. */
uint u32[4]; /**< The full 128-bit register. */
} dr_simd_t;
# endif
# ifdef X64
# define MCXT_NUM_SIMD_SVE_SLOTS \
32 /**< Number of 512-bit SIMD Vn/Zn slots in dr_mcontext_t. \
*/
# define MCXT_NUM_SVEP_SLOTS 16 /**< Number of SIMD Pn slots in dr_mcontext_t. */
# define MCXT_NUM_FFR_SLOTS \
1 /**< Number of first-fault register slots in dr_mcontext_t. */
/** Total number of SIMD register slots in dr_mcontext_t. */
# define MCXT_NUM_SIMD_SLOTS \
(MCXT_NUM_SIMD_SVE_SLOTS + MCXT_NUM_SVEP_SLOTS + MCXT_NUM_FFR_SLOTS)
# else
# define MCXT_NUM_SIMD_SLOTS \
16 /**< Number of 128-bit SIMD Vn slots in dr_mcontext_t. \
*/
/* 32bit ARM does not have these slots, but they are defined for compatibility.
*/
# define MCXT_NUM_SVEP_SLOTS 0
# define MCXT_NUM_FFR_SLOTS 0
# endif
# define PRE_SIMD_PADDING \
0 /**< Bytes of padding before xmm/ymm dr_mcontext_t slots. \
*/
# define MCXT_NUM_OPMASK_SLOTS \
0 /**< Number of 16-64-bit OpMask Kn slots in dr_mcontext_t, \
* if architecture supports. \
*/
#elif defined(X86)
/* If this is increased, you'll probably need to increase the size of
* inject_into_thread's buf and INTERCEPTION_CODE_SIZE (for Windows).
* Also, update MCXT_NUM_SIMD_SLOTS in x86.asm and get_xmm_caller_saved.
* i#437: YMM is an extension of XMM from 128-bit to 256-bit without
* adding new ones, so code operating on XMM often also operates on YMM,
* and thus some *XMM* macros also apply to *YMM*.
*/
# ifdef X64
# ifdef WINDOWS
/* TODO i#1312: support AVX-512 extended registers. */
/**< Number of [xyz]mm0-5 reg slots in dr_mcontext_t pre AVX-512 in-use. */
# define MCXT_NUM_SIMD_SSE_AVX_SLOTS 6
/**< Number of [xyz]mm0-5 reg slots in dr_mcontext_t */
# define MCXT_NUM_SIMD_SLOTS 6
# else
/**< Number of [xyz]mm-15 reg slots in dr_mcontext_t pre AVX-512 in-use. */
# define MCXT_NUM_SIMD_SSE_AVX_SLOTS 16
/**< Number of [xyz]mm0-31 reg slots in dr_mcontext_t */
# define MCXT_NUM_SIMD_SLOTS 32
# endif
/**< Bytes of padding before simd dr_mcontext_t slots */
# define PRE_XMM_PADDING 48
# else
/**< Number of [xyz]mm0-7 reg slots in dr_mcontext_t pre AVX-512 in-use. */
# define MCXT_NUM_SIMD_SSE_AVX_SLOTS 8
/**< Number of [xyz]mm0-7 reg slots in dr_mcontext_t */
# define MCXT_NUM_SIMD_SLOTS 8
/**< Bytes of padding before simd dr_mcontext_t slots */
# define PRE_XMM_PADDING 24
# endif
/**< Number of 16-64-bit OpMask Kn slots in dr_mcontext_t, if architecture supports. */
# define MCXT_NUM_OPMASK_SLOTS 8
#elif defined(RISCV64)
/**
* 256-bit RISC-V Vector extension registers.
* Vector register length can be from 64 to 65536 bits in the power of 2.
* Currently we support implementations of up to 256 bits due to limit of DR's
* stack size and 12-bit signed immediate range. Also, align to 16 bytes for
* better performance.
*/
typedef union ALIGN_VAR(16) _dr_simd_t {
uint u32[8]; /**< Representation as 8 32-bit elements. */
uint64 u64[4]; /**< The full 256-bit register. */
} dr_simd_t;
# define MCXT_NUM_SIMD_SLOTS 32
# define MCXT_NUM_OPMASK_SLOTS 0
#else
# error NYI
#endif /* AARCHXX/X86/RISCV64 */
#ifdef DR_NUM_SIMD_SLOTS_COMPATIBILITY
# undef NUM_SIMD_SLOTS
/**
* Number of saved SIMD slots in dr_mcontext_t.
*/
# define NUM_SIMD_SLOTS proc_num_simd_saved()
# define NUM_XMM_SLOTS NUM_SIMD_SLOTS /* for backward compatibility */
#endif /* DR_NUM_SIMD_SLOTS_COMPATIBILITY */
/** Values for the flags field of dr_mcontext_t */
typedef enum {
/**
* On x86, selects the xdi, xsi, xbp, xbx, xdx, xcx, xax, and r8-r15 fields (i.e.,
* all of the general-purpose registers excluding xsp, xip, and xflags).
* On ARM, selects r0-r12 and r14.
* On AArch64, selects r0-r30.
*/
DR_MC_INTEGER = 0x01,
/* XXX i#2710: The link register should be under DR_MC_CONTROL */
/**
* On x86, selects the xsp, xflags, and xip fields.
* On ARM, selects the sp, pc, and cpsr fields.
* On AArch64, selects the sp, pc, and nzcv fields.
* On RISC-V, selects the sp, pc and fcsr fields.
* \note: The xip/pc field is only honored as an input for
* dr_redirect_execution(), and as an output for system call
* events.
*/
DR_MC_CONTROL = 0x02,
/**
* Selects the simd fields. This flag is ignored unless
* dr_mcontext_xmm_fields_valid() returns true. If
* dr_mcontext_xmm_fields_valid() returns false, the application values of
* the multimedia registers remain in the registers themselves.
*/
DR_MC_MULTIMEDIA = 0x04,
/** Selects all fields */
DR_MC_ALL = (DR_MC_INTEGER | DR_MC_CONTROL | DR_MC_MULTIMEDIA),
} dr_mcontext_flags_t;
/**
* Machine context structure.
*/
typedef struct _dr_mcontext_t {
/**
* The size of this structure. This field must be set prior to filling
* in the fields to support forward compatibility.
*/
size_t size;
/**
* The valid fields of this structure. This field must be set prior to
* filling in the fields. For input requests (dr_get_mcontext()), this
* indicates which fields should be written. Writing the multimedia fields
* frequently can incur a performance hit. For output requests
* (dr_set_mcontext() and dr_redirect_execution()), this indicates which
* fields will be copied to the actual context.
*/
dr_mcontext_flags_t flags;
#ifdef DYNAMORIO_INTERNAL
# include "mcxtx_api.h"
#else
# include "dr_mcxtx.h"
#endif
} dr_mcontext_t;
/** The opaque type used to represent linear lists of #instr_t instructions. */
typedef struct _instrlist_t instrlist_t;
/** Alias for the #_module_data_t structure holding library information. */
typedef struct _module_data_t module_data_t;
#ifdef X64
/**
* Upper note values are reserved for core DR.
*/
# define DR_NOTE_FIRST_RESERVED 0xffffffffffff0000ULL
#else
/**
* Upper note values are reserved for core DR.
*/
# define DR_NOTE_FIRST_RESERVED 0xffff0000UL
#endif
enum {
/**
* Identifies an annotation point. This label will be replaced by a
* clean call to the registered annotation handler.
*/
DR_NOTE_ANNOTATION = DR_NOTE_FIRST_RESERVED + 1,
DR_NOTE_RSEQ,
DR_NOTE_LDEX,
/** Identifies the end of a clean call. */
/* This is used to allow instrumentation pre-and-post a clean call for i#4128. */
DR_NOTE_CLEAN_CALL_END,
/**
* Identifies a point at which clients should restore all registers to
* their application values, as required for DR's internal block mangling.
*/
DR_NOTE_REG_BARRIER,
/**
* Used for internal translation from an instruction list. These apply not only to
* client-inserted clean calls but all inserted calls whether inserted by
* clients or DR and whether fully clean or not. This is thus distinct from
* #DR_NOTE_CLEAN_CALL_END.
*/
DR_NOTE_CALL_SEQUENCE_START,
DR_NOTE_CALL_SEQUENCE_END,
/**
* Placed at the top of a basic block, this identifies the entry to an "rseq" (Linux
* restartable sequence) region. The first two label data fields (see
* instr_get_label_data_area()) are filled in with this rseq region's end PC
* and its abort handler PC, in that order.
*/
DR_NOTE_RSEQ_ENTRY,
};
/**
* Structure written by dr_get_time() to specify the current time.
*/
typedef struct {
uint year; /**< The current year. */
uint month; /**< The current month, in the range 1 to 12. */
uint day_of_week; /**< The day of the week, in the range 0 to 6. */
uint day; /**< The day of the month, in the range 1 to 31. */
uint hour; /**< The hour of the day, in the range 0 to 23. */
uint minute; /**< The minutes past the hour. */
uint second; /**< The seconds past the minute. */
uint milliseconds; /**< The milliseconds past the second. */
} dr_time_t;
/**
* Used by dr_get_stats() and dr_app_stop_and_cleanup_with_stats()
*/
typedef struct _dr_stats_t {
/** The size of this structure. Set this to sizeof(dr_stats_t). */
size_t size;
/** The total number of basic blocks ever built so far, globally. This
* includes duplicates and blocks that were deleted for consistency
* or capacity reasons or thread-private caches.
*/
uint64 basic_block_count;
/** Peak number of simultaneous threads under DR control. */
uint64 peak_num_threads;
/** Accumulated total number of threads encountered by DR. */
uint64 num_threads_created;
/**
* Thread synchronization attempts retried due to the target thread being at
* an un-translatable spot.
*/
uint64 synchs_not_at_safe_spot;
/** Peak number of memory blocks used for unreachable heaps. */
uint64 peak_vmm_blocks_unreach_heap;
/** Peak number of memory blocks used for (unreachable) thread stacks. */
uint64 peak_vmm_blocks_unreach_stack;
/** Peak number of memory blocks used for unreachable specialized heaps. */
uint64 peak_vmm_blocks_unreach_special_heap;
/** Peak number of memory blocks used for other unreachable mappings. */
uint64 peak_vmm_blocks_unreach_special_mmap;
/** Peak number of memory blocks used for reachable heaps. */
uint64 peak_vmm_blocks_reach_heap;
/** Peak number of memory blocks used for (reachable) code caches. */
uint64 peak_vmm_blocks_reach_cache;
/** Peak number of memory blocks used for reachable specialized heaps. */
uint64 peak_vmm_blocks_reach_special_heap;
/** Peak number of memory blocks used for other reachable mappings. */
uint64 peak_vmm_blocks_reach_special_mmap;
/** Signals delivered to native threads. */
uint64 num_native_signals;
/** Number of exits from the code cache. */
uint64 num_cache_exits;
} dr_stats_t;
/**
* Error codes of DR API routines.
*/
typedef enum {
/**
* Invalid parameter passed to the API routine.
*/
DR_ERROR_INVALID_PARAMETER = 1,
/**
* Insufficient size of passed buffer.
*/
DR_ERROR_INSUFFICIENT_SPACE = 2,
/**
* String encoding is unknown.
*/
DR_ERROR_UNKNOWN_ENCODING = 3,
/**
* Feature of API routine not yet implemented.
*/
DR_ERROR_NOT_IMPLEMENTED = 4,
} dr_error_code_t;
/**
* Identifies where a thread's control is at any one point.
* Used with client PC sampling using dr_set_itimer().
*/
typedef enum {
DR_WHERE_APP = 0, /**< Control is in native application code. */
DR_WHERE_INTERP, /**< Control is in basic block building. */
DR_WHERE_DISPATCH, /**< Control is in d_r_dispatch. */
DR_WHERE_MONITOR, /**< Control is in trace building. */
DR_WHERE_SYSCALL_HANDLER, /**< Control is in system call handling. */
DR_WHERE_SIGNAL_HANDLER, /**< Control is in signal handling. */
DR_WHERE_TRAMPOLINE, /**< Control is in trampoline hooks. */
DR_WHERE_CONTEXT_SWITCH, /**< Control is in context switching. */
DR_WHERE_IBL, /**< Control is in inlined indirect branch lookup. */
DR_WHERE_FCACHE, /**< Control is in the code cache. */
DR_WHERE_CLEAN_CALLEE, /**< Control is in a clean call. */
DR_WHERE_UNKNOWN, /**< Control is in an unknown location. */
#ifdef HOT_PATCHING_INTERFACE
DR_WHERE_HOTPATCH, /**< Control is in hotpatching. */
#endif
DR_WHERE_LAST /**< Equals the count of DR_WHERE_xxx locations. */
} dr_where_am_i_t;
/**
* Flags to request non-default preservation of state in a clean call
* as well as other call options. This is used with dr_insert_clean_call_ex(),
* dr_insert_clean_call_ex_varg(), and dr_register_clean_call_insertion_event().
*/
typedef enum {
/**
* Save legacy floating-point state (x86-specific; not saved by default).
* The last floating-point instruction address (FIP) in the saved state is
* left in an untranslated state (i.e., it may point into the code cache).
* This flag is orthogonal to the saving of SIMD registers and related flags below.
*/
DR_CLEANCALL_SAVE_FLOAT = 0x0001,
/**
* Skip saving the flags and skip clearing the flags (including
* DF) for client execution. Note that this can cause problems
* if dr_redirect_execution() is called from a clean call,
* as an uninitialized flags value can cause subtle errors.
*/
DR_CLEANCALL_NOSAVE_FLAGS = 0x0002,
/** Skip saving any XMM or YMM registers (saved by default). */
DR_CLEANCALL_NOSAVE_XMM = 0x0004,
/** Skip saving any XMM or YMM registers that are never used as parameters. */
DR_CLEANCALL_NOSAVE_XMM_NONPARAM = 0x0008,
/** Skip saving any XMM or YMM registers that are never used as return values. */
DR_CLEANCALL_NOSAVE_XMM_NONRET = 0x0010,
/**
* Requests that an indirect call be used to ensure reachability, both for
* reaching the callee and for any out-of-line helper routine calls.
* Only honored for 64-bit mode, where r11 will be used for the indirection.
*/
DR_CLEANCALL_INDIRECT = 0x0020,
/* internal use only: maps to META_CALL_RETURNS_TO_NATIVE in insert_meta_call_vargs */
DR_CLEANCALL_RETURNS_TO_NATIVE = 0x0040,
/**
* Requests that out-of-line state save and restore routines be used even
* when a subset of the state does not need to be preserved for this callee.
* Also disables inlining.
* This helps guarantee that the inserted code remains small.
*/
DR_CLEANCALL_ALWAYS_OUT_OF_LINE = 0x0080,
/**
* Indicates that the callee will access the application context (either as
* passed parameters or by calling dr_get_mcontext()). This flag is passed
* to callbacks registered with dr_register_clean_call_insertion_event()
* requesting that register reservation code in clients and libraries restore
* application values to all registers. Without this flag, register values
* observed by the callee may be values written by instrumentation rather than
* application values. If the intent is to have a mixture of application and
* tool values in registers, manual restoration is required rather than passing
* this automation flag.
*/
DR_CLEANCALL_READS_APP_CONTEXT = 0x0100,
/**
* Indicates that the callee will modify the application context (by calling
* dr_set_mcontext()). This flag is passed to callbacks registered with
* dr_register_clean_call_insertion_event() requesting that register reservation
* code in clients and libraries update spilled application register values.
* Without this flag, changes made by dr_set_mcontext() may be undone by later
* restores of spilled values.
*/
DR_CLEANCALL_WRITES_APP_CONTEXT = 0x0200,
/**
* Indicates that the clean call may be skipped by inserted tool control flow.
* This affects how register spilling and restoring occurs when combined with the
* #DR_CLEANCALL_READS_APP_CONTEXT flag. Tool values may be clobbered when this
* flag is used. If control flow and clean call context access is used with
* registers holding tool values across the clean call, manual restoration may be
* required rather than passing any of these automated flags.
*
* Combining this flag with #DR_CLEANCALL_WRITES_APP_CONTEXT is not supported.
* Manual updates are required for such a combination.
*/
/* XXX i#5168: Supporting multipath with writing requires extra drreg
* functionality for stateless respills, but given that we have not seen any code
* that requires it we have not put the effort into supporting it. It is possible
* that the component inserting the multi-path clean call is not the one controlling
* the drreg usage and so would have a hard time inserting manual restores.
*/
DR_CLEANCALL_MULTIPATH = 0x0400,
} dr_cleancall_save_t;
#endif /* _DR_DEFINES_H_ */