* 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.
*/
* os_exports.h - UNIX-specific exported declarations
*/
#ifndef _OS_EXPORTS_H_
#define _OS_EXPORTS_H_ 1
#include <stdarg.h>
#include "../os_shared.h"
#include "os_public.h"
* We thus directly include opnd.h here for reg_id_t to resolve the circular
* dependence (cleaner than having to use ushort instead of reg_id_t).
*/
#include "../ir/opnd.h"
#ifndef NOT_DYNAMORIO_CORE_PROPER
# define getpid getpid_forbidden_use_get_process_id
#endif
#ifdef MACOS
# define DYNAMORIO_PRELOAD_NAME "libdrpreload.dylib"
#else
# define DYNAMORIO_PRELOAD_NAME "libdrpreload.so"
#endif
#define OS_ALLOC_GRANULARITY (4 * 1024)
#define MAP_FILE_VIEW_ALIGNMENT (4 * 1024)
* uses gs) and gs for x64 (where pthreads uses fs) (presumably to
* avoid conflicts w/ wine).
* Keep this consistent w/ the TLS_SEG_OPCODE define in ir/instr.h
* and TLS_SEG in arch/asm_defines.asm
*
* PR 205276 covers transparently stealing our segment selector.
*/
#ifdef X86
# if defined(MACOS64)
# define SEG_TLS SEG_GS
# define LIB_SEG_TLS SEG_GS
# define STR_SEG "gs"
# define STR_LIB_SEG "gs"
# elif defined(X64)
# define SEG_TLS SEG_GS
# define ASM_SEG "%gs"
# define LIB_SEG_TLS SEG_FS
# define LIB_ASM_SEG "%fs"
# define STR_SEG "gs"
# define STR_LIB_SEG "fs"
# else
# define SEG_TLS SEG_FS
# define ASM_SEG "%fs"
# define LIB_SEG_TLS SEG_GS
# define LIB_ASM_SEG "%gs"
# define STR_SEG "fs"
# define STR_LIB_SEG "gs"
# endif
#elif defined(AARCHXX)
* end up having to steal the app library TPID register for priv lib use.
* When in DR state, we steal a field inside the priv lib TLS to store the DR base.
* When in app state in the code cache, we steal a GPR (r10 by default) to store
* the DR base.
*/
# ifdef X64
# ifdef MACOS
# define SEG_TLS DR_REG_TPIDR_EL0
# define LIB_SEG_TLS DR_REG_TPIDRRO_EL0
# define STR_SEG "tpidrurw"
# define STR_LIB_SEG "tpidruro"
# else
# define SEG_TLS DR_REG_TPIDRRO_EL0
# define LIB_SEG_TLS DR_REG_TPIDR_EL0
# define STR_SEG "tpidruro"
# define STR_LIB_SEG "tpidrurw"
# endif
# else
# define SEG_TLS \
DR_REG_TPIDRURW
*/
# define LIB_SEG_TLS DR_REG_TPIDRURO
# define STR_SEG "tpidrurw"
# define STR_LIB_SEG "tpidruro"
# endif
#elif defined(RISCV64)
# define SEG_TLS DR_REG_INVALID
# define LIB_SEG_TLS DR_REG_TP
# define STR_SEG "<none>"
# define STR_LIB_SEG "tp"
#endif
#define TLS_REG_LIB LIB_SEG_TLS
#define TLS_REG_ALT SEG_TLS
#ifdef X86
# define DR_REG_SYSNUM REG_EAX
#elif defined(ARM)
# define DR_REG_SYSNUM DR_REG_R7
#elif defined(AARCH64)
# define DR_REG_SYSNUM DR_REG_X8
#elif defined(RISCV64)
# define DR_REG_SYSNUM DR_REG_A7
#else
# error NYI
#endif
#ifdef MACOS64
* provide a dynamic method to determine the first entry for forward compatability.
* Starting w/ libpthread-218.1.3 they now leave slots 6 and 11 unused to allow
* limited interoperability w/ code targeting the Windows x64 ABI. We steal slot 6
* for our own use.
*/
# define SEG_TLS_BASE_SLOT 28
# define DR_TLS_BASE_SLOT 6
# define DR_TLS_BASE_OFFSET (sizeof(void *) * (SEG_TLS_BASE_SLOT + DR_TLS_BASE_SLOT))
#endif
#if defined(AARCHXX) && !defined(MACOS64)
# ifdef ANDROID
* pthread_internal_t. However, its offset varies by Android version, requiring
* indirection through a variable.
*/
# ifdef AARCH64
# error NYI
# else
extern uint android_tls_base_offs;
# define DR_TLS_BASE_OFFSET android_tls_base_offs
# endif
# else
* On ARM, we use the 'private' field of the tcbhead_t to store DR TLS base,
* as we can't use the alternate TLS register b/c the kernel doesn't preserve it.
* typedef struct
* {
* dtv_t *dtv;
* void *private;
* } tcb_head_t;
* When using the private loader, we control all the TLS allocation and
* should be able to avoid using that field.
* This is also used in asm code, so we use literal instead of sizeof.
*/
# define DR_TLS_BASE_OFFSET IF_X64_ELSE(8, 4)
# endif
* mrc p15, 0, reg_app, c13, c0, 3
*/
# define USR_TLS_REG_OPCODE 3
# define USR_TLS_COPROC_15 15
#endif
#ifdef RISCV64
* with the only difference being tp register points at the end of TCB.
*
* typedef struct
* {
* dtv_t *dtv;
* void *private;
* } tcb_head_t;
*/
# define DR_TLS_BASE_OFFSET IF_X64_ELSE(-8, -4)
#endif
#ifdef LINUX
# include "include/clone3.h"
#endif
void *
d_r_get_tls(ushort tls_offs);
void
d_r_set_tls(ushort tls_offs, void *value);
byte *
os_get_dr_tls_base(dcontext_t *dcontext);
void
os_file_init(void);
void
os_fork_init(dcontext_t *dcontext);
void
os_thread_stack_store(dcontext_t *dcontext);
app_pc
get_dynamorio_dll_end(void);
thread_id_t
get_tls_thread_id(void);
thread_id_t
get_sys_thread_id(void);
bool
is_thread_terminated(dcontext_t *dcontext);
void
os_wait_thread_terminated(dcontext_t *dcontext);
void
os_wait_thread_detached(dcontext_t *dcontext);
void
os_signal_thread_detach(dcontext_t *dcontext);
void
os_tls_pre_init(int gdt_index);
ushort
os_get_app_tls_base_offset(reg_id_t seg);
ushort
os_get_app_tls_reg_offset(reg_id_t seg);
void *
os_get_app_tls_base(dcontext_t *dcontext, reg_id_t seg);
#ifdef DEBUG
void
os_enter_dynamorio(void);
#endif
* our own syscall wrappers.
*/
int
open_syscall(const char *file, int flags, int mode);
int
close_syscall(int fd);
int
dup_syscall(int fd);
ssize_t
read_syscall(int fd, void *buf, size_t nbytes);
ssize_t
write_syscall(int fd, const void *buf, size_t nbytes);
void
exit_process_syscall(long status);
void
exit_thread_syscall(long status);
process_id_t
get_parent_id(void);
* we have libc independence or our own private isolated libc we need
* to preserve the app's libc's errno
*/
int
get_libc_errno(void);
void
set_libc_errno(int val);
#ifdef STATIC_LIBRARY
* after our constructor ran: thus we do not want to cache the environ pointer.
*/
extern char **environ;
# define our_environ environ
#else
extern char **our_environ;
#endif
bool
is_our_environ_followed_by_auxv(void);
void
dynamorio_set_envp(char **envp);
#if !defined(NOT_DYNAMORIO_CORE_PROPER) && !defined(NOT_DYNAMORIO_CORE)
# define getenv our_getenv
#endif
char *
our_getenv(const char *name);
#define unsetenv our_unsetenv
* Use disable_env instead. Xref i#909.
*/
int
our_unsetenv(const char *name);
bool
disable_env(const char *name);
* name is a string
* wx should contain one of the strings "w", "wx", "x", or ""
*/
* section goes -- for cl, order linked seems to do it, but for linux
* will need a linker script (see unix/os.c for the nspdata problem)
*/
* protection per-page (currently only on Windows). Hard-coded 4K alignment will
* lead to issues on systems with larger base pages.
*/
#ifdef MACOS
# define DECLARE_DATA_SECTION(name, wx) \
asm(".section __DATA," name); \
asm(".align 12");
#else
# ifdef DR_HOST_X86
# define DECLARE_DATA_SECTION(name, wx) \
asm(".section " name ", \"a" wx "\", @progbits"); \
asm(".align 0x1000");
# elif defined(DR_HOST_AARCHXX)
# define DECLARE_DATA_SECTION(name, wx) \
asm(".section " name ", \"a" wx "\""); \
asm(".align 12");
# elif defined(DR_HOST_RISCV64)
# define DECLARE_DATA_SECTION(name, wx) \
asm(".section " name ", \"a" wx "\""); \
asm(".align 12");
# endif
#endif
* declarations. gcc 4.3 seems to switch back to text at the start of every
* function, while gcc >= 4.6 seems to emit all code together without extra
* section switches. Since earlier versions of gcc do their own switching and
* the latest versions expect .text, we choose to switch to the text section.
*/
#ifdef MACOS
# define END_DATA_SECTION_DECLARATIONS() \
asm(".section __DATA,.data"); \
asm(".align 12"); \
asm(".text");
#else
# ifdef DR_HOST_X86
# define END_DATA_SECTION_DECLARATIONS() \
asm(".section .data"); \
asm(".align 0x1000"); \
asm(".text");
# elif defined(DR_HOST_AARCHXX)
# define END_DATA_SECTION_DECLARATIONS() \
asm(".section .data"); \
asm(".align 12"); \
asm(".text");
# elif defined(DR_HOST_RISCV64)
# define END_DATA_SECTION_DECLARATIONS() \
asm(".section .data"); \
asm(".align 12"); \
asm(".text");
# endif
#endif
#define START_DATA_SECTION(name, wx)
#define END_DATA_SECTION()
* but for gcc we need to explicitly declare which section. We still need
* the .section asm above to give section attributes and alignment.
*/
#ifdef MACOS
# define VAR_IN_SECTION(name) __attribute__((section("__DATA," name)))
#else
# define VAR_IN_SECTION(name) __attribute__((section(name)))
#endif
extern app_pc vdso_page_start;
extern size_t vdso_size;
extern app_pc vsyscall_page_start;
extern app_pc vsyscall_syscall_end_pc;
extern app_pc vsyscall_sysenter_return_pc;
extern app_pc vsyscall_sysenter_displaced_pc;
#define VSYSCALL_PAGE_MAPS_NAME "[vdso]"
bool
was_thread_create_syscall(dcontext_t *dcontext);
bool
is_sigreturn_syscall(dcontext_t *dcontext);
bool
was_sigreturn_syscall(dcontext_t *dcontext);
bool
ignorable_system_call(int num, instr_t *gateway, dcontext_t *dcontext_live);
bool
kernel_is_64bit(void);
void
os_handle_mov_seg(dcontext_t *dcontext, byte *pc);
void
init_emulated_brk(app_pc exe_end);
bool
is_DR_segment_reader_entry(app_pc pc);
#define NUM_NONRT 32
#define OFFS_RT 32
#ifdef LINUX
# define NUM_RT 33
#else
# define NUM_RT 0
#endif
#define MAX_SIGNUM ((OFFS_RT) + (NUM_RT)-1)
*/
#define SIGARRAY_SIZE (MAX_SIGNUM + 1)
#ifdef X64
# define _NSIG_BPW 64
#else
# define _NSIG_BPW 32
#endif
#ifdef LINUX
# define _NSIG_WORDS (MAX_SIGNUM / _NSIG_BPW)
#else
# define _NSIG_WORDS 1
#endif
* each (-> 8 bytes vs. 128 bytes)
*/
typedef struct _kernel_sigset_t {
#ifdef LINUX
unsigned long sig[_NSIG_WORDS];
#elif defined(MACOS)
unsigned int sig[_NSIG_WORDS];
#endif
} kernel_sigset_t;
void
receive_pending_signal(dcontext_t *dcontext);
bool
is_signal_restorer_code(byte *pc, size_t *len);
bool
is_currently_on_sigaltstack(dcontext_t *dcontext);
#define CONTEXT_HEAP_SIZE(sc) (sizeof(sc))
#define CONTEXT_HEAP_SIZE_OPAQUE (CONTEXT_HEAP_SIZE(sigcontext_t))
* The storage for the pointed-at structs must be valid across the whole use of
* this container struct, of course, so be careful where it's used.
*/
typedef struct _sig_full_cxt_t {
sigcontext_t *sc;
void *fp_simd_state;
} sig_full_cxt_t;
typedef sig_full_cxt_t os_cxt_ptr_t;
extern os_cxt_ptr_t osc_empty;
static inline bool
is_os_cxt_ptr_null(os_cxt_ptr_t osc)
{
return osc.sc == NULL;
}
static inline void
set_os_cxt_ptr_null(os_cxt_ptr_t *osc)
{
*osc = osc_empty;
}
bool
os_context_to_mcontext(dr_mcontext_t *dmc, priv_mcontext_t *mc, os_cxt_ptr_t osc);
bool
mcontext_to_os_context(os_cxt_ptr_t osc, dr_mcontext_t *dmc, priv_mcontext_t *mc);
void *
#ifdef MACOS
create_clone_record(dcontext_t *dcontext, reg_t *app_thread_xsp, app_pc thread_func,
void *func_arg);
#elif defined(LINUX)
create_clone_record(dcontext_t *dcontext, reg_t *app_thread_xsp,
clone3_syscall_args_t *dr_clone_args,
clone3_syscall_args_t *app_clone_args);
#else
create_clone_record(dcontext_t *dcontext, reg_t *app_thread_xsp);
#endif
#ifdef MACOS
void *
get_clone_record_thread_arg(void *record);
#endif
void *
get_clone_record(reg_t xsp);
reg_t
get_clone_record_app_xsp(void *record);
byte *
get_clone_record_dstack(void *record);
#ifdef AARCHXX
reg_t
get_clone_record_stolen_value(void *record);
# ifndef AARCH64
uint
get_clone_record_isa_mode(void *record);
# endif
void
set_thread_register_from_clone_record(void *record);
void
set_app_lib_tls_base_from_clone_record(dcontext_t *dcontext, void *record);
#endif
void
restore_clone_param_from_clone_record(dcontext_t *dcontext, void *record);
void
os_clone_post(dcontext_t *dcontext);
void
signal_fork_init(dcontext_t *dcontext);
void
signal_remove_alarm_handlers(dcontext_t *dcontext);
bool
set_itimer_callback(dcontext_t *dcontext, int which, uint millisec,
void (*func)(dcontext_t *, priv_mcontext_t *),
void (*func_api)(dcontext_t *, dr_mcontext_t *));
uint
get_itimer_frequency(dcontext_t *dcontext, int which);
bool
sysnum_is_not_restartable(int sysnum);
void
pcprofile_fragment_deleted(dcontext_t *dcontext, fragment_t *f);
void
pcprofile_thread_exit(dcontext_t *dcontext);
void
d_r_stackdump(void);
void
glibc_stackdump(int fd);
bool
send_nudge_signal(process_id_t pid, uint action_mask, client_id_t client_id,
uint64 client_arg);
bool
at_dl_runtime_resolve_ret(dcontext_t *dcontext, app_pc source_fragment, int *ret_imm);
#ifdef LINUX
extern vm_area_vector_t *d_r_rseq_areas;
bool
rseq_get_region_info(app_pc pc, app_pc *start OUT, app_pc *end OUT, app_pc *handler OUT,
bool **reg_written OUT, int *reg_written_size OUT);
bool
rseq_set_final_instr_pc(app_pc start, app_pc final_instr_pc);
int
rseq_get_tls_ptr_offset(void);
int
rseq_get_signature(void);
int
rseq_get_rseq_cs_alignment(void);
byte *
rseq_get_rseq_cs_alloc(byte **rseq_cs_aligned OUT);
void
rseq_record_rseq_cs(byte *rseq_cs_alloc, fragment_t *f, cache_pc start, cache_pc end,
cache_pc abort);
void
rseq_remove_fragment(dcontext_t *dcontext, fragment_t *f);
void
rseq_shared_fragment_flushtime_update(dcontext_t *dcontext);
void
rseq_process_native_abort(dcontext_t *dcontext);
void
rseq_insert_start_label(dcontext_t *dcontext, app_pc tag, instrlist_t *ilist);
#endif
#endif