blob: ac77dbde97ffcfc8cd3cd17381abb9929da48c2f [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011-2014 Google, Inc. All rights reserved.
* Copyright (c) 2005-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) 2005-2007 Determina Corp. */
/*
* os_private.h - declarations shared among os-specific files, but not
* exported to the rest of the code
*/
#ifndef _OS_PRIVATE_H_
#define _OS_PRIVATE_H_ 1
#include "drmarker.h"
/* in os.c *********************************************************/
#define GLOBAL_NT_PREFIX L"\\??\\"
/* FIXME: used for converting Dos to NT paths */
/* thread-local data that's os-private, for modularity and easy sharing across
* callbacks
*/
typedef struct _os_thread_data_t {
/* Store stack info at thread startup since an attack or inadvertent write
* could clobber the teb fields storing this info. Also, on NT and 2k the
* stack is freed in process during kernel32!ExitThread (which uses some
* unused TEB space as the stack to free oringinal stack and exit the
* the thread) so we mark teb_stack_no_longer_valid when we see the free
* (which we watch for). */
byte *stack_base;
byte *stack_top;
bool teb_stack_no_longer_valid;
} os_thread_data_t;
/* pc values delimiting dynamo dll image */
extern app_pc dynamo_dll_start;
extern app_pc dynamo_dll_end;
extern dcontext_t *early_inject_load_helper_dcontext;
/* passed to early injection init by parent */
typedef struct {
byte *dr_base;
byte *ntdll_base;
byte *tofree_base;
byte *hook_location;
bool late_injection;
char dynamorio_lib_path[MAX_PATH];
} earliest_args_t;
/* Max size is x64 ind jmp (6 bytes) + target (8 bytes).
* Simpler to always use the same size, esp wrt cross-arch injection.
* We assume all our early inject target functions are at least
* this size. We restore the hook right away in any case.
*/
#define EARLY_INJECT_HOOK_SIZE 14
bool
is_first_thread_in_new_process(HANDLE process_handle, CONTEXT *cxt);
bool
maybe_inject_into_process(dcontext_t *dcontext, HANDLE process_handle,
CONTEXT *cxt);
bool
translate_context(thread_record_t *trec, CONTEXT *cxt, bool restore_memory);
void
dump_mbi(file_t file, MEMORY_BASIC_INFORMATION *mbi, bool dump_xml);
void
dump_mbi_addr(file_t file, app_pc target, bool dump_xml);
bool
prot_is_writable(uint prot);
bool
prot_is_executable(uint osprot);
uint
get_current_protection(byte *pc);
/* translate platform independent protection bits to native flags */
int
memprot_to_osprot(uint prot);
/* translate native flags to platform independent protection bits */
int
osprot_to_memprot(uint prot);
int
osprot_add_writecopy(uint prot);
int
process_mmap(dcontext_t *dcontext, app_pc pc, size_t size, bool add,
const char *filepath);
void
check_for_ldrpLoadImportModule(byte *base, uint *ebp);
#ifdef CLIENT_SIDELINE
void
client_thread_target(void *param);
#endif
bool os_delete_file_w(const wchar_t *file_name,
file_t directory_handle);
byte *
os_terminate_wow64_stack(HANDLE thread_handle);
void
os_terminate_wow64_write_args(bool exit_process, HANDLE proc_or_thread_handle,
int exit_status);
void
thread_attach_setup(priv_mcontext_t *mc);
void
thread_attach_context_revert(CONTEXT *cxt INOUT);
/* in syscall.c *********************************************************/
/* this points to a windows-version-specific syscall array */
extern int *syscalls;
#define SYSCALL_NOT_PRESENT 0xffffffff
/* this points to a windows-version-specific WOW table index array */
extern int *wow64_index;
#ifdef CLIENT_INTERFACE
/* i#1230: we support the client adding to the end of these, so they are not const
* (but they're still in .data, so they're read-only once past init)
*/
# define SYS_CONST /* in .data */
#else
# define SYS_CONST const
#endif
extern SYS_CONST int windows_81_x64_syscalls[];
extern SYS_CONST int windows_81_wow64_syscalls[];
extern SYS_CONST int windows_81_x86_syscalls[];
extern SYS_CONST int windows_8_x64_syscalls[];
extern SYS_CONST int windows_8_wow64_syscalls[];
extern SYS_CONST int windows_8_x86_syscalls[];
extern SYS_CONST int windows_7_x64_syscalls[];
extern SYS_CONST int windows_7_syscalls[];
extern SYS_CONST int windows_vista_sp1_x64_syscalls[];
extern SYS_CONST int windows_vista_sp1_syscalls[];
extern SYS_CONST int windows_vista_sp0_x64_syscalls[];
extern SYS_CONST int windows_vista_sp0_syscalls[];
extern SYS_CONST int windows_2003_syscalls[];
extern SYS_CONST int windows_XP_x64_syscalls[];
extern SYS_CONST int windows_XP_wow64_index[]; /* for XP through Win7 */
extern SYS_CONST int windows_XP_syscalls[];
extern SYS_CONST int windows_2000_syscalls[];
extern SYS_CONST int windows_NT_sp3_syscalls[];
extern SYS_CONST int windows_NT_sp0_syscalls[];
extern SYS_CONST int windows_NT_sp4_syscalls[];
/* for x64 this is the # of args */
extern SYS_CONST uint syscall_argsz[];
extern const char * SYS_CONST syscall_names[];
extern bool init_apc_go_native_pause;
extern bool init_apc_go_native;
#ifdef DEBUG
void check_syscall_array_sizes(void);
#endif
bool
windows_version_init(void);
enum {
#define SYSCALL(name, act, nargs, arg32, ntsp0, ntsp3, ntsp4, w2k, xp, wow64, xp64,\
w2k3, vista0, vista0_x64, vista1, vista1_x64, w7x86, w7x64, \
w8x86, w8w64, w8x64, w81x86, w81w64, w81x64) \
SYS_##name,
#include "syscallx.h"
#undef SYSCALL
SYS_MAX,
};
/* the offset from edx of the parameters to a system call, our current
* (FIXME - also potentially unreliable, since really is a function of os
* version and processor type) check is by the system entry method,
* if it's int then offset is 0, if it's sysenter or syscall then offset is 8
* will also have it default to 0 since I think 2k uses int regardless of
* proccesor type */
/* FIXME - if we are really paranoid then we should ensure that the offset
* holds the return values the os would expect (i.e. the ntdll wrapper return
* address for XP/2003), also if used before we know the syscall method will
* default to 0! */
#define SYSCALL_PARAM_MAX_OFFSET (2*XSP_SZ) /* offset for real arguments */
#ifdef X64
/* retaddr, then args */
# define SYSCALL_PARAM_OFFSET() (XSP_SZ)
#else
/* as done on WinXP, syscalls have extra slots before real params */
/* edx is 4 less than on 2000, plus there's an extra call to provide
* return address for sysenter, so we have to skip 2 slots:
*/
/* On Win8, wow64 syscalls do not point edx at the params and
* instead simply use esp and thus must skip the retaddr.
*/
# define SYSCALL_PARAM_OFFSET() \
((get_syscall_method() == SYSCALL_METHOD_SYSCALL || \
get_syscall_method() == SYSCALL_METHOD_SYSENTER) \
? SYSCALL_PARAM_MAX_OFFSET : \
((get_syscall_method() == SYSCALL_METHOD_WOW64 && \
!syscall_uses_wow64_index()) ? XSP_SZ : 0))
#endif
static inline reg_t *
sys_param_addr(dcontext_t *dcontext, reg_t *param_base, int num)
{
#ifdef X64
/* we force-inline get_mcontext() and so don't take it as a param */
priv_mcontext_t *mc = get_mcontext(dcontext);
switch (num) {
case 0: return &mc->xcx;
case 1: return &mc->xdx;
case 2: return &mc->r8;
case 3: return &mc->r9;
default: return ((reg_t *)param_base) + num;
}
#else
return ((reg_t *)param_base) + num;
#endif
}
static inline reg_t
sys_param(dcontext_t *dcontext, reg_t *param_base, int num)
{
/* sys_param is also called from handle_system_call where dcontext->whereami
* is not set to WHERE_SYSCALL_HANDLER yet.
*/
ASSERT(!dcontext->post_syscall);
return *sys_param_addr(dcontext, param_base, num);
}
static inline reg_t
postsys_param(dcontext_t *dcontext, reg_t *param_base, int num)
{
ASSERT(dcontext->whereami == WHERE_SYSCALL_HANDLER &&
dcontext->post_syscall);
#ifdef X64
switch (num) {
/* Register params are volatile so we save in dcontext in pre-syscall */
case 0: return dcontext->sys_param0;
case 1: return dcontext->sys_param1;
case 2: return dcontext->sys_param2;
case 3: return dcontext->sys_param3;
default: return *sys_param_addr(dcontext, param_base, num);
}
#else
return *sys_param_addr(dcontext, param_base, num);
#endif
}
void
init_syscall_trampolines(void);
void
exit_syscall_trampolines(void);
bool
os_get_file_size_by_handle(IN HANDLE file_handle,
uint64 *end_of_file);
bool
os_set_file_size(IN HANDLE file_handle,
uint64 end_of_file);
/* use os_rename_file() for cross-platform uses */
bool
os_rename_file_in_directory(IN HANDLE rootdir,
const wchar_t *orig_name,
const wchar_t *new_name,
bool replace);
/* in callback.c ***************************************************/
/* thread-shared only needs 4 pages on 32-bit but -thread_private needs 5
* in case we hook the image entry on an early cbret
*/
#define INTERCEPTION_CODE_SIZE IF_X64_ELSE(8*4096,7*4096)
/* see notes in intercept_new_thread() about these values */
#define THREAD_START_ADDR IF_X64_ELSE(CXT_XCX, CXT_XAX)
#define THREAD_START_ARG IF_X64_ELSE(CXT_XDX, CXT_XBX)
void
callback_init(void);
void
callback_exit(void);
dr_marker_t*
get_drmarker(void);
#define UNDER_DYN_HACK 0xab
#define IS_UNDER_DYN_HACK(val) ((byte)(val) == UNDER_DYN_HACK)
byte *
intercept_syscall_wrapper(byte **ptgt_pc /* IN/OUT */,
intercept_function_t prof_func,
void *callee_arg, after_intercept_action_t action_after,
app_pc *skip_syscall_pc /* OUT */,
byte **orig_bytes_pc /* OUT */,
byte *fpo_stack_adjustment /* OUT OPTIONAL */,
const char *name);
byte *
insert_trampoline(byte *tgt_pc, intercept_function_t prof_func, void *callee_arg,
bool assume_esp, after_intercept_action_t action_after,
bool cti_safe_to_ignore);
void
remove_trampoline(byte *our_pc, byte *tgt_pc);
void
remove_image_entry_trampoline(void);
void
callback_start_return(priv_mcontext_t *mc);
void
intercept_nt_continue(CONTEXT *cxt, int flag);
void
intercept_nt_setcontext(dcontext_t *dcontext, CONTEXT *cxt);
/* methods of taking over */
#define INTERCEPT_POINT(point) point,
#define INTERCEPT_ALL_POINTS \
/* when dr_preinjected=false, not used */ \
INTERCEPT_POINT(INTERCEPT_EXPLICIT_INJECT) \
/* otherwise we are in one of these */ \
INTERCEPT_POINT(INTERCEPT_PREINJECT) \
INTERCEPT_POINT(INTERCEPT_IMAGE_ENTRY) \
INTERCEPT_POINT(INTERCEPT_LOAD_DLL) \
INTERCEPT_POINT(INTERCEPT_UNLOAD_DLL) \
/* asynch prior to image entry */ \
INTERCEPT_POINT(INTERCEPT_EARLY_ASYNCH) \
/* syscall trampoline prior to image entry */ \
INTERCEPT_POINT(INTERCEPT_SYSCALL)
typedef enum {
INTERCEPT_ALL_POINTS
} retakeover_point_t;
#undef INTERCEPT_POINT
void
retakeover_after_native(thread_record_t *tr, retakeover_point_t where);
bool
new_thread_is_waiting_for_dr_init(thread_id_t tid, app_pc pc);
void
context_to_mcontext(priv_mcontext_t *mcontext, CONTEXT* cxt);
void
mcontext_to_context(CONTEXT* cxt, priv_mcontext_t *mcontext, bool set_cur_seg);
#ifdef DEBUG
void dump_context_info(CONTEXT *context, file_t file, bool all);
#endif
/* PR 264138: we need to preserve xmm0-5 for x64 and wow64.
* These flags must be used for any CONTEXT that is being used
* to set a priv_mcontext_t for executing by DR, or if the CONTEXT
* will be passed to nt_set_context() and the thread in question
* will execute DR code in between.
* Although winnt.h mentions CONTEXT_MMX_REGISTERS, there is no such
* constant: they must mean CONTEXT_FLOATING_POINT.
* We allow non-core inject.c to use this by not using
* preserve_xmm_caller_saved() and just ignoring underlying SSE support: so we
* have some duplication of logic, but it's messy to get preserve_xmm_caller_saved()
* into arch_exports.h as NT_CURRENT_PROCESS is not defined yet, and
* non-core modules don't link with proc.c.
* Since this affects only what we request from the kernel, asking
* for floating point w/o underlying sse support is not a problem.
*/
#ifdef CONTEXT_XSTATE
# undef CONTEXT_XSTATE /* defined in VS2008+ */
#endif
/* i#437:
* http://msdn.microsoft.com/en-us/library/windows/desktop/hh134240(v=vs.85).aspx
* Win 7 SP1 is the first version of Windows supporting the AVX API.
* The value for CONTEXT_XSTATE is different between Win 7 and Win 7 SP1.
* A single MACRO is not enough to set the CONTEXT_XSTATE across different
* Windows, so we use a global variable instead and set the value at runtime.
*/
extern uint context_xstate;
#define CONTEXT_XSTATE context_xstate
#define CONTEXT_XMM_FLAG IF_X64_ELSE(CONTEXT_FLOATING_POINT, CONTEXT_EXTENDED_REGISTERS)
#define CONTEXT_YMM_FLAG CONTEXT_XSTATE
#define CONTEXT_PRESERVE_XMM IF_X64_ELSE(true, is_wow64_process(NT_CURRENT_PROCESS))
/* AVX is supported only if both hardware and os support it, and this proc
* check looks at both (i#1278)
*/
#define CONTEXT_PRESERVE_YMM (proc_avx_enabled())
#define CONTEXT_DR_STATE_NO_YMM (CONTEXT_INTEGER | CONTEXT_CONTROL | \
(CONTEXT_PRESERVE_XMM ? CONTEXT_XMM_FLAG : 0U))
#define CONTEXT_DR_STATE (CONTEXT_DR_STATE_NO_YMM | \
(CONTEXT_PRESERVE_YMM ? CONTEXT_YMM_FLAG : 0U))
/* FIXME i#444: including CONTEXT_YMM_FLAG blindly results in STATUS_NOT_SUPPORTED in
* inject_into_thread()'s NtGetContextThread so for now we remove it:
*/
#define CONTEXT_DR_STATE_ALLPROC (CONTEXT_INTEGER | CONTEXT_CONTROL | \
CONTEXT_XMM_FLAG | 0/*CONTEXT_YMM_FLAG: see above*/)
#define XSTATE_HEADER_SIZE 0x40 /* 512 bits */
#define YMMH_AREA(ymmh_area, i) (((dr_xmm_t*)ymmh_area)[i])
#define MAX_CONTEXT_64_SIZE 0x680 /* 0x66f from win-7 sp1 */
#ifdef X64
# define MAX_CONTEXT_SIZE MAX_CONTEXT_64_SIZE
#else
# define MAX_CONTEXT_SIZE 0x480 /* 0x463 from win-7 sp1 */
#endif
#define CONTEXT_DYNAMICALLY_LAID_OUT(flags) (TESTALL(CONTEXT_XSTATE, flags))
enum {
EXCEPTION_INFORMATION_READ_EXECUTE_FAULT = 0,
/* On non-NX capable machines Read and Execute faults are not
* differentiated */
EXCEPTION_INFORMATION_WRITE_FAULT = 1,
EXCEPTION_INFORMATION_EXECUTE_FAULT = 8, /* case 5879 */
/* Only on NX enabled machines Execute faults are differentiated */
};
#ifndef X64
/* x64 CONTEXT, for use from WOW64 32-bit code */
/* XXX: is there a better way to identify pre-7.0 SDK? It has XSAVE_FORMAT
* under _AMD64_ so we have to supply it here. To identify, it doesn't
* have XSAVE_ALIGN. Neither does 8.0 SDK, but we rule that out via
* XSTATE_AVX, which is only defined in 8.0.
*/
# if !defined(XSAVE_ALIGN) && !defined(XSTATE_AVX)
typedef struct DECLSPEC_ALIGN(16) _M128A {
ULONGLONG Low;
LONGLONG High;
} M128A, *PM128A;
typedef struct _XMM_SAVE_AREA32 {
WORD ControlWord;
WORD StatusWord;
BYTE TagWord;
BYTE Reserved1;
WORD ErrorOpcode;
DWORD ErrorOffset;
WORD ErrorSelector;
WORD Reserved2;
DWORD DataOffset;
WORD DataSelector;
WORD Reserved3;
DWORD MxCsr;
DWORD MxCsr_Mask;
M128A FloatRegisters[8];
M128A XmmRegisters[16];
BYTE Reserved4[96];
} XMM_SAVE_AREA32, *PXMM_SAVE_AREA32;
# else
typedef XSAVE_FORMAT XMM_SAVE_AREA32, *PXMM_SAVE_AREA32;
# endif
typedef struct DECLSPEC_ALIGN(16) _CONTEXT_64 {
//
// Register parameter home addresses.
//
// N.B. These fields are for convience - they could be used to extend the
// context record in the future.
//
DWORD64 P1Home;
DWORD64 P2Home;
DWORD64 P3Home;
DWORD64 P4Home;
DWORD64 P5Home;
DWORD64 P6Home;
//
// Control flags.
//
DWORD ContextFlags;
DWORD MxCsr;
//
// Segment Registers and processor flags.
//
WORD SegCs;
WORD SegDs;
WORD SegEs;
WORD SegFs;
WORD SegGs;
WORD SegSs;
DWORD EFlags;
//
// Debug registers
//
DWORD64 Dr0;
DWORD64 Dr1;
DWORD64 Dr2;
DWORD64 Dr3;
DWORD64 Dr6;
DWORD64 Dr7;
//
// Integer registers.
//
DWORD64 Rax;
DWORD64 Rcx;
DWORD64 Rdx;
DWORD64 Rbx;
DWORD64 Rsp;
DWORD64 Rbp;
DWORD64 Rsi;
DWORD64 Rdi;
DWORD64 R8;
DWORD64 R9;
DWORD64 R10;
DWORD64 R11;
DWORD64 R12;
DWORD64 R13;
DWORD64 R14;
DWORD64 R15;
//
// Program counter.
//
DWORD64 Rip;
//
// Floating point state.
//
union {
XMM_SAVE_AREA32 FltSave;
struct {
M128A Header[2];
M128A Legacy[8];
M128A Xmm0;
M128A Xmm1;
M128A Xmm2;
M128A Xmm3;
M128A Xmm4;
M128A Xmm5;
M128A Xmm6;
M128A Xmm7;
M128A Xmm8;
M128A Xmm9;
M128A Xmm10;
M128A Xmm11;
M128A Xmm12;
M128A Xmm13;
M128A Xmm14;
M128A Xmm15;
} DUMMYSTRUCTNAME;
} DUMMYUNIONNAME;
//
// Vector registers.
//
M128A VectorRegister[26];
DWORD64 VectorControl;
//
// Special debug control registers.
//
DWORD64 DebugControl;
DWORD64 LastBranchToRip;
DWORD64 LastBranchFromRip;
DWORD64 LastExceptionToRip;
DWORD64 LastExceptionFromRip;
} CONTEXT_64, *PCONTEXT_64;
#endif
/* in module_shared.c */
#ifndef X64
bool
thread_get_context_64(HANDLE thread, CONTEXT_64 *cxt64);
bool
thread_set_context_64(HANDLE thread, CONTEXT_64 *cxt64);
#endif
bool
should_inject_into_process(dcontext_t *dcontext, HANDLE process_handle,
int *rununder_mask, /* OPTIONAL OUT */
inject_setting_mask_t *inject_settings /* OPTIONAL OUT */);
/* in inject.c (also used by dynamo library) ***********************/
/* Note : inject_init calls get_module_handle and therefore should be called
* during dynamo initialization to avoid race conditions on the loader lock */
void
inject_init(void); /* must be called prior to inject_into_thread(void) */
bool
inject_into_thread(HANDLE phandle, CONTEXT *cxt, HANDLE thandle,
char *dynamo_path);
/* inject_location values come form the INJECT_LOCATION_* enum is os_shared.h */
bool
inject_into_new_process(HANDLE phandle, char *dynamo_path, bool map,
uint inject_location, void *inject_address);
/* in <arch.s> (x86.asm for us) ************************************/
void
internal_dynamo_start(void);
void
cleanup_after_interp(void);
void
callback_dynamo_start(void);
void
nt_continue_dynamo_start(void);
/* x86.asm custom routine used only for check_for_modified_code() */
void call_modcode_alt_stack(dcontext_t *dcontext, EXCEPTION_RECORD *pExcptRec,
CONTEXT *cxt, app_pc target, uint flags,
bool using_initstack, fragment_t *fragment);
/* x86.asm routine used for injection */
void load_dynamo(void);
/* in eventlog.c ***************************************************/
void
eventlog_init(void);
void
eventlog_fast_exit(void);
void
eventlog_slow_exit(void);
/* in module.c *****************************************************/
#ifdef X64
#ifndef __IMAGE_UNWIND_INFO
#define __IMAGE_UNWIND_INFO
#pragma warning(push)
#pragma warning(disable : 4214) /* allow byte-sized bitfields */
/* These definitions are needed to parse exception handlers to add to the RCT
* table as part of PR 250395. These definitions aren't found in any header
* files. These seem to be coming directly from internal sources. I saw a
* definition for RUNTIME_FUNCTION in winternal.h which was identical to
* IMAGE_RUNTIME_FUNCTION_ENTRY, which under a big comment block saying that it
* is for internal windows use only and might change from release to release, so
* using externally visible ones and declaring those that aren't available.
*
* These are based on the Microsoft specifications and suggested
* C defines at http://msdn2.microsoft.com/en-us/library/ssa62fwe(VS.80).aspx
* Since these are not in any header files we use our own style conventions.
*/
typedef enum _unwind_opcode_t {
UWOP_PUSH_NONVOL = 0, /* info == register number */
UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */
UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
} unwind_opcode_t;
typedef union _unwind_code_t {
struct {
byte CodeOffset;
byte UnwindOp :4;
byte OpInfo :4;
};
USHORT FrameOffset;
} unwind_code_t;
#ifndef UNW_FLAG_EHANDLER
# define UNW_FLAG_EHANDLER 0x01
# define UNW_FLAG_UHANDLER 0x02
# define UNW_FLAG_CHAININFO 0x04
#endif
typedef struct _unwind_info_t {
byte Version :3;
byte Flags :5;
byte SizeOfProlog;
byte CountOfCodes;
byte FrameRegister:4;
byte FrameOffset :4;
unwind_code_t UnwindCode[1];
#if 0 /* variable-length tail of struct */
/* MSDN uses "((CountOfCodes + 1) & ~1)" which is just align-forward-2,
* used b/c the UnwindCode array must always have an even capacity */
unwind_code_t MoreUnwindCode[ALIGN_FORWARD(CountOfCodes, 2) - 1];
union {
OPTIONAL ULONG ExceptionHandler;
OPTIONAL ULONG FunctionEntry;
};
OPTIONAL ULONG ExceptionData[];
#endif
} unwind_info_t;
/* Address of field that's after the unwind code data */
#define UNWIND_INFO_PTR_ADDR(info) \
((void *)&(info)->UnwindCode[ALIGN_FORWARD((info)->CountOfCodes, 2)])
/* Field that's after the unwind code data, treated as an RVA */
#define UNWIND_INFO_PTR_RVA(info) (*(uint*)UNWIND_INFO_PTR_ADDR(info))
/* ExceptionData field (2nd one after the unwind code data) */
#define UNWIND_INFO_DATA_ADDR(info) (((uint*)UNWIND_INFO_PTR_ADDR(info))+1)
#define UNWIND_INFO_DATA_RVA(info) (*(((uint*)UNWIND_INFO_PTR_ADDR(info))+1))
/* ExceptionData takes this form. It is inlined according to my observation
* but it may instead be pointed at by an RVA.
*/
typedef struct _scope_table_t {
ULONG Count;
struct {
ULONG BeginAddress;
ULONG EndAddress;
ULONG HandlerAddress;
ULONG JumpTarget;
} ScopeRecord[1];
} scope_table_t;
#pragma warning(pop)
#endif /* __IMAGE_UNWIND_INFO */
#endif /* X64 */
#define RVA_TO_VA(base, rva) ((ptr_uint_t)(base) + (ptr_uint_t)(rva))
bool
is_readable_pe_base(app_pc base);
bool
get_module_info_pe(const app_pc module_base, uint *checksum, uint *timestamp,
size_t *image_size, char **pe_name, size_t *code_size);
/* Use get_module_short_name for arbitrary pcs -- only call this if
* you KNOW this is the base addr of a non-executable module, as it
* bypasses some safety checks in get_module_short_name to avoid 4
* system calls.
*/
char*
get_dll_short_name(app_pc base_addr);
/* Use get_module_short_name in general */
const char *
get_module_short_name_uncached(dcontext_t *dcontext, app_pc base, bool at_map
HEAPACCT(which_heap_t which));
app_pc
get_module_entry(app_pc module_base);
uint
get_module_characteristics(app_pc module_base);
bool
module_has_cor20_header(app_pc module_base);
bool
module_is_32bit(app_pc module_base);
bool
module_is_64bit(app_pc module_base);
#ifdef DEBUG
enum {SYMBOLS_LOGLEVEL = 1};
int
loaded_modules_exports(void);
int
remove_module_info(app_pc start, size_t size);
int
add_module_info(app_pc base_addr, size_t size);
void
module_cleanup(void);
void
module_info_exit(void);
#endif /* DEBUG */
bool
module_file_relocatable(app_pc module_base);
bool module_rebase(app_pc module_base, size_t module_size,
ssize_t relocation_delta,
bool protect_incrementally);
bool module_dump_pe_file(HANDLE new_file,
app_pc module_base, size_t module_size);
bool
module_contents_compare(app_pc original_module_base,
app_pc suspect_module_base,
size_t matching_module_size,
bool relocated,
ssize_t relocation_delta,
size_t validation_section_prefix);
bool
module_make_writable(app_pc module_base, size_t module_size);
bool
aslr_compare_header(app_pc original_module_base, size_t original_header_len,
app_pc suspect_module_base);
bool
get_executable_segment(app_pc module_base,
app_pc *sec_start /* OPTIONAL OUT */,
app_pc *sec_end /* OPTIONAL OUT */,
app_pc *sec_end_nopad /* OPTIONAL OUT */);
/* Returns a dr_strdup-ed string which caller must dr_strfree w/ ACCT_VMAREAS */
const char *
section_to_file_lookup(HANDLE section_handle);
bool
section_to_file_add_wide(HANDLE section_handle, const wchar_t *file_path);
bool
section_to_file_add(HANDLE section_handle, const char *file_path);
bool
section_to_file_remove(HANDLE section_handle);
/* in aslr.c */
const wchar_t *
get_file_short_name(IN HANDLE file_handle, IN OUT FILE_NAME_INFORMATION *name_info);
void
aslr_set_last_section_file_name(dcontext_t *dcontext, const wchar_t *short_name);
/* in os.c */
bool
safe_write(void *base, size_t size, const void *in_buf);
/* Note that we should keep an eye for potential additional qualifier
* flags. Alternatively we may simply mask off ~0xff to allow for any
* future flags added here.
*/
#define PAGE_PROTECTION_QUALIFIERS (PAGE_GUARD | PAGE_NOCACHE | PAGE_WRITECOMBINE)
char *
prot_string(uint prot);
/* FIXME: should we try to alert any dynamo running the other process?
* Refer new instances to Case 68
*/
#define IPC_ALERT(...) SYSLOG_INTERNAL_WARNING_ONCE("IPC ALERT " __VA_ARGS__)
const PSID
get_process_primary_SID(void);
bool
convert_NT_to_Dos_path(OUT wchar_t *buf, IN const wchar_t *fname,
IN size_t buf_len/*# elements*/);
CONTEXT *
nt_initialize_context(char *buf, DWORD flags);
byte *
context_ymmh_saved_area(CONTEXT *cxt);
#ifndef NOT_DYNAMORIO_CORE_PROPER /* b/c of global_heap_* */
/* always null-terminates when it returns non-NULL */
wchar_t *
convert_to_NT_file_path_wide(OUT wchar_t *fixedbuf, IN const wchar_t *fname,
IN size_t fixedbuf_len/*# elements*/,
OUT size_t *allocbuf_sz/*#bytes*/);
void
convert_to_NT_file_path_wide_free(IN wchar_t *alloc, IN size_t alloc_buf_sz/*#bytes*/);
#endif
/* always null-terminates when it returns true */
bool
convert_to_NT_file_path(OUT wchar_t *buf, IN const char *fname,
IN size_t buf_len/*# elements*/);
/* in loader.c */
/* early injection bootstrapping */
bool
privload_bootstrap_dynamorio_imports(byte *dr_base, byte *ntdll_base);
bool
bootstrap_protect_virtual_memory(void *base, size_t size, uint prot, uint *old_prot);
/* in ntdll.c, set via arg from parent for earliest inj */
void
set_ntdll_base(app_pc base);
/* in diagnost.c */
byte *
get_system_processes(OUT uint *info_bytes_needed);
#endif /* _OS_PRIVATE_H_ */