* 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.
*/
#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>
#ifndef DYNAMORIO_INTERNAL
# 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
# define DR_UNS_EXCEPT_TESTS_API
#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
* behave properly. It indents the guard. There seems to be no workaround.
*/
# ifndef __cplusplus
# ifdef WINDOWS
# define inline __inline
# else
# define inline __inline__
# endif
# ifndef DR_DO_NOT_DEFINE_bool
# ifdef DR__Bool_EXISTS
typedef _Bool bool;
# else
typedef char bool;
# endif
# endif
# ifndef true
# define true (1)
# endif
# ifndef false
# define false (0)
# endif
# endif
# ifdef UNIX
# include <sys/types.h>
# endif
# ifdef WINDOWS
# pragma warning(disable : 4201)
# if _MSC_VER >= 1400 && _MSC_VER < 1500
# pragma warning(disable : 4244)
# endif
# endif
#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
# define NOINLINE __declspec(noinline)
#else
* (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
* 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
* 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
# 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
#ifdef X64
typedef uint64 reg_t;
#else
typedef uint reg_t;
#endif
typedef reg_t ptr_uint_t;
#ifdef X64
typedef int64 ptr_int_t;
#else
typedef int ptr_int_t;
#endif
* 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
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
* we have to use HANDLE on Windows
* we hide the distinction behind the file_t type
*/
typedef HANDLE file_t;
# define INVALID_FILE INVALID_HANDLE_VALUE
* INVALID_HANDLE_VALUE. We leave INVALID_HANDLE_VALUE as is,
* since it equals INVALID_FILE
*/
# define STDOUT (dr_get_stdout_file())
# define STDERR (dr_get_stderr_file())
# define STDIN (dr_get_stdin_file())
# endif
#endif
#ifdef UNIX
typedef int file_t;
# define INVALID_FILE -1
extern file_t our_stdout;
extern file_t our_stderr;
extern file_t our_stdin;
# define STDOUT our_stdout
# define STDERR our_stderr
# define STDIN our_stdin
#endif
* 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 IN
# define IN
#endif
#ifndef OUT
# define OUT
#endif
#ifndef INOUT
# define INOUT
#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
#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
* 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"
#define PIFX "0x" PIFMT
#ifndef INFINITE
# define INFINITE 0xFFFFFFFF
#endif
#ifdef WINDOWS
# define PIDFMT SZFMT
# define TIDFMT SZFMT
#else
# define PIDFMT "%d"
# ifdef MACOS
# define TIDFMT \
UINT64_FORMAT_STRING
*/
# else
# define TIDFMT "%d"
# endif
#endif
typedef union _dr_xmm_t {
#ifdef X64
uint64 u64[2];
#endif
uint u32[4];
byte u8[16];
reg_t reg[IF_X64_ELSE(2, 4)];
} dr_xmm_t;
typedef union _dr_ymm_t {
* 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];
# endif
#endif
uint u32[8];
byte u8[32];
reg_t reg[IF_X64_ELSE(4, 8)];
} dr_ymm_t;
typedef union _dr_zmm_t {
#ifndef DYNAMORIO_INTERNAL
# ifdef X64
uint64 u64[8];
# endif
#endif
uint u32[16];
byte u8[64];
reg_t reg[IF_X64_ELSE(8, 16)];
} dr_zmm_t;
* MAX_KL = 64 bits.
*/
typedef uint64 dr_opmask_t;
#if defined(AARCHXX)
* 512-bit ARM Scalable Vector Extension (SVE) vector registers Zn and
* predicate registers Pn. 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;
ushort h;
uint s;
uint64 d;
uint q[4];
uint u32[16];
} dr_simd_t;
# else
typedef union _dr_simd_t {
uint s[4];
uint d[4];
uint u32[4];
} dr_simd_t;
# endif
# ifdef X64
# define MCXT_NUM_SIMD_SVE_SLOTS \
32
*/
# define MCXT_NUM_SVEP_SLOTS 16
# define MCXT_NUM_FFR_SLOTS \
1
# 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
*/
*/
# define MCXT_NUM_SVEP_SLOTS 0
# define MCXT_NUM_FFR_SLOTS 0
# endif
# define PRE_SIMD_PADDING \
0
*/
# define MCXT_NUM_OPMASK_SLOTS \
0
* if architecture supports. \
*/
#elif defined(X86)
* 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
# define MCXT_NUM_SIMD_SSE_AVX_SLOTS 6
# define MCXT_NUM_SIMD_SLOTS 6
# else
# define MCXT_NUM_SIMD_SSE_AVX_SLOTS 16
# define MCXT_NUM_SIMD_SLOTS 32
# endif
# define PRE_XMM_PADDING 48
# else
# define MCXT_NUM_SIMD_SSE_AVX_SLOTS 8
# define MCXT_NUM_SIMD_SLOTS 8
# define PRE_XMM_PADDING 24
# endif
# define MCXT_NUM_OPMASK_SLOTS 8
#elif defined(RISCV64)
typedef union ALIGN_VAR(16) _dr_simd_t {
byte b;
ushort h;
uint s;
uint d[2];
uint q[4];
uint u32[4];
} dr_simd_t;
# define MCXT_NUM_SIMD_SLOTS 8
# define MCXT_NUM_OPMASK_SLOTS 0
#else
# error NYI
#endif
#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
#endif
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,
* 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,
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;
typedef struct _instrlist_t instrlist_t;
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,
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;
uint month;
uint day_of_week;
uint day;
uint hour;
uint minute;
uint second;
uint milliseconds;
} dr_time_t;
* Used by dr_get_stats() and dr_app_stop_and_cleanup_with_stats()
*/
typedef struct _dr_stats_t {
size_t size;
* includes duplicates and blocks that were deleted for consistency
* or capacity reasons or thread-private caches.
*/
uint64 basic_block_count;
uint64 peak_num_threads;
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;
uint64 peak_vmm_blocks_unreach_heap;
uint64 peak_vmm_blocks_unreach_stack;
uint64 peak_vmm_blocks_unreach_special_heap;
uint64 peak_vmm_blocks_unreach_special_mmap;
uint64 peak_vmm_blocks_reach_heap;
uint64 peak_vmm_blocks_reach_cache;
uint64 peak_vmm_blocks_reach_special_heap;
uint64 peak_vmm_blocks_reach_special_mmap;
uint64 num_native_signals;
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,
DR_WHERE_INTERP,
DR_WHERE_DISPATCH,
DR_WHERE_MONITOR,
DR_WHERE_SYSCALL_HANDLER,
DR_WHERE_SIGNAL_HANDLER,
DR_WHERE_TRAMPOLINE,
DR_WHERE_CONTEXT_SWITCH,
DR_WHERE_IBL,
DR_WHERE_FCACHE,
DR_WHERE_CLEAN_CALLEE,
DR_WHERE_UNKNOWN,
#ifdef HOT_PATCHING_INTERFACE
DR_WHERE_HOTPATCH,
#endif
DR_WHERE_LAST
} 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,
DR_CLEANCALL_NOSAVE_XMM = 0x0004,
DR_CLEANCALL_NOSAVE_XMM_NONPARAM = 0x0008,
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,
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.
*/
* 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