blob: 29e6ca772f736e98d6cd13426b95b9aa09faea86 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011-2014 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.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2000-2001 Hewlett-Packard Company */
/*
* globals.h - global defines and typedefs, included in all files
*/
#ifndef _GLOBALS_H_
#define _GLOBALS_H_ 1
#include "configure.h"
#ifdef WINDOWS
/* Vista SDK compiler default is to set NTDDI_VERSION to NTDDI_LONGHORN, causing
* 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 /* ==0x0400; NTDDI_VERSION is set from this */
# define WIN32_LEAN_AND_MEAN
/* Exclude rarely-used stuff from Windows headers */
/* Case 1167 - bumping up warning level to 4 - work in progress FIXME: */
#pragma warning( disable : 4054) //from function pointer 'void (__cdecl *)(void )' to data pointer 'unsigned char *'
#pragma warning( disable : 4100) //'envp' : unreferenced formal parameter
#pragma warning( disable : 4127) //conditional expression is constant (majority of warnings - 2078)
#pragma warning( disable : 4189) //'start_pc' : local variable is initialized but not referenced
#pragma warning( disable : 4204) //nonstandard extension used : non-constant aggregate initializer
#pragma warning( disable : 4210) //nonstandard extension used : function given file scope
#pragma warning( disable : 4505) //unreferenced local function has been removed
#pragma warning( disable : 4702) //unreachable code (should be disabled DEBUG=0, e.g. for INTERNAL_OPTION test)
#pragma warning( disable : 4324) // structure was padded due to __declspec(align())
#pragma warning( disable : 4709) // comma operator within array index expression
#pragma warning( disable : 4214) // nonstandard extension used : bit field types other than int
/**************************************************/
/* warnings on compiling with VC 8.0, all on VC or PlatformSDK header files */
/* shows up in buildtools/VC/8.0/dist/VC/include/vadefs.h
* supposed to include identifier in the pop pragma and they don't
*/
#pragma warning( disable : 4159) // #pragma pack has popped previously pushed identifier
/* FIXME case 191729: this is coming from our own code. We could
* switch to the _s versions when on Windows.
*/
#pragma warning( disable : 4996) //'sscanf' was declared deprecated
/**************************************************/
#endif
#include "globals_shared.h"
/* currently we always export statistics structure */
#define DYNAMORIO_STATS_EXPORTS 1
/* we only export IR interface if CLIENT_INTERFACE is defined */
#ifdef CLIENT_INTERFACE
/* in Makefile, we define these (so that genapi.pl, etc. get them):
* define DYNAMORIO_IR_EXPORTS 1
* define CUSTOM_EXIT_STUBS 1
* define CUSTOM_TRACES 1
* CUSTOM_TRACES_RET_REMOVAL is aggressive -- assumes calling convention kept
* Only useful if custom traces are doing inlining => do not define for external
* release, or even by default for internal since it's always on even if
* not building custom traces!
*/
#endif /* CLIENT_INTERFACE */
# ifdef WINDOWS
# define DYNAMORIO_EXPORT __declspec(dllexport)
# elif defined(USE_VISIBILITY_ATTRIBUTES)
/* PR 262804: we use "protected" instead of "default" to ensure our
* 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
/* visibility attribute not available in gcc < 3.3 (we use linker script) */
# define DYNAMORIO_EXPORT
# endif
#ifdef DYNAMORIO_IR_EXPORTS
# define DR_API DYNAMORIO_EXPORT
#else
# define DR_API
#endif
#ifdef UNSUPPORTED_API
# define DR_UNS_API DR_API
#else
# define DR_UNS_API /* nothing */
#endif
#ifdef WINDOWS
# define NOINLINE __declspec(noinline)
#else
# define NOINLINE __attribute__((noinline))
#endif
#define INLINE_ONCE inline
#include <stdlib.h>
#include <stdio.h>
/* N.B.: some of these typedefs and defines are duplicated in
* lib/globals_shared.h!
*/
#ifdef WINDOWS
#include <windows.h>
typedef unsigned long ulong;
typedef unsigned short ushort;
/* We can't put this in globals_shared.h b/c it needs windows.h and
* 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)
*/
/* 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;
#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 /* UNIX */
/* uint, ushort, and ulong are in types.h */
# ifdef MACOS
typedef unsigned long ulong;
# endif
#include <sys/types.h> /* for wait */
#define DIRSEP '/'
#define ALT_DIRSEP DIRSEP
#endif
/* FIXME: what is range of thread_id_t on linux and on win32?
* 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; /* fragment cache pc */
#define SUCCESS 0
#define FAILURE 1
/* macros to make conditional compilation look prettier */
#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
/* make sure defines are consistent */
#if !defined(X86) && !defined(ARM)
# error Must define X86 or ARM, no other platforms are supported
#endif
#if defined(PAPI) && defined(WINDOWS)
# error PAPI does not work on WINDOWS
#endif
#if defined(DCONTEXT_IN_EDI) && !defined(STEAL_REGISTER)
# error Must steal register to keep dcontext in edi
#endif
#if defined(SIDELINE_COUNT_STUDY)
# if !defined(PROFILE_LINKCOUNT) || !defined(SIDELINE)
# error SIDELINE_COUNT_STUDY requires PROFILE_LINKCOUNT and defined(SIDELINE)
# endif
#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
/* in buildmark.c */
extern const char dynamorio_version_string[];
extern const char dynamorio_buildmark[];
struct _opnd_t;
typedef struct _opnd_t opnd_t;
struct _instr_t;
typedef struct _instr_t instr_t;
struct _instr_list_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;
/* DR_API EXPORT TOFILE dr_defines.h */
/* DR_API EXPORT BEGIN */
typedef struct _instr_list_t instrlist_t;
typedef struct _module_data_t module_data_t;
/* DR_API EXPORT END */
/* DR_API EXPORT BEGIN */
#ifdef X64
/**
* Upper note values are reserved for core DR.
*/
# define DR_NOTE_FIRST_RESERVED 0xfffffffffffffff0ULL
#else
/**
* Upper note values are reserved for core DR.
*/
# define DR_NOTE_FIRST_RESERVED 0xfffffff0UL
#endif
#define DR_NOTE_ANNOTATION (DR_NOTE_FIRST_RESERVED + 1)
/**
* 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;
/* DR_API EXPORT END */
#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; /* thread id */
#ifdef WINDOWS
HANDLE handle; /* win32 thread handle */
bool retakeover;
#else
process_id_t pid; /* thread group id */
bool execve; /* exiting due to execve (i#237/PR 498284) */
#endif
uint num; /* creation ordinal */
bool under_dynamo_control; /* used for deciding whether to intercept events */
dcontext_t *dcontext; /* allows other threads to see this thread's context */
struct _thread_record_t * next;
} thread_record_t;
/* we don't include dr_api.h, that's for external use, we only need _app
* (everything in dr_defines.h is duplicated in our own header files)
*/
#ifdef DR_APP_EXPORTS
/* we only export app interface if DR_APP_EXPORTS is defined */
# include "dr_app.h"
/* a few always-exported routines are part of the app interface */
# undef DYNAMORIO_EXPORT
# define DYNAMORIO_EXPORT DR_APP_API
#endif
#ifdef PROFILE_LINKCOUNT
#ifndef LINKCOUNT_64_BITS
typedef uint linkcount_type_t;
#else
typedef uint64 linkcount_type_t;
#endif
#endif
#include "heap.h"
#include "utils.h"
#include "options.h"
#include "os_exports.h"
#include "arch_exports.h"
#include "vmareas.h"
#include "instrlist.h"
#include "dispatch.h"
#include "dr_stats.h"
#ifdef CLIENT_INTERFACE
/* did the client request a premature exit at a potentially awkward spot
* (nudge handler, signal handler)?
*/
extern bool client_requested_exit;
typedef struct _client_to_do_list_t {
/* used to make a list of fragments to delete/replace */
/* deletes frag at tag if ilist is null else replaces it with ilist */
instrlist_t *ilist;
app_pc tag;
struct _client_to_do_list_t *next;
} client_todo_list_t;
/* Clients need a separate list to queue up flush requests from dr_flush() */
typedef struct _client_flush_req_t {
app_pc start;
size_t size;
uint flush_id; /* client supplied identifier for this flush */
void (*flush_callback)(int);
struct _client_flush_req_t *next;
} client_flush_req_t;
/* for -thin_client we don't allocate client_data currently, also client_data could be
* 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)
/* Client interface-specific data for dcontexts */
typedef struct _client_data_t {
/* field for use by user via exported API */
void * user_field;
client_todo_list_t * to_do;
client_flush_req_t *flush_list;
# ifdef CLIENT_SIDELINE
mutex_t sideline_mutex;
# endif
/* fields for doing release and debug build checks against erroneous API usage */
module_data_t *no_delete_mod_data;
/* Client-owned threads, such as a client nudge thread, require special
* 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; /* NOTE - use IS_CLIENT_THREAD() */
bool client_thread_safe_for_synch;
/* i#1420: we add a field to indicate if we are in a safe syscall spot
* for THREAD_SYNCH_TERMINATED_AND_CLEANED.
*/
bool at_safe_to_terminate_syscall;
bool suspendable; /* suspend w/ synchall: PR 609569 */
bool left_unsuspended; /* not suspended by synchall: PR 609569 */
uint mutex_count; /* mutex nesting: for PR 558463 */
void *client_grab_mutex;
# ifdef DEBUG
bool is_translating;
# endif
/* flags for asserts on linux and for getting param base right on windows */
bool in_pre_syscall;
bool in_post_syscall;
/* flag for dr_syscall_invoke_another() */
bool invoke_another_syscall;
/* flags for dr_get_mcontext (i#117/PR 395156) */
bool mcontext_in_dcontext;
bool suspended;
priv_mcontext_t *cur_mc;
} client_data_t;
#else
# define IS_CLIENT_THREAD(dcontext) false
#endif /* CLIENT_INTERFACE */
#ifdef UNIX
/* i#61/PR 211530: nudges on Linux do not use separate threads */
typedef struct _pending_nudge_t {
nudge_arg_t arg;
struct _pending_nudge_t *next;
} pending_nudge_t;
#endif
/* size of each Dynamo thread-private stack */
#define DYNAMORIO_STACK_SIZE dynamo_options.stack_size
/* global flags */
extern bool automatic_startup; /* ignore start/stop api, run entire program */
extern bool control_all_threads; /* ok for "weird" things to happen -- not all
threads are under our control */
extern bool dynamo_heap_initialized; /* has dynamo_heap been initialized? */
extern bool dynamo_initialized; /* has dynamo been initialized? */
extern bool dynamo_exited; /* has dynamo exited? */
extern bool dynamo_exited_and_cleaned; /* has dynamo component cleanup started? */
#ifdef DEBUG
extern bool dynamo_exited_log_and_stats; /* are stats and logfile shut down? */
#endif
extern bool dynamo_resetting; /* in middle of global reset? */
extern bool dynamo_all_threads_synched; /* are all other threads suspended safely? */
#if defined(CLIENT_INTERFACE) || defined(STANDALONE_UNIT_TEST)
extern bool standalone_library; /* used as standalone library */
#else
/* avoid complex ifdefs everywhere */
# define standalone_library false
#endif
#ifdef UNIX
extern bool post_execve; /* have we performed an execve? */
/* i#237/PR 498284: vfork threads that execve need to be separately delay-freed */
extern int num_execve_threads;
#endif
/* global instance of statistics struct */
extern dr_statistics_t *stats;
/* the process-wide logfile */
extern file_t main_logfile;
/* initial stack so we don't have to use app's */
extern byte * initstack;
extern mutex_t initstack_mutex;
extern byte * initstack_app_xsp;
#if defined(WINDOWS) && defined(STACK_GUARD_PAGE)
/* PR203701: separate stack for error reporting when the dstack is exhausted */
extern byte * exception_stack;
#endif
/* keeps track of how many threads are in cleanup_and_terminate so that we know
* if any threads could still be using shared resources even if they aren't on
* the all_threads list */
extern int exiting_thread_count;
/* Called before a second thread is ever scheduled. */
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
#ifdef DR_APP_EXPORTS
/* flags to indicate when DR is being initialized / exited using the API */
extern bool dr_api_entry;
extern bool dr_api_exit;
#endif
/* in dynamo.c */
/* 9-bit addressed hash table takes up 2K, has capacity of 512
* we never resize, assuming won't be seeing more than a few hundred threads
*/
#define ALL_THREADS_HASH_BITS 9
extern thread_record_t **all_threads;
extern mutex_t all_threads_lock;
DYNAMORIO_EXPORT int dynamorio_app_init(void);
int dynamorio_app_exit(void);
#if defined(CLIENT_INTERFACE) || defined(STANDALONE_UNIT_TEST)
dcontext_t * standalone_init(void);
void standalone_exit(void);
#endif
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 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
_IF_CLIENT_INTERFACE(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);
/* used for synch to prevent thread creation/deletion in critical periods */
extern mutex_t thread_initexit_lock;
dcontext_t * create_new_dynamo_context(bool initial, byte *dstack_in);
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);
/* functions needed by detach */
int dynamo_shared_exit(IF_WINDOWS_(thread_record_t *toexit)
IF_WINDOWS_ELSE_NP(bool detach_stacked_callbacks, void));
/* perform exit tasks that require full thread data structs */
void dynamo_process_exit_with_thread_info(void);
/* thread cleanup prior to clean exit event */
void dynamo_thread_exit_pre_client(dcontext_t *dcontext, thread_id_t id);
/* enter/exit DR hooks */
void entering_dynamorio(void);
void exiting_dynamorio(void);
void handle_system_call(dcontext_t *dcontext);
/* self-protection */
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 /* DEBUG */
/* all the locks used to protect shared data structures during multi-operation
* 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;
/* where the current app thread's control is */
typedef enum {
WHERE_APP=0,
WHERE_INTERP,
WHERE_DISPATCH,
WHERE_MONITOR,
WHERE_SYSCALL_HANDLER,
WHERE_SIGNAL_HANDLER,
WHERE_TRAMPOLINE,
WHERE_CONTEXT_SWITCH,
WHERE_IBL,
WHERE_FCACHE,
WHERE_UNKNOWN,
#ifdef HOT_PATCHING_INTERFACE
WHERE_HOTPATCH,
#endif
WHERE_LAST
} where_am_i_t;
/* make args easier to read for protection change calls
* since only two possibilities not using new type
*/
enum {
READONLY=false,
WRITABLE=true
};
/* Values for unprotected_context_t.exit_reason, stored in a ushort. */
enum {
/* Default. All other reasons must clear after setting. */
EXIT_REASON_SELFMOD = 0,
/* Floating-point state PC needs updating (i#698). */
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,
/* Additional types of system call gateways. */
EXIT_REASON_NI_SYSCALL_INT_0x81,
EXIT_REASON_NI_SYSCALL_INT_0x82,
};
/* Number of nested calls into native modules that we support. This number
* 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;
/* To handle TRY/EXCEPT/FINALLY setjmp */
typedef struct try_except_context_t {
/* FIXME: we are using a local dr_jmp_buf which is relatively
* small so minimal risk of dstack pressure. Alternatively, we
* can disallow nesting and have a single buffer per dcontext.
*/
/* N.B.: offsetof(try_except_context_t, context) is hardcoded in x86.asm */
dr_jmp_buf_t context;
struct try_except_context_t *prev_context;
} try_except_context_t;
/* We do support TRY pre-dynamo_initialized via this global struct.
* 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; /* for TRY/EXCEPT/FINALLY */
bool unwinding_exception; /* NYI support for TRY/FINALLY -
* marks exception until an EXCEPT handles */
} try_except_t;
extern try_except_t global_try_except;
typedef struct {
/* WARNING: if you change the offsets of any of these fields,
* you must also change the offsets in <arch>/<arch.s>
*/
priv_mcontext_t mcontext; /* real machine context (in arch_exports.h) */
#ifdef UNIX
int errno; /* errno used for DR (no longer used for app) */
#endif
bool at_syscall; /* for shared deletion syscalls_synch_flush,
* as well as syscalls handled from dispatch,
* and for reset to identify when at syscalls
*/
ushort exit_reason; /* Allows multiplexing LINK_SPECIAL_EXIT */
/* Above fields are padded to 8 bytes on all archs except Win x86-32. */
#ifdef CLIENT_INTERFACE
/* Spill slots for inlined clean calls. */
reg_t inline_spill_slots[CLEANCALL_NUM_INLINE_SLOTS];
#endif
} unprotected_context_t;
/* dynamo-specific context associated with each active app thread
* 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 {
/* NOTE: For any field to survive across callback stack switches it must either
* be indirected through a modular field or explicitly copied in
* create_callback_dcontext() (like the modular fields are).
*/
/* WARNING: if you change the offsets of any of these fields, up through
* ignore_enterexit, you must also change the offsets in <arch>/<arch.s>
*/
/* if SELFPROT_DCONTEXT, must split dcontext into unprotected and
* 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 {
/* we use separate_upcontext if
* (TEST(SELFPROT_DCONTEXT, dynamo_options.protect_mask))
* else we use the inlined upcontext
*/
unprotected_context_t *separate_upcontext;
unprotected_context_t upcontext;
} upcontext;
/* HACK for x86.asm lack of runtime param access: this is either
* a self-ptr (to inlined upcontext) or if we separate upcontext it points there.
*/
unprotected_context_t *upcontext_ptr;
/* The next application pc to execute.
* 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; /* last exit from cache */
byte * dstack; /* thread-private dynamo stack */
bool is_exiting; /* flag for exiting thread */
#ifdef WINDOWS
# ifdef CLIENT_INTERFACE
/* i#249: TEB field isolation */
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;
# ifdef X64
void * app_stack_limit;
# endif
/* we need this to restore ptrs for other threads on detach */
byte * teb_base;
# endif
/* storage for an extra app value around sysenter system calls for the
* case 5441 Sygate interoperability hack */
/* FIXME - this needs to be moved into the upcontext as is written to
* in cache by ignore/shared_syscall, ramifications? */
app_pc sysenter_storage;
/* used to avoid enter/exit hooks for certain system calls (see case 4942) */
bool ignore_enterexit;
#endif
/* Coarse-grain cache exits require extra state storage as they do not
* use per-exit separate data structures
*/
union {
/* Indirect branches store on exit the source tag (with the type of
* branch coming from fake linkstubs), while direct store the source unit
*/
app_pc src_tag;
coarse_info_t *dir_exit;
} coarse_exit;
/************* end of offset-crucial fields *********************/
/* FIXME: now that we initialize a new thread's dcontext right away, and
* a new callback's as well, we should be able to get rid of this
*/
bool initialized; /* has this context been used yet? */
thread_id_t owning_thread;
#ifdef UNIX
process_id_t owning_process; /* handle shared address space w/o shared pid */
#endif
#ifdef MACOS
uint thread_port; /* mach_port_t */
#endif
thread_record_t *thread_record; /* so don't have to do a thread_lookup */
where_am_i_t whereami; /* where control is at the moment */
void * allocated_start; /* used for cache alignment */
fragment_t * last_fragment; /* cached value of linkstub_fragment(last_exit) */
int sys_num; /* holds normalized syscall number */
#ifdef WINDOWS
reg_t * sys_param_base; /* used for post_system_call */
#endif
#if defined(UNIX) || defined(X64)
reg_t sys_param0; /* used for post_system_call */
reg_t sys_param1; /* used for post_system_call */
reg_t sys_param2; /* used for post_system_call */
reg_t sys_param3; /* used for post_system_call */
#endif
#ifdef UNIX
reg_t sys_param4; /* used for post_system_call i#173 */
bool sys_was_int; /* was the last system call via do_int_syscall? */
bool sys_xbp; /* PR 313715: store orig xbp */
# ifdef DEBUG
bool mprot_multi_areas; /* PR 410921: mprotect of 2 or more vmareas? */
# endif
#endif
#ifdef MACOS
reg_t app_xdx; /* stores orig xdx during sysenter */
#endif
/* Holds the ISA mode of the thread.
* 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;
/* to make things more modular these are void*: */
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;
bool signals_pending;
#endif
void * private_code; /* various thread-private routines */
#ifdef TRACE_HEAD_CACHE_INCR
cache_pc trace_head_pc; /* HACK to jmp to trace head w/o a prefix */
#endif
#ifdef WINDOWS
/* these fields used for "stack" of contexts for callbacks */
# ifdef DCONTEXT_IN_EDI
dcontext_t *next_saved;
# endif
dcontext_t *prev_unused;
/* need to be able to tell which dcontexts in callback stack are valid */
bool valid;
/* special slot used to deal with callback returns, where we want to
* 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
/* next_tag holds the do_syscall entry point, so we need another
* slot to hold asynch targets for APCs to know next target and
* for NtContinue and sigreturn to set next target
*/
app_pc asynch_target;
/* must store post-intercepted-syscall target to allow using normal
* dispatch() for native_exec syscalls
*/
app_pc native_exec_postsyscall;
/* Stack of app return addresses and stack locations of callsites where we
* 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; /* to implement executable_if_alloc policy */
#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;
/* HACK to avoid recursion on pclookup for target invoking disassembly
* during decode_fragment() for a coarse target
*/
bool in_opnd_disassemble;
#endif /* DEBUG */
#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; /* records start time for profiling */
fragment_t * prev_fragment;
/* top ten times spent in cache */
uint64 cache_frag_count; /* num frag execs in single cache period */
uint64 cache_time[10]; /* top ten times spent in cache */
uint64 cache_count[10]; /* top ten cache_frag_counts */
#endif
#ifdef CLIENT_INTERFACE
/* client interface-specific data */
client_data_t *client_data;
#endif
/* FIXME trace_sysenter_exit is used to capture an exit from a trace that
* 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;
/* DR sets this field to indicate that it's forging an exception that
* may appear to originate in DR but should be passed on to the app. */
app_pc forged_exception_addr;
#ifdef HOT_PATCHING_INTERFACE
/* Fix for case 5367. */
bool nudge_thread; /* True only if this is a nudge thread. */
dr_jmp_buf_t hotp_excpt_state; /* To handle hot patch exceptions. */
#endif
try_except_t try_except; /* for TRY/EXCEPT/FINALLY */
#ifdef WINDOWS
/* for ASLR_SHARED_CONTENT, note per callback, not per thread to
* 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;
/* Initially memset to 0 in create dcontext. If this is a nudge (or
* 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;
/* If free_app_stack is set, we free the application stack during thread exit
* cleanup. Used for nudge threads. */
bool free_app_stack;
/* used when a nudge invokes dr_exit_process() */
bool nudge_terminate_process;
uint nudge_exit_code;
#endif /* WINDOWS */
/* we keep an absolute address pointer to our tls state so that we
* can access it from other threads
*/
local_state_t *local_state;
#ifdef WINDOWS
/* case 8721: saving the win32 start address so we can print it in the
* 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
/* Used to abort bb building on decode faults. Not persistent across cache. */
void *bb_build_info;
#ifdef UNIX
pending_nudge_t *nudge_pending;
/* frag we unlinked to expedite nudge delivery */
fragment_t *interrupted_for_nudge;
# ifdef DEBUG
/* i#238/PR 499179: check that libc errno hasn't changed */
int libc_errno;
# endif
#else
# ifdef DEBUG
bool post_syscall;
# endif
#endif
/* The start/stop APi doesn't change thread_record_t.under_dynamo_control,
* but we need some indication so we add a custom field.
*/
bool currently_stopped;
};
/* sentinel value for dcontext_t* used to indicate
* "global rather than a particular thread"
*/
#define GLOBAL_DCONTEXT ((dcontext_t *)PTR_UINT_MINUS_1)
/* FIXME: why do we need to force the inline for this simple function? */
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);
}
/* A number of routines (dump_mbi*, dump_mcontext, dump_callstack,
* 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
};
/* io.c */
/* to avoid transparency problems we must have our own vnsprintf and sscanf */
#include <stdarg.h> /* for va_list */
int our_snprintf(char *s, size_t max, const char *fmt, ...);
int our_vsnprintf(char *s, size_t max, const char *fmt, va_list ap);
int our_snprintf_wide(wchar_t *s, size_t max, const wchar_t *fmt, ...);
int our_vsnprintf_wide(wchar_t *s, size_t max, const wchar_t *fmt, va_list ap);
#undef snprintf /* defined on macos */
#define snprintf our_snprintf
#undef _snprintf
#define _snprintf our_snprintf
#undef vsnprintf
#define vsnprintf our_vsnprintf
#define snwprintf our_snprintf_wide
#define _snwprintf our_snprintf_wide
int our_sscanf(const char *str, const char *format, ...);
int our_vsscanf(const char *str, const char *fmt, va_list ap);
const char * 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/*unicode chars*/);
#define sscanf our_sscanf
/* string.c */
int tolower(int c);
/* Code cleanliness rules */
#ifdef WINDOWS
# define strcasecmp _stricmp
# define strncasecmp _strnicmp
# define wcscasecmp _wcsicmp
#endif
#if !defined(NOT_DYNAMORIO_CORE_PROPER) && !defined(NOT_DYNAMORIO_CORE)
# define printf printf_forbidden_function
# undef sprintf /* defined on macos */
# define sprintf sprintf_forbidden_function
# define swprintf swprintf_forbidden_function
# undef vsprintf /* defined on macos */
# define vsprintf vsprintf_forbidden_function
# define __try __try_forbidden_construct /* see case 4461 */
/* libc independence */
# 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
# define gettimeofday gettimeofday_forbidden_function
# define time time_forbidden_function
# define modify_ldt modify_ldt_forbidden_function
#endif
#endif /* _GLOBALS_H_ */