* Copyright (c) 2011-2023 Google, Inc. All rights reserved.
* Copyright (c) 2000-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.
*/
* globals.h - global defines and typedefs, included in all files
*/
#ifndef _GLOBALS_H_
#define _GLOBALS_H_ 1
#include "configure.h"
#ifdef WINDOWS
* problems w/ new Vista-only flags like in PROCESS_ALL_ACCESS in win32/injector.c.
* The problematic flag there, PROCESS_QUERY_LIMITED_INFORMATION, is a subset of
* PROCESS_QUERY_INFORMATION, so we don't lose anything by not asking for it on Vista.
* But if they add new non-subset flags in the future we'd need dynamic dispatch,
* as earlier Windows versions give access denied on unknown flags!
*/
# define _WIN32_WINNT _WIN32_WINNT_NT4
# define WIN32_LEAN_AND_MEAN
# pragma warning(disable : 4054)
# pragma warning(disable : 4100)
# pragma warning(disable : 4127)
# pragma warning(disable : 4189)
# pragma warning( \
disable : 4204)
# pragma warning(disable : 4210)
# pragma warning(disable : 4505)
# pragma warning( \
disable : 4702)
# pragma warning(disable : 4324)
# pragma warning(disable : 4709)
# pragma warning(disable : 4214)
* supposed to include identifier in the pop pragma and they don't
*/
# pragma warning( \
disable : 4159)
* switch to the _s versions when on Windows.
*/
# pragma warning(disable : 4996)
#endif
#include "globals_shared.h"
#define DYNAMORIO_STATS_EXPORTS 1
#ifdef WINDOWS
# define DYNAMORIO_EXPORT __declspec(dllexport)
#elif defined(USE_VISIBILITY_ATTRIBUTES)
* own uses won't be preempted. Note that for DR_APP_API in
* lib/dr_app.h we get a link error trying to use "protected": but we
* don't use dr_app_* internally anyway, so leaving as default.
*/
# define DYNAMORIO_EXPORT __attribute__((visibility("protected")))
#else
# define DYNAMORIO_EXPORT
#endif
#define DR_API DYNAMORIO_EXPORT
#if (defined(DEBUG) && defined(BUILD_TESTS)) || defined(UNSUPPORTED_API)
# define DR_UNS_EXCEPT_TESTS_API DR_API
#else
# define DR_UNS_EXCEPT_TESTS_API
#endif
#ifdef UNSUPPORTED_API
* we can't just change a define and export these anymore anyway: they would have
* to be moved to the _api.h public headers.
*/
# define DR_UNS_API DR_API
#else
# define DR_UNS_API
#endif
#ifdef WINDOWS
# define DISABLE_NULL_SANITIZER
#else
* we need to first check whether __has_attribute is defined, to ensure
* portability. We saw issues in the Android-ARM cross compile without this.
*/
# if defined __has_attribute
# if __has_attribute(__no_sanitize__) && defined(HAVE_FNOSANITIZE_NULL)
* of this, it stores and retrieves pointers from the stack frame. Each
* pointer dereference uses a different stack location. So, if there are too
* many pointer dereferences in a function (like dump_global_stats and
* dump_thread_stats) it will increase the size of the stack frame a lot
* (127KB and 147KB respectively for the mentioned examples) when the null
* sanitizer is enabled. The following macro lets us disable this check for
* methods annotated with it.
*/
# define DISABLE_NULL_SANITIZER __attribute__((no_sanitize("null")))
# endif
# endif
# ifndef DISABLE_NULL_SANITIZER
# define DISABLE_NULL_SANITIZER
# endif
#endif
#define INLINE_ONCE inline
#include <stdlib.h>
#include <stdio.h>
* lib/globals_shared.h!
*/
#ifdef WINDOWS
# include <windows.h>
typedef unsigned long ulong;
typedef unsigned short ushort;
* not all users of globals_shared.h want that included, so we
* duplicate it here (we do have Linux file_t stuff in globals_shared.h)
*/
* 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
# define STDOUT (file_t) get_stdout_handle()
# define STDERR (file_t) get_stderr_handle()
# define STDIN (file_t) get_stdin_handle()
# define DIRSEP '\\'
# define ALT_DIRSEP '/'
#else
# if defined(MACOS) || defined(ANDROID)
typedef unsigned long ulong;
# endif
# include <sys/types.h>
# define DIRSEP '/'
# define ALT_DIRSEP DIRSEP
#endif
* linux routines use -1 as sentinel, right?
* on win32, are ids only 16 bits?
* if so, change thread_id_t to be a signed int and use -1?
* For now, based on observation, no process on linux and no thread on windows
* has id 0 (on windows even a new thread in its init apc has a non-0 id)
*/
#define INVALID_THREAD_ID 0
typedef unsigned char uchar;
typedef byte *cache_pc;
#define SUCCESS 0
#define FAILURE 1
#ifdef DGC_DIAGNOSTICS
# define _IF_DGCDIAG(x) , x
# define IF_DGCDIAG_ELSE(x, y) x
#else
# define _IF_DGCDIAG(x)
# define IF_DGCDIAG_ELSE(x, y) y
#endif
#if !defined(X86) && !defined(ARM) && !defined(AARCH64) && !defined(RISCV64)
# error Must define X86, ARM, AARCH64 or RISCV64: no other platforms are supported
#endif
#if defined(PAPI) && defined(WINDOWS)
# error PAPI does not work on WINDOWS
#endif
#ifdef DGC_DIAGNOSTICS
# ifndef PROGRAM_SHEPHERDING
# error DGC_DIAGNOSTICS requires PROGRAM_SHEPHERDING
# endif
# ifndef DEBUG
# error DGC_DIAGNOSTICS requires DEBUG
# endif
#endif
#ifndef PROGRAM_SHEPHERDING
# ifdef SIMULATE_ATTACK
# error SIMULATE_ATTACK requires PROGRAM_SHEPHERDING
# endif
#endif
extern const char dynamorio_version_string[];
extern const char dynamorio_buildmark[];
struct _instrlist_t;
struct _fragment_t;
typedef struct _fragment_t fragment_t;
struct _future_fragment_t;
typedef struct _future_fragment_t future_fragment_t;
struct _trace_t;
typedef struct _trace_t trace_t;
struct _linkstub_t;
typedef struct _linkstub_t linkstub_t;
struct _dcontext_t;
typedef struct _dcontext_t dcontext_t;
struct vm_area_vector_t;
typedef struct vm_area_vector_t vm_area_vector_t;
struct _coarse_info_t;
typedef struct _coarse_info_t coarse_info_t;
struct _coarse_freeze_info_t;
typedef struct _coarse_freeze_info_t coarse_freeze_info_t;
struct _module_data_t;
#if defined(RETURN_AFTER_CALL) || defined(RCT_IND_BRANCH)
struct _rct_module_table_t;
typedef struct _rct_module_table_t rct_module_table_t;
typedef enum {
RCT_RAC = 0,
RCT_RCT,
RCT_NUM_TYPES,
} rct_type_t;
#endif
typedef struct _thread_record_t {
thread_id_t id;
#ifdef WINDOWS
HANDLE handle;
bool retakeover;
#else
process_id_t pid;
bool execve;
#endif
uint num;
bool under_dynamo_control;
dcontext_t *dcontext;
struct _thread_record_t *next;
} thread_record_t;
#ifdef DR_APP_EXPORTS
# include "dr_app.h"
# undef DYNAMORIO_EXPORT
# define DYNAMORIO_EXPORT DR_APP_API
#endif
* the hardware implementation and can be one of:
* 128 256 384 512 640 768 896 1024 1152 1280 1408 1536 1664 1792 1920 2048
* See https://developer.arm.com/documentation/102476/0100/Introducing-SVE
* This variable stores the length for off-line decoding.
*/
extern int sve_veclen;
#include "heap.h"
#include "options_struct.h"
#include "utils.h"
#include "options.h"
#include "os_exports.h"
#include "arch_exports.h"
#include "drlibc.h"
#include "vmareas.h"
#include "instrlist.h"
#include "dispatch.h"
#include "dr_stats.h"
* (nudge handler, signal handler)?
*/
extern bool client_requested_exit;
typedef struct _client_to_do_list_t {
instrlist_t *ilist;
app_pc tag;
struct _client_to_do_list_t *next;
} client_todo_list_t;
typedef struct _client_flush_req_t {
app_pc start;
size_t size;
uint flush_id;
void (*flush_callback)(int);
struct _client_flush_req_t *next;
} client_flush_req_t;
* NULL during thread startup or teardown (i.e. mutex_wait_contended_lock() usage) */
#define IS_CLIENT_THREAD(dcontext) \
((dcontext) != NULL && dcontext != GLOBAL_DCONTEXT && \
(dcontext)->client_data != NULL && (dcontext)->client_data->is_client_thread)
#ifdef DEBUG
# define IS_CLIENT_THREAD_EXITING(dcontext) \
((dcontext) != NULL && dcontext != GLOBAL_DCONTEXT && \
(dcontext)->is_client_thread_exiting)
#endif
typedef struct _client_data_t {
void *user_field;
client_todo_list_t *to_do;
client_flush_req_t *flush_list;
mutex_t sideline_mutex;
module_data_t *no_delete_mod_data;
* synchronization support. is_client_thread means that the thread is currently
* completely owned by the client. client_thread_safe_for_sync is use to mark
* client-owned threads that are safe for synch_with_all_threads synchronization but
* are in dynamo/native code (such as in dr_thread_yield(), dr_sleep(),
* dr_mutex_lock() and dr_messagebox()). Note it does not need to be set when
* the client is in client library code. For dr_mutex_lock() we set client_grab_mutex
* to the client mutex that is being locked so that we can set
* client_thread_safe_for_sync only around the actual wait.
* FIXME - PR 231301, we may need a way for clients that call ntdll directly to
* mark client_thread_safe_for_synch for client-owned threads when calling out to
* ntdll. Especially if they're calling system calls that wait or take a long time
* to finish etc. Applies to generated code and other libraries called by the client
* lib as well.
*/
bool is_client_thread;
bool client_thread_safe_for_synch;
* for THREAD_SYNCH_TERMINATED_AND_CLEANED.
*/
bool at_safe_to_terminate_syscall;
bool suspendable;
bool left_unsuspended;
uint mutex_count;
void *client_grab_mutex;
#ifdef DEBUG
bool is_translating;
#endif
#ifdef LINUX
app_pc last_special_xl8;
#endif
bool in_pre_syscall;
bool in_post_syscall;
bool invoke_another_syscall;
bool mcontext_in_dcontext;
bool suspended;
priv_mcontext_t *cur_mc;
os_cxt_ptr_t os_cxt;
* but only upon failures.
*/
dr_error_code_t error_code;
} client_data_t;
#ifdef UNIX
typedef struct _pending_nudge_t {
nudge_arg_t arg;
struct _pending_nudge_t *next;
} pending_nudge_t;
#endif
#define DYNAMORIO_STACK_SIZE dynamo_options.stack_size
extern bool automatic_startup;
extern bool control_all_threads;
threads are under our control */
extern bool dynamo_heap_initialized;
extern bool dynamo_initialized;
extern bool dynamo_started;
extern bool dynamo_exited;
extern bool dynamo_exited_all_other_threads;
extern bool dynamo_exited_and_cleaned;
#ifdef DEBUG
extern bool dynamo_exited_log_and_stats;
#endif
extern bool dynamo_resetting;
extern bool dynamo_all_threads_synched;
* DR initializes, which equates to attaching (vs being launched by DR) on Linux.
* On Windows though we can't really tell the difference due to our late injection,
* so this is always set on Windows.
*/
extern bool dynamo_control_via_attach;
* go through the app interface.
*/
extern bool doing_detach;
extern thread_id_t detacher_tid;
extern event_t dr_app_started;
extern event_t dr_attach_finished;
extern bool standalone_library;
#ifdef UNIX
extern bool post_execve;
extern int num_execve_threads;
#endif
extern dr_statistics_t *d_r_stats;
extern file_t main_logfile;
extern byte *d_r_initstack;
extern mutex_t initstack_mutex;
extern byte *initstack_app_xsp;
#ifdef WINDOWS
extern byte *exception_stack;
#endif
* if any threads could still be using shared resources even if they aren't on
* the all_threads list */
extern volatile int exiting_thread_count;
extern volatile int uninit_thread_count;
void
pre_second_thread(void);
bool
is_on_initstack(byte *esp);
bool
is_on_dstack(dcontext_t *dcontext, byte *esp);
bool
is_currently_on_dstack(dcontext_t *dcontext);
#ifdef WINDOWS
extern bool dr_early_injected;
extern int dr_early_injected_location;
extern bool dr_earliest_injected;
extern bool dr_injected_primary_thread;
extern bool dr_injected_secondary_thread;
extern bool dr_late_injected_primary_thread;
#endif
#ifdef RETURN_AFTER_CALL
extern bool dr_preinjected;
#endif
extern bool dr_api_entry;
extern bool dr_api_exit;
* XXX: We currently never resize, assuming won't be seeing more than
* a few thousand threads: it should be simple to swap for a resizing
* table using generic_table_t though.
*/
#define ALL_THREADS_HASH_BITS 12
extern thread_record_t **all_threads;
extern mutex_t all_threads_lock;
DYNAMORIO_EXPORT int
dynamorio_app_init(void);
void
dynamorio_app_init_part_one_options();
int
dynamorio_app_init_part_two_finalize();
int
dynamorio_app_exit(void);
dcontext_t *
standalone_init(void);
void
standalone_exit(void);
thread_record_t *
thread_lookup(thread_id_t tid);
void
add_thread(IF_WINDOWS_ELSE_NP(HANDLE hthread, process_id_t pid), thread_id_t tid,
bool under_dynamo_control, dcontext_t *dcontext);
bool
remove_thread(IF_WINDOWS_(HANDLE hthread) thread_id_t tid);
uint
get_thread_num(thread_id_t tid);
int
d_r_get_num_threads(void);
bool
is_last_app_thread(void);
void
get_list_of_threads(thread_record_t ***list, int *num);
bool
is_thread_known(thread_id_t tid);
#ifdef UNIX
void
get_list_of_threads_ex(thread_record_t ***list, int *num, bool include_execve);
void
mark_thread_execve(thread_record_t *tr, bool execve);
#endif
bool
is_thread_initialized(void);
int
dynamo_thread_init(byte *dstack_in, priv_mcontext_t *mc, void *os_data,
bool client_thread);
int
dynamo_thread_exit(void);
void
dynamo_thread_stack_free_and_exit(byte *stack);
int
dynamo_other_thread_exit(thread_record_t *tr _IF_WINDOWS(bool detach_stacked_callbacks));
void
dynamo_thread_under_dynamo(dcontext_t *dcontext);
void
dynamo_thread_not_under_dynamo(dcontext_t *dcontext);
extern mutex_t thread_initexit_lock;
dcontext_t *
create_new_dynamo_context(bool initial, byte *dstack_in, priv_mcontext_t *mc);
void
initialize_dynamo_context(dcontext_t *dcontext);
dcontext_t *
create_callback_dcontext(dcontext_t *old_dcontext);
int
dynamo_nullcalls_exit(void);
int
dynamo_process_exit(void);
#ifdef UNIX
void
dynamorio_fork_init(dcontext_t *dcontext);
#endif
void
dynamorio_take_over_threads(dcontext_t *dcontext);
dr_statistics_t *
get_dr_stats(void);
int
dynamo_shared_exit(thread_record_t *toexit _IF_WINDOWS(bool detach_stacked_callbacks));
void
dynamo_process_exit_with_thread_info(void);
void
dynamo_thread_exit_pre_client(dcontext_t *dcontext, thread_id_t id);
void
dynamo_exit_post_detach(void);
void
entering_dynamorio(void);
void
exiting_dynamorio(void);
void
handle_system_call(dcontext_t *dcontext);
void
protect_data_section(uint sec, bool writable);
#ifdef DEBUG
const char *
get_data_section_name(app_pc pc);
bool
check_should_be_protected(uint sec);
# ifdef WINDOWS
bool
data_sections_enclose_region(app_pc start, app_pc end);
# endif
#endif
* sequences, exported so that micro-operations can assert that one is held
*/
extern mutex_t bb_building_lock;
extern volatile bool bb_lock_start;
extern recursive_lock_t change_linking_lock;
* since only two possibilities not using new type
*/
enum { READONLY = false, WRITABLE = true };
enum {
EXIT_REASON_SELFMOD = 0,
EXIT_REASON_FLOAT_PC_FNSAVE,
EXIT_REASON_FLOAT_PC_FXSAVE,
EXIT_REASON_FLOAT_PC_FXSAVE64,
EXIT_REASON_FLOAT_PC_XSAVE,
EXIT_REASON_FLOAT_PC_XSAVE64,
EXIT_REASON_NI_SYSCALL_INT_0x81,
EXIT_REASON_NI_SYSCALL_INT_0x82,
EXIT_REASON_SINGLE_STEP,
EXIT_REASON_RSEQ_ABORT,
};
* needs to equal the number of stubs in x86.asm:back_from_native_retstubs,
* which is checked at startup in native_exec.c.
* FIXME: Remove this limitation if we ever need to support true mutual
* recursion between native and non-native modules.
*/
enum { MAX_NATIVE_RETSTACK = 10 };
typedef struct _retaddr_and_retloc_t {
app_pc retaddr;
app_pc retloc;
} retaddr_and_retloc_t;
typedef struct try_except_context_t {
* small so minimal risk of dstack pressure. Alternatively, we
* can disallow nesting and have a single buffer per dcontext.
*/
dr_jmp_buf_t context;
struct try_except_context_t *prev_context;
} try_except_context_t;
* This, along with safe_read pc ranges, satisfies most TRY uses that
* don't have a dcontext (i#350).
*/
typedef struct _try_except_t {
try_except_context_t *try_except_state;
bool unwinding_exception;
* marks exception until an EXCEPT handles */
} try_except_t;
extern try_except_t global_try_except;
#ifdef UNIX
extern thread_id_t global_try_tid;
#endif
typedef struct {
* you must also change the offsets in <arch>/<arch.asm>
*/
priv_mcontext_t mcontext;
#ifdef UNIX
int dr_errno;
#endif
bool at_syscall;
* as well as syscalls handled from d_r_dispatch,
* and for reset to identify when at syscalls
*/
ushort exit_reason;
reg_t inline_spill_slots[CLEANCALL_NUM_INLINE_SLOTS];
} unprotected_context_t;
* N.B.: make sure to update these routines as necessary if
* you add or remove fields:
* create_new_dynamo_context
* create_callback_dcontext
* initialize_dynamo_context
* swap_dcontexts
* if you add any pointers to data structures, make sure callback_setup()
* clears them to prevent stale pointers on callback return
*/
struct _dcontext_t {
* be indirected through a modular field or explicitly copied in
* create_callback_dcontext() (like the modular fields are).
*/
* ignore_enterexit, you must also change the offsets in <arch>/<arch.s>
*/
* protected fields depending on whether they must be read-only
* when in the code cache.
* we waste sizeof(unprotected_context_t) bytes to provide runtime flexibility:
*/
union {
* (TEST(SELFPROT_DCONTEXT, dynamo_options.protect_mask))
* else we use the inlined upcontext
*/
unprotected_context_t *separate_upcontext;
unprotected_context_t upcontext;
} upcontext;
* a self-ptr (to inlined upcontext) or if we separate upcontext it points there.
*/
unprotected_context_t *upcontext_ptr;
* Also used to store the cache pc to execute when entering the code cache,
* and set to the sentinel value BACK_TO_NATIVE_AFTER_SYSCALL for native_exec.
* FIXME: change to a union?
*/
app_pc next_tag;
linkstub_t *last_exit;
byte *dstack;
bool is_exiting;
#ifdef WINDOWS
int app_errno;
void *app_fls_data;
void *priv_fls_data;
void *app_nt_rpc;
void *priv_nt_rpc;
void *app_nls_cache;
void *priv_nls_cache;
void *app_static_tls;
void *priv_static_tls;
void *app_stack_limit;
void *app_stack_base;
byte *teb_base;
* case 5441 Sygate interoperability hack */
* in cache by ignore/shared_syscall, ramifications? */
app_pc sysenter_storage;
bool ignore_enterexit;
#endif
* use per-exit separate data structures
*/
union {
* branch coming from fake linkstubs), while direct store the source unit
*/
app_pc src_tag;
coarse_info_t *dir_exit;
} coarse_exit;
dr_where_am_i_t whereami;
#ifdef UNIX
* https://www.arm.linux.org.uk/docs/faqs/signedchar.php
* But we need _signed_ char, so we use sbyte which explicitly qualifies
* as that.
*/
sbyte signals_pending;
#endif
* a new callback's as well, we should be able to get rid of this
*/
bool initialized;
thread_id_t owning_thread;
#ifdef UNIX
process_id_t owning_process;
#endif
#ifdef MACOS
uint thread_port;
#endif
thread_record_t *thread_record;
void *allocated_start;
fragment_t *last_fragment;
int sys_num;
#ifdef WINDOWS
reg_t *sys_param_base;
#endif
#if defined(UNIX) || defined(X64)
reg_t sys_param0;
reg_t sys_param1;
reg_t sys_param2;
reg_t sys_param3;
#endif
#ifdef UNIX
reg_t sys_param4;
bool sys_was_int;
bool sys_xbp;
# ifdef DEBUG
bool mprot_multi_areas;
# endif
#endif
#ifdef MACOS
reg_t app_xdx;
#endif
* For x86, default is to decode as base platform, but we want runtime ability to
* decode/encode 32-bit from 64-bit dynamorio.dll (we don't support the
* other way around: PR 236203). For ARM we must support swapping.
*/
dr_isa_mode_t isa_mode;
#ifdef ARM
* The actual type is not uint, we use them for better abstraction
* and better performace (avoiding a void * with separate allocation).
*/
uint encode_state[2];
uint decode_state[2];
#endif
void *link_field;
void *monitor_field;
void *fcache_field;
void *fragment_field;
void *heap_field;
void *vm_areas_field;
void *os_field;
void *synch_field;
#ifdef UNIX
void *signal_field;
void *pcprofile_field;
#endif
void *private_code;
#ifdef TRACE_HEAD_CACHE_INCR
cache_pc trace_head_pc;
#endif
#ifdef WINDOWS
dcontext_t *prev_unused;
bool valid;
* restore state of prior guy on callback stack, yet need current state
* to restore native state prior to callback return interrupt/syscall.
* Also used as temp next_tag slot for fcache_enter_indirect and cb ret.
*/
reg_t nonswapped_scratch;
#endif
* slot to hold asynch targets for APCs to know next target and
* for NtContinue and sigreturn to set next target
*/
app_pc asynch_target;
* d_r_dispatch() for native_exec syscalls
*/
app_pc native_exec_postsyscall;
* called into a native module.
*/
retaddr_and_retloc_t native_retstack[MAX_NATIVE_RETSTACK];
uint native_retstack_cur;
#ifdef PROGRAM_SHEPHERDING
bool alloc_no_reserve;
#endif
#ifdef CUSTOM_TRACES_RET_REMOVAL
int num_calls;
int num_rets;
int call_depth;
#endif
#ifdef CHECK_RETURNS_SSE2
int call_depth;
void *call_stack;
#endif
#ifdef DEBUG
file_t logfile;
thread_local_statistics_t *thread_stats;
bool expect_last_syscall_to_fail;
* during decode_fragment() for a coarse target
*/
bool in_opnd_disassemble;
#endif
#ifdef DEADLOCK_AVOIDANCE
thread_locks_t *thread_owned_locks;
#endif
#ifdef KSTATS
thread_kstats_t *thread_kstats;
#endif
#ifdef PROFILE_RDTSC
uint64 cache_enter_time;
uint64 start_time;
fragment_t *prev_fragment;
uint64 cache_frag_count;
uint64 cache_time[10];
uint64 cache_count[10];
#endif
client_data_t *client_data;
#ifdef DEBUG
bool is_client_thread_exiting;
#endif
* ends in a SYSENTER and to enable trace head marking. So it's really a
* monitor-centric variable. It's placed in the context for now so that
* it's not shared across contexts (as the monitor data is). Cross-context
* sharing of this field could cause inadvertent trace head marking,
* for example, during a callback. A longer-term fix may be to move it to
* a context-private non-shared monitor struct.
*/
bool trace_sysenter_exit;
* may appear to originate in DR but should be passed on to the app. */
app_pc forged_exception_addr;
* step exception when app comes to that address. */
app_pc single_step_addr;
#ifdef HOT_PATCHING_INTERFACE
bool nudge_thread;
dr_jmp_buf_t hotp_excpt_state;
#endif
try_except_t try_except;
#ifdef WINDOWS
* track properties of a syscall or a syscall pair. Even we don't
* expect to get APCs or callbacks while processing normal DLLs
* this should be per dcontext.
*/
aslr_syscall_context_t aslr_context;
* internal detach) thread (as detected by start address in intercept_apc),
* nudge_target is set to the corresponding nudge routine (currently always
* generic_nudge_target). We can then check this
* value in those routines after we come out of the cache as a security
* measure (xref case 552). This gives us some protection against an
* attacker leveraging our own detach routines and the like. FIXME - if
* the attacker is able to specify the start address for a newly created
* thread then they can fake this. */
void *nudge_target;
* cleanup. Used for nudge threads. */
bool free_app_stack;
bool nudge_terminate_process;
uint nudge_exit_code;
#endif
* can access it from other threads
*/
local_state_t *local_state;
#ifdef WINDOWS
* ldmp. An alternative solution is to call NtQueryInformationThread
* with ThreadQuerySetWin32StartAddress at dump time. According to
* Nebbet, however, a thread calling ZwReplyWaitReplyPort or
* ZwReplyWaitRecievePort will clobber the start address.
*/
app_pc win32_start_addr;
#endif
void *bb_build_info;
#ifdef UNIX
pending_nudge_t *nudge_pending;
fragment_t *interrupted_for_nudge;
# ifdef DEBUG
int libc_errno;
# endif
#else
# ifdef DEBUG
bool post_syscall;
# endif
#endif
* but we need some indication so we add a custom field.
*/
bool currently_stopped;
bool go_native;
#ifdef LINUX
rseq_entry_state_t rseq_entry_state;
#endif
};
* "global rather than a particular thread"
*/
#define GLOBAL_DCONTEXT ((dcontext_t *)PTR_UINT_MINUS_1)
static INLINE_FORCED priv_mcontext_t *
get_mcontext(dcontext_t *dcontext)
{
if (TEST(SELFPROT_DCONTEXT, dynamo_options.protect_mask))
return &(dcontext->upcontext.separate_upcontext->mcontext);
else
return &(dcontext->upcontext.upcontext.mcontext);
}
* print_modules) have an argument on whether to dump in an xml friendly format
* (for xml diagnostics files). We use these defines for readability. */
enum { DUMP_XML = true, DUMP_NOT_XML = false };
#include <stdarg.h>
int
d_r_snprintf(char *s, size_t max, const char *fmt, ...);
int
d_r_vsnprintf(char *s, size_t max, const char *fmt, va_list ap);
int
d_r_snprintf_wide(wchar_t *s, size_t max, const wchar_t *fmt, ...);
int
d_r_vsnprintf_wide(wchar_t *s, size_t max, const wchar_t *fmt, va_list ap);
#undef snprintf
#define snprintf d_r_snprintf
#undef _snprintf
#define _snprintf d_r_snprintf
#undef vsnprintf
#define vsnprintf d_r_vsnprintf
#define snwprintf d_r_snprintf_wide
#define _snwprintf d_r_snprintf_wide
int
d_r_sscanf(const char *str, const char *format, ...);
int
d_r_vsscanf(const char *str, const char *fmt, va_list ap);
const char *
d_r_parse_int(const char *sp, uint64 *res_out, uint base, uint width, bool is_signed);
ssize_t
utf16_to_utf8_size(const wchar_t *src, size_t max_chars,
size_t *written );
#define sscanf d_r_sscanf
#ifdef UNIX
* prefer to just invoke the d_r_ version explicitly, but on Windows we need the
* regular name to use the ntdll versions. Thus we use macro indirection.
*/
# undef strlen
# define strlen d_r_strlen
# undef strlen
# define strlen d_r_strlen
# undef wcslen
# define wcslen d_r_wcslen
# undef strchr
# define strchr d_r_strchr
# undef strrchr
# define strrchr d_r_strrchr
# undef strncpy
# define strncpy d_r_strncpy
# undef strncat
# define strncat d_r_strncat
# undef memmove
# define memmove d_r_memmove
# undef strcmp
# define strcmp d_r_strcmp
# undef strncmp
# define strncmp d_r_strncmp
# undef memcmp
# define memcmp d_r_memcmp
# undef strstr
# define strstr d_r_strstr
# undef tolower
# define tolower d_r_tolower
# undef strcasecmp
# define strcasecmp d_r_strcasecmp
# undef strtoul
# define strtoul d_r_strtoul
#endif
size_t
strlen(const char *str);
size_t
wcslen(const wchar_t *str);
char *
strchr(const char *str, int c);
char *
strrchr(const char *str, int c);
char *
strncpy(char *dst, const char *src, size_t n);
char *
strncat(char *dest, const char *src, size_t n);
void *
memmove(void *dst, const void *src, size_t n);
int
strcmp(const char *left, const char *right);
int
strncmp(const char *left, const char *right, size_t n);
int
memcmp(const void *left_v, const void *right_v, size_t n);
char *
strstr(const char *haystack, const char *needle);
int
tolower(int c);
int
strcasecmp(const char *left, const char *right);
unsigned long
strtoul(const char *str, char **end, int base);
#ifdef WINDOWS
# define strcasecmp _stricmp
# define strncasecmp _strnicmp
# define wcscasecmp _wcsicmp
#endif
#if !defined(NOT_DYNAMORIO_CORE_PROPER) && !defined(NOT_DYNAMORIO_CORE)
# undef printf
# define printf printf_forbidden_function
# undef sprintf
# define sprintf sprintf_forbidden_function
# define swprintf swprintf_forbidden_function
# undef vsprintf
# define vsprintf vsprintf_forbidden_function
# define mprotect mprotect_forbidden_function
# define mmap mmap_forbidden_function
# define munmap munmap_forbidden_function
# define getppid getppid_forbidden_function
# define sched_yield sched_yield_forbidden_function
# define dup dup_forbidden_function
# define sigaltstack sigaltstack_forbidden_function
# define setitimer setitimer_forbidden_function
# define _exit _exit_forbidden_function
# if !(defined(MACOS) && defined(AARCH64))
# define gettimeofday gettimeofday_forbidden_function
# endif
# define time time_forbidden_function
# define modify_ldt modify_ldt_forbidden_function
#endif
#endif