From 52955a4cb41d87839e96880de638211057b9d84c Mon Sep 17 00:00:00 2001 From: Ilya Berezhniuk Date: Thu, 20 Mar 2008 03:26:42 +0300 Subject: [PATCH] Make-Port-Crash-Signal-Handler-shared v3 - 02-patch --- build.xml | 18 ++- make/vm/port.xml | 51 ++----- make/vm/port_ch.xml | 134 ++++++++++++++++++ make/vm/vmcore.xml | 3 +- vm/include/open/types.h | 2 +- vm/port/build/ch.exp | 21 +++ vm/port/include/port_crash_handler.h | 16 +- vm/port/include/port_memaccess.h | 5 +- vm/port/include/port_modules.h | 9 +- vm/port/include/port_thread.h | 47 ------ vm/port/include/port_unwind.h | 7 +- .../src/crash_handler/linux/gdb_crash_handler.cpp | 2 +- vm/port/src/misc/linux/execname.c | 73 ++++++++++ vm/port/src/misc/linux/sysinfo.c | 46 ------ vm/port/src/misc/win/execname.c | 38 +++++ vm/port/src/misc/win/sysinfo.c | 15 -- vm/port/src/signals/include/signals_internal.h | 49 +++++++ vm/port/src/signals/linux/signals_asm_em64t.s | 10 +- vm/port/src/signals/linux/signals_em64t.cpp | 149 ++++++++++++++++++++ vm/port/src/signals/linux/signals_ia32.cpp | 105 ++++++++++++++ vm/port/src/signals/win/signals_asm_em64t.asm | 118 +++++++++++++++- vm/port/src/signals/win/signals_em64t.cpp | 137 ++++++++++++++++++ vm/port/src/signals/win/signals_ia32.cpp | 87 ++++++++++++ vm/port/src/thread/linux/thread_em64t.c | 121 ---------------- vm/port/src/thread/linux/thread_ia32.c | 85 ----------- vm/port/src/thread/linux/thread_ipf.c | 24 --- vm/port/src/thread/win/thread_asm_em64t.asm | 133 ----------------- vm/port/src/thread/win/thread_em64t.c | 122 ---------------- vm/port/src/thread/win/thread_ia32.c | 85 ----------- vm/port/src/thread/win/thread_os.c | 6 +- 30 files changed, 964 insertions(+), 754 deletions(-) create mode 100644 make/vm/port_ch.xml create mode 100644 vm/port/build/ch.exp create mode 100644 vm/port/src/misc/linux/execname.c create mode 100644 vm/port/src/misc/win/execname.c create mode 100644 vm/port/src/signals/linux/signals_em64t.cpp create mode 100644 vm/port/src/signals/linux/signals_ia32.cpp create mode 100644 vm/port/src/signals/win/signals_em64t.cpp delete mode 100644 vm/port/src/thread/win/thread_asm_em64t.asm diff --git a/build.xml b/build.xml index 4029694..90a5024 100644 --- a/build.xml +++ b/build.xml @@ -109,22 +109,26 @@ Usage: - + - + - + - + + + + + @@ -137,7 +141,7 @@ Usage: - + @@ -148,7 +152,7 @@ Usage: - + @@ -164,7 +168,7 @@ Usage: - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/make/vm/vmcore.xml b/make/vm/vmcore.xml index 52a33b1..1bb17f8 100644 --- a/make/vm/vmcore.xml +++ b/make/vm/vmcore.xml @@ -217,7 +217,8 @@ - + + diff --git a/vm/include/open/types.h b/vm/include/open/types.h index 63abb85..363d379 100644 --- a/vm/include/open/types.h +++ b/vm/include/open/types.h @@ -18,7 +18,7 @@ #ifndef _VM_TYPES_H_ #define _VM_TYPES_H_ -#include "platform_types.h" +#include "open/platform_types.h" #include diff --git a/vm/port/build/ch.exp b/vm/port/build/ch.exp new file mode 100644 index 0000000..b24cd00 --- /dev/null +++ b/vm/port/build/ch.exp @@ -0,0 +1,21 @@ +PORT_0.1 { + global : +# + port_init_crash_handler; + port_shutdown_crash_handler; + port_crash_handler_*; + port_set_breakpoint; + port_clear_breakpoint; + port_is_breakpoint_set; + port_read_memory; + port_write_memory; + port_get_all_modules; + port_dump_modules; + port_clear_modules; + port_find_module; + port_init_unwind_context; + port_clean_unwind_context; + port_unwind_frame; +# + local : *; +}; diff --git a/vm/port/include/port_crash_handler.h b/vm/port/include/port_crash_handler.h index deca7f1..1692bf9 100644 --- a/vm/port/include/port_crash_handler.h +++ b/vm/port/include/port_crash_handler.h @@ -135,7 +135,7 @@ typedef struct * @return TRUE if initalization is successful. * FALSE if initialization failed. */ -Boolean port_init_crash_handler( +VMEXPORT Boolean port_init_crash_handler( port_signal_handler_registration *registrations, unsigned count, port_unwind_compiled_frame unwind_callback); @@ -201,7 +201,7 @@ typedef enum * * @returns supported crash handler features. */ -unsigned port_crash_handler_get_capabilities(); +VMEXPORT unsigned port_crash_handler_get_capabilities(); /** * Set crash handler output flags. Default mode is @@ -212,7 +212,7 @@ unsigned port_crash_handler_get_capabilities(); * * @param flags - crash handler output flags. */ -void port_crash_handler_set_flags(unsigned flags); +VMEXPORT void port_crash_handler_set_flags(unsigned flags); /** * Callback function that is called at the end of shutdown sequence. @@ -243,7 +243,7 @@ typedef void (*port_crash_handler_action)( * FALSE if action was not added because no memory could * be allocated. */ -Boolean port_crash_handler_add_action(port_crash_handler_action action); +VMEXPORT Boolean port_crash_handler_add_action(port_crash_handler_action action); /** * Shutdown signals and crash handler. All signals are assigned their @@ -255,7 +255,7 @@ Boolean port_crash_handler_add_action(port_crash_handler_action action); * @return TRUE if shutdown is * successful. FALSE if shutdown failed. */ -Boolean port_shutdown_crash_handler(); +VMEXPORT Boolean port_shutdown_crash_handler(); /** @@ -267,7 +267,7 @@ Boolean port_shutdown_crash_handler(); * @note Caller should keep store previous byte to restore * the location in future. */ -int port_set_breakpoint(void* addr, unsigned char* prev); +VMEXPORT int port_set_breakpoint(void* addr, unsigned char* prev); /** * Restores original byte in the location previously instrumented @@ -277,14 +277,14 @@ int port_set_breakpoint(void* addr, unsigned char* prev); * @return 0 if OK; nonzero if the location was not * instrumented yet or if an error occured. */ -int port_clear_breakpoint(void* addr, unsigned char prev); +VMEXPORT int port_clear_breakpoint(void* addr, unsigned char prev); /** * Checks if the location is instrumented. * @param [in] addr - memory location to deinstrument. * @return TRUE if instrumented; FALSE otherwise. */ -Boolean port_is_breakpoint_set(void* addr); +VMEXPORT Boolean port_is_breakpoint_set(void* addr); diff --git a/vm/port/include/port_memaccess.h b/vm/port/include/port_memaccess.h index 3122cae..dfc3577 100644 --- a/vm/port/include/port_memaccess.h +++ b/vm/port/include/port_memaccess.h @@ -20,6 +20,7 @@ #include #include "open/platform_types.h" +#include "port_general.h" #ifdef __cplusplus @@ -34,7 +35,7 @@ extern "C" { * @param buf - buffer to read to. * @return 0 if OK; nonzero if an error occured. */ -int port_read_memory(void* addr, size_t size, void* buf); +VMEXPORT int port_read_memory(void* addr, size_t size, void* buf); /** * Tries to write specified number of bytes from buffer to given address. @@ -43,7 +44,7 @@ int port_read_memory(void* addr, size_t size, void* buf); * @param buf - buffer to write from. * @return 0 if OK; nonzero if an error occured. */ -int port_write_memory(void* addr, size_t size, void* buf); +VMEXPORT int port_write_memory(void* addr, size_t size, void* buf); #ifdef __cplusplus diff --git a/vm/port/include/port_modules.h b/vm/port/include/port_modules.h index 3bd59bd..2abf289 100644 --- a/vm/port/include/port_modules.h +++ b/vm/port/include/port_modules.h @@ -25,6 +25,7 @@ #include #include #include "open/platform_types.h" +#include "port_general.h" typedef enum { @@ -61,20 +62,20 @@ extern "C" { * @param count_ptr - count of modules in the returned list * @return TRUE if OK; FALSE if error occured. */ -Boolean port_get_all_modules(native_module_t** list_ptr, int* count_ptr); +VMEXPORT Boolean port_get_all_modules(native_module_t** list_ptr, int* count_ptr); /** * Dumps the list of modules loaded to the current process.. * @param modules - pointer to the list of modules to dump. * @param out - stream for printing the dump. */ -void port_dump_modules(native_module_t* modules, FILE *out); +VMEXPORT void port_dump_modules(native_module_t* modules, FILE *out); /** * Clears the list of modules passed, writes NULL to the poiner. * @param modules - pointer to the list of modules to clear. */ -void port_clear_modules(native_module_t** list_ptr); +VMEXPORT void port_clear_modules(native_module_t** list_ptr); /** * Searches for the specific address in the list of modules. @@ -82,7 +83,7 @@ void port_clear_modules(native_module_t** list_ptr); * @param code_ptr - the address to look for. * @return native_module_t pointer if OK; otherwise, NULL. */ -native_module_t* port_find_module(native_module_t* modules, void* code_ptr); +VMEXPORT native_module_t* port_find_module(native_module_t* modules, void* code_ptr); #ifdef __cplusplus diff --git a/vm/port/include/port_thread.h b/vm/port/include/port_thread.h index 85014ba..83f68c3 100644 --- a/vm/port/include/port_thread.h +++ b/vm/port/include/port_thread.h @@ -85,53 +85,6 @@ int port_thread_set_context(osthread_t thread, thread_context_t* pcontext); void port_thread_context_to_regs(Registers* regs, thread_context_t* context); void port_thread_regs_to_context(thread_context_t* context, Registers* regs); -/* Transfer control to specified register context */ -void port_transfer_to_regs(Registers* regs); - -/** -* Prepares 'Registers' structure and stack area pointed in for calling -* 'fn' function with a set of arguments provided in variable args list. -* THe 'fn' function is called through a special stub function with -* preserving 'red zone' on Linux and clearing direction flag on Windows. -* After returning from 'fn' and stub, processor registers are restored -* with a values provided in 'regs' argument. -* The function can be used to prepare register context for transfering -* a control to a signal/exception handling function out of the OS handler. -* -* When the first argument passed to 'fn' is the same 'regs' pointer, its -* value is substituted with the pointer stored 'Registers' structure used -* to restore register context. If 'fn' function modifies the context -* pointed by the first argument, these changes will take effect after -* returning from 'fn'. -* -* The stub for calling 'fn' is written in assembler language; 'Registers' -* fields and size are hardcoded. It would be better to rewrite it using -* encoder in future, to keep control on 'Registers' structure and size. -* -* @param [in] fn - the address of the function to be called -* @param [in] regs - the register context -* @param [in] num - the number of parameters passed to the 'fn' function -* in the variable args list (6 args at maximum) -* @param [in] ... - the parameters for 'fn'; should all be void* or of -* the same size (pointer-sized) -*/ -void port_set_longjump_regs(void* fn, Registers* regs, int num, ...); - -/** -* The same as 'port_set_longjump_regs', but transfers a control to the -* prepared registers context by itself. -* Actually it's a combination of 'port_set_longjump_regs' and -* 'port_transfer_to_regs' functions, but 'regs' fields are kept unchanged. -* -* @param [in] fn - the address of the function to be called -* @param [in] regs - the register context -* @param [in] num - the number of parameters passed to the 'fn' function -* in the variable args list (6 args at maximum) -* @param [in] ... - the parameters for 'fn'; should all be void* or of -* the same size (pointer-sized) -*/ -void port_transfer_to_function(void* fn, Registers* regs, int num, ...); - //@} diff --git a/vm/port/include/port_unwind.h b/vm/port/include/port_unwind.h index 8067073..c7e8bd1 100644 --- a/vm/port/include/port_unwind.h +++ b/vm/port/include/port_unwind.h @@ -18,6 +18,7 @@ #ifndef __PORT_UNWIND_H__ #define __PORT_UNWIND_H__ +#include "port_general.h" #include "port_modules.h" typedef struct UnwindContext { @@ -31,10 +32,10 @@ extern "C" { #endif -bool port_init_unwind_context(UnwindContext* context, native_module_t* modules, Registers* regs); -void port_clean_unwind_context(UnwindContext* context); +VMEXPORT bool port_init_unwind_context(UnwindContext* context, native_module_t* modules, Registers* regs); +VMEXPORT void port_clean_unwind_context(UnwindContext* context); -bool port_unwind_frame(UnwindContext* context, Registers* regs); +VMEXPORT bool port_unwind_frame(UnwindContext* context, Registers* regs); #ifdef __cplusplus diff --git a/vm/port/src/crash_handler/linux/gdb_crash_handler.cpp b/vm/port/src/crash_handler/linux/gdb_crash_handler.cpp index e9b9e58..42a0f39 100644 --- a/vm/port/src/crash_handler/linux/gdb_crash_handler.cpp +++ b/vm/port/src/crash_handler/linux/gdb_crash_handler.cpp @@ -98,6 +98,6 @@ bool init_gdb_crash_handler() void cleanup_gdb_crash_handler() { - STD_FREE(g_executable); +// STD_FREE(g_executable); g_prepared = false; } diff --git a/vm/port/src/misc/linux/execname.c b/vm/port/src/misc/linux/execname.c new file mode 100644 index 0000000..22e6b2d --- /dev/null +++ b/vm/port/src/misc/linux/execname.c @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** +* @author Alexey V. Varlamov +* @version $Revision: 1.1.2.1.4.3 $ +*/ + +#include +#include +#include +#include +#include +#include "port_malloc.h" +#include "port_sysinfo.h" +#if defined(FREEBSD) +#define _GNU_SOURCE +#include +extern int main (int argc, char **argv, char **envp); +#endif + +APR_DECLARE(apr_status_t) port_executable_name(char** self_name) { + + char* buf; + +#if defined(FREEBSD) + Dl_info info; + + if (dladdr( (const void*)&main, &info) == 0) { + return APR_ENOENT; + } + + buf = (char*)STD_MALLOC(strlen(info.dli_fname) + 1); + + if (!buf) + return APR_ENOMEM; + + strcpy(buf, info.dli_fname); +#else + char tmpbuf[PATH_MAX + 1]; + + int n = readlink("/proc/self/exe", tmpbuf, PATH_MAX); + + if (n == -1) { + return apr_get_os_error(); + } + + tmpbuf[n] = '\0'; + + buf = (char*)STD_MALLOC(n + 1); + + if (!buf) + return APR_ENOMEM; + + strcpy(buf, tmpbuf); +#endif + + *self_name = buf; + return APR_SUCCESS; +} diff --git a/vm/port/src/misc/linux/sysinfo.c b/vm/port/src/misc/linux/sysinfo.c index 92f1258..9dade9c 100644 --- a/vm/port/src/misc/linux/sysinfo.c +++ b/vm/port/src/misc/linux/sysinfo.c @@ -24,54 +24,8 @@ #include #include #include -#include "port_malloc.h" #include "port_sysinfo.h" #include -#if defined(FREEBSD) -#define _GNU_SOURCE -#include -extern int main (int argc, char **argv, char **envp); -#endif - -APR_DECLARE(apr_status_t) port_executable_name(char** self_name) { - - char* buf; - -#if defined(FREEBSD) - Dl_info info; - - if (dladdr( (const void*)&main, &info) == 0) { - return APR_ENOENT; - } - - buf = (char*)STD_MALLOC(strlen(info.dli_fname) + 1); - - if (!buf) - return APR_ENOMEM; - - strcpy(buf, info.dli_fname); -#else - char tmpbuf[PATH_MAX + 1]; - - int n = readlink("/proc/self/exe", tmpbuf, PATH_MAX); - - if (n == -1) { - return apr_get_os_error(); - } - - tmpbuf[n] = '\0'; - - buf = (char*)STD_MALLOC(n + 1); - - if (!buf) - return APR_ENOMEM; - - strcpy(buf, tmpbuf); -#endif - - *self_name = buf; - return APR_SUCCESS; -} APR_DECLARE(int) port_CPUs_number(void) { return (int)sysconf(_SC_NPROCESSORS_CONF); diff --git a/vm/port/src/misc/win/execname.c b/vm/port/src/misc/win/execname.c new file mode 100644 index 0000000..fd22978 --- /dev/null +++ b/vm/port/src/misc/win/execname.c @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "port_malloc.h" +#include "port_sysinfo.h" + +#include +#include +#include + +APR_DECLARE(apr_status_t) port_executable_name(char** self_name){ + + char buf[_MAX_PATH*2]; /*XXX result in TCHARs */ + int len = GetModuleFileName(0, buf, _MAX_PATH); + if (0 == len) { + return apr_get_os_error(); + } + + *self_name = STD_MALLOC(strlen(buf) + 1); + if (*self_name) + strcpy(*self_name, buf); + + return APR_SUCCESS; +} diff --git a/vm/port/src/misc/win/sysinfo.c b/vm/port/src/misc/win/sysinfo.c index de98f0d..7d2fdc3 100644 --- a/vm/port/src/misc/win/sysinfo.c +++ b/vm/port/src/misc/win/sysinfo.c @@ -96,21 +96,6 @@ APR_DECLARE(apr_status_t) port_OS_name_version(char** os_name, char** os_ver, return APR_SUCCESS; } -APR_DECLARE(apr_status_t) port_executable_name(char** self_name){ - - char buf[_MAX_PATH*2]; /*XXX result in TCHARs */ - int len = GetModuleFileName(0, buf, _MAX_PATH); - if (0 == len) { - return apr_get_os_error(); - } - - *self_name = STD_MALLOC(strlen(buf) + 1); - if (*self_name) - strcpy(*self_name, buf); - - return APR_SUCCESS; -} - APR_DECLARE(const char *) port_CPU_architecture(void){ #if defined(_IPF_) return "ia64"; diff --git a/vm/port/src/signals/include/signals_internal.h b/vm/port/src/signals/include/signals_internal.h index bf46feb..5196056 100644 --- a/vm/port/src/signals/include/signals_internal.h +++ b/vm/port/src/signals/include/signals_internal.h @@ -82,6 +82,55 @@ PORT_INLINE int set_private_tls_data(port_tls_data* data) } +/* Transfer control to specified register context */ +void port_transfer_to_regs(Registers* regs); + +/** +* Prepares 'Registers' structure and stack area pointed in for calling +* 'fn' function with a set of arguments provided in variable args list. +* THe 'fn' function is called through a special stub function with +* preserving 'red zone' on Linux and clearing direction flag on Windows. +* After returning from 'fn' and stub, processor registers are restored +* with a values provided in 'regs' argument. +* The function can be used to prepare register context for transfering +* a control to a signal/exception handling function out of the OS handler. +* +* When the first argument passed to 'fn' is the same 'regs' pointer, its +* value is substituted with the pointer stored 'Registers' structure used +* to restore register context. If 'fn' function modifies the context +* pointed by the first argument, these changes will take effect after +* returning from 'fn'. +* +* The stub for calling 'fn' is written in assembler language; 'Registers' +* fields and size are hardcoded. It would be better to rewrite it using +* encoder in future, to keep control on 'Registers' structure and size. +* +* @param [in] fn - the address of the function to be called +* @param [in] regs - the register context +* @param [in] num - the number of parameters passed to the 'fn' function +* in the variable args list (6 args at maximum) +* @param [in] ... - the parameters for 'fn'; should all be void* or of +* the same size (pointer-sized) +*/ +void port_set_longjump_regs(void* fn, Registers* regs, int num, ...); + +/** +* The same as 'port_set_longjump_regs', but transfers a control to the +* prepared registers context by itself. +* Actually it's a combination of 'port_set_longjump_regs' and +* 'port_transfer_to_regs' functions, but 'regs' fields are kept unchanged. +* +* @param [in] fn - the address of the function to be called +* @param [in] regs - the register context +* @param [in] num - the number of parameters passed to the 'fn' function +* in the variable args list (6 args at maximum) +* @param [in] ... - the parameters for 'fn'; should all be void* or of +* the same size (pointer-sized) +*/ +void port_transfer_to_function(void* fn, Registers* regs, int num, ...); + + + #define INSTRUMENTATION_BYTE_HLT 0xf4 // HLT instruction #define INSTRUMENTATION_BYTE_CLI 0xfa // CLI instruction #define INSTRUMENTATION_BYTE_INT3 0xcc // INT 3 instruction diff --git a/vm/port/src/signals/linux/signals_asm_em64t.s b/vm/port/src/signals/linux/signals_asm_em64t.s index 5468020..9a5cd76 100644 --- a/vm/port/src/signals/linux/signals_asm_em64t.s +++ b/vm/port/src/signals/linux/signals_asm_em64t.s @@ -41,11 +41,11 @@ // uint32 eflags;; 88h // }; // -// void port_transfer_to_regs(Registers* regs) +// void port_transfer_to_regs_asm(Registers* regs) -.globl port_transfer_to_regs - .type port_transfer_to_regs, @function -port_transfer_to_regs: +.globl port_transfer_to_regs_asm + .type port_transfer_to_regs_asm, @function +port_transfer_to_regs_asm: movq %rdi, %rdx // regs pointer (1st param - RDI) -> RDX movq 0x08(%rdx), %rbp // RBP field @@ -116,5 +116,5 @@ __skipefl__: port_longjump_stub: // movq 128(%rsp), %rdi // load RDI with the address of saved Registers movq (%rsp), %rdi // load RDI with the address of saved Registers - callq port_transfer_to_regs // restore context + callq port_transfer_to_regs_asm // restore context ret // dummy RET - unreachable diff --git a/vm/port/src/signals/linux/signals_em64t.cpp b/vm/port/src/signals/linux/signals_em64t.cpp new file mode 100644 index 0000000..c3c5b67 --- /dev/null +++ b/vm/port/src/signals/linux/signals_em64t.cpp @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include "signals_internal.h" + + +extern "C" void port_longjump_stub(void); +#define DIR_FLAG ((uint32)0x00000400) + +void port_set_longjump_regs(void* fn, Registers* regs, int num, ...) +{ + void** sp; + va_list ap; + int i; + size_t align; + void** p_pregs; + size_t rcount = + (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); + + if (!regs) + return; + + sp = (void**)regs->rsp - 16 - 1; /* preserve 128-bytes 'red zone' */ + *sp = (void*)regs->rip; + align = !((rcount & 1) ^ (((uint64)sp & sizeof(void*)) != 0)); + p_pregs = sp - rcount - align - 1; + sp = sp - rcount; + *((Registers*)sp) = *regs; + *p_pregs = (void*)sp; + +// sp = p_pregs - 16 - 1; /* preserve 128-bytes 'red zone' */ + sp = p_pregs - 1; /* set sp to return address */ + + va_start(ap, num); + + if (num > 0) + { + void* arg = va_arg(ap, void*); + if (arg == regs) + regs->rdi = (uint64)(*p_pregs); /* Replace 1st arg */ + else + regs->rdi = (uint64)arg; + } + + if (num > 1) + regs->rsi = (uint64)va_arg(ap, void*); + + if (num > 2) + regs->rdx = (uint64)va_arg(ap, void*); + + if (num > 3) + regs->rcx = (uint64)va_arg(ap, void*); + + if (num > 4) + regs->r8 = (uint64)va_arg(ap, void*); + + if (num > 5) + regs->r9 = (uint64)va_arg(ap, void*); + + *sp = (void*)&port_longjump_stub; + regs->rsp = (uint64)sp; + regs->rip = (uint64)fn; + regs->eflags = regs->eflags & ~DIR_FLAG; +} + +void port_transfer_to_function(void* fn, Registers* pregs, int num, ...) +{ + void** sp; + va_list ap; + int i; + size_t align; + void** p_pregs; + size_t rcount = + (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); + Registers regs; + + if (!pregs) + return; + + regs = *pregs; + + sp = (void**)regs.rsp - 16 - 1; /* preserve 128-bytes 'red zone' */ + *sp = (void*)regs.rip; + align = !((rcount & 1) ^ (((uint64)sp & sizeof(void*)) != 0)); + p_pregs = sp - rcount - align - 1; + sp = sp - rcount; + *((Registers*)sp) = regs; + *p_pregs = (void*)sp; + +// sp = p_pregs - 16 - 1; /* preserve 128-bytes 'red zone' */ + sp = p_pregs - 1; /* set sp to return address */ + + va_start(ap, num); + + if (num > 0) + { + void* arg = va_arg(ap, void*); + if (arg == pregs) + regs.rdi = (uint64)(*p_pregs); /* Replace 1st arg */ + else + regs.rdi = (uint64)arg; + } + + if (num > 1) + regs.rsi = (uint64)va_arg(ap, void*); + + if (num > 2) + regs.rdx = (uint64)va_arg(ap, void*); + + if (num > 3) + regs.rcx = (uint64)va_arg(ap, void*); + + if (num > 4) + regs.r8 = (uint64)va_arg(ap, void*); + + if (num > 5) + regs.r9 = (uint64)va_arg(ap, void*); + + *sp = (void*)&port_longjump_stub; + regs.rsp = (uint64)sp; + regs.rip = (uint64)fn; + regs.eflags = regs.eflags & ~DIR_FLAG; + + port_transfer_to_regs(®s); +} + +// Workaround for improper -fPIC processing for assembler files +extern "C" void port_transfer_to_regs_asm(Registers* regs); + +void port_transfer_to_regs(Registers* regs) +{ + port_transfer_to_regs_asm(regs); +} diff --git a/vm/port/src/signals/linux/signals_ia32.cpp b/vm/port/src/signals/linux/signals_ia32.cpp new file mode 100644 index 0000000..ab60ddd --- /dev/null +++ b/vm/port/src/signals/linux/signals_ia32.cpp @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include "signals_internal.h" + + +extern "C" void port_longjump_stub(void); +#define DIR_FLAG ((uint32)0x00000400) + +void port_set_longjump_regs(void* fn, Registers* regs, int num, ...) +{ + void** sp; + va_list ap; + int i; + size_t rcount = + (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); + + if (!regs) + return; + + sp = (void**)regs->esp - 1; + *sp = (void*)regs->eip; + sp = sp - rcount - 1; + *((Registers*)(sp + 1)) = *regs; + *sp = (void*)(sp + 1); + regs->ebp = (uint32)sp; + + sp = sp - num - 1; + + va_start(ap, num); + + for (i = 1; i <= num; i = i + 1) + { + void* arg = va_arg(ap, void*); + + if (i == 1 && arg == regs) + sp[i] = *((void**)regs->ebp); /* Replace 1st arg */ + else + sp[i] = arg; + } + + *sp = (void*)&port_longjump_stub; + regs->esp = (uint32)sp; + regs->eip = (uint32)fn; + regs->eflags = regs->eflags & ~DIR_FLAG; +} + +void port_transfer_to_function(void* fn, Registers* pregs, int num, ...) +{ + void** sp; + va_list ap; + int i; + size_t rcount = + (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); + Registers regs; + + if (!pregs) + return; + + regs = *pregs; + + sp = (void**)regs.esp - 1; + *sp = (void*)regs.eip; + sp = sp - rcount - 1; + *((Registers*)(sp + 1)) = regs; + *sp = (void*)(sp + 1); + regs.ebp = (uint32)sp; + + sp = sp - num - 1; + + va_start(ap, num); + + for (i = 1; i <= num; i = i + 1) + { + void* arg = va_arg(ap, void*); + + if (i == 1 && arg == pregs) + sp[i] = *((void**)regs.ebp); /* Replace 1st arg */ + else + sp[i] = arg; + } + + *sp = (void*)&port_longjump_stub; + regs.esp = (uint32)sp; + regs.eip = (uint32)fn; + regs.eflags = regs.eflags & ~DIR_FLAG; + + port_transfer_to_regs(®s); +} diff --git a/vm/port/src/signals/win/signals_asm_em64t.asm b/vm/port/src/signals/win/signals_asm_em64t.asm index b54aa4f..d967caf 100644 --- a/vm/port/src/signals/win/signals_asm_em64t.asm +++ b/vm/port/src/signals/win/signals_asm_em64t.asm @@ -1,8 +1,10 @@ -PUBLIC vectored_exception_handler -EXTRN vectored_exception_handler_internal:PROC _TEXT SEGMENT + +PUBLIC vectored_exception_handler +EXTRN vectored_exception_handler_internal:PROC + vectored_exception_handler PROC ; LONG NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_exception) @@ -22,6 +24,118 @@ vectored_exception_handler PROC vectored_exception_handler ENDP + +; struct Registers { +; uint64 rsp; ; 00h +; uint64 rbp; ; 08h +; uint64 rip; ; 10h +; // callee-saved +; uint64 rbx; ; 18h +; uint64 r12; ; 20h +; uint64 r13; ; 28h +; uint64 r14; ; 30h +; uint64 r15; ; 38h +; // scratched +; uint64 rax; ; 40h +; uint64 rcx; ; 48h +; uint64 rdx; ; 50h +; uint64 rsi; ; 58h +; uint64 rdi; ; 60h +; uint64 r8; ; 68h +; uint64 r9; ; 70h +; uint64 r10; ; 78h +; uint64 r11; ; 80h +; +; uint32 eflags;; 88h +; }; +; +; void port_transfer_to_regs(Registers* regs) + +PUBLIC port_transfer_to_regs + +port_transfer_to_regs PROC + + mov rdx, rcx ; regs pointer (1st param - RCX) -> RDX + + mov rbp, qword ptr [rdx+08h] ; RBP field + mov rbx, qword ptr [rdx+18h] ; RBX field + mov r12, qword ptr [rdx+20h] ; R12 field + mov r13, qword ptr [rdx+28h] ; R13 field + mov r14, qword ptr [rdx+30h] ; R14 field + mov r15, qword ptr [rdx+38h] ; R15 field + mov rsi, qword ptr [rdx+58h] ; RSI field + mov rdi, qword ptr [rdx+60h] ; RDI field + mov r8, qword ptr [rdx+68h] ; R8 field + mov r9, qword ptr [rdx+70h] ; R9 field + mov r10, qword ptr [rdx+78h] ; R10 field + mov r11, qword ptr [rdx+80h] ; R11 field + + mov rax, qword ptr [rdx+00h] ; (new RSP) -> RAX + mov qword ptr [rsp], rax ; (new RSP) -> [RSP] for future use + mov rcx, qword ptr [rdx+10h] ; (new RIP) -> RCX + mov qword ptr [rax-88h],rcx ; (new RIP) -> [(new RSP) - 128 - 8] + mov rax, qword ptr [rdx+40h] ; RAX field + + movzx rcx, word ptr [rdx+88h] ; (word)EFLAGS -> RCX + test rcx, rcx + je __skipefl__ + pushfq + and dword ptr [rsp], 003F7202h ; Clear OF, DF, TF, SF, ZF, AF, PF, CF + and ecx, 00000CD5h ; Clear all except OF, DF, SF, ZF, AF, PF, CF + or dword ptr [rsp], ecx + popfq ; restore RFLAGS +__skipefl__: + + mov rcx, qword ptr [rdx+48h] ; RCX field + mov rdx, qword ptr [rdx+50h] ; RDX field + + mov rsp, qword ptr [rsp] ; load new RSP + jmp qword ptr [rsp-88h] ; JMP to new RIP + +port_transfer_to_regs ENDP + + +; void port_longjump_stub(void) +; +; after returning from the called function, RSP points to the 2 argument +; slots in the stack. Saved Registers structure pointer is (RSP + 48) +; +; | interrupted | +; | program | <- RSP where the program was interrupted by exception +; |-------------| +; | 0x80 bytes | <- preserved stack area - we will not change it +; |-------------| +; | return addr | +; | from stub | <- for using in port_transfer_to_regs as [(new RSP) - 128 - 8] +; |-------------| +; | saved | +; | Registers | <- to restore register context +; |-------------| +; | [alignment] | <- align Regs pointer to 16-bytes boundary +; |-------------| +; | pointer to | +; | saved Regs | <- (RSP + 48) +; |-------------| +; | arg 5 | <- present even if not used +; |-------------| +; | arg 4 | <- present even if not used +; |-------------| +; | 32 bytes | <- 'red zone' for argument registers flushing +; |-------------| +; | return addr | +; | from 'fn' | <- address to return to the port_longjump_stub +; |-------------| + +PUBLIC port_longjump_stub + +port_longjump_stub PROC + + mov rcx, qword ptr [rsp + 48] ; load RCX with the address of saved Registers + call port_transfer_to_regs ; restore context + ret ; dummy RET - unreachable +port_longjump_stub ENDP + + _TEXT ENDS END diff --git a/vm/port/src/signals/win/signals_em64t.cpp b/vm/port/src/signals/win/signals_em64t.cpp new file mode 100644 index 0000000..d7eefca --- /dev/null +++ b/vm/port/src/signals/win/signals_em64t.cpp @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "signals_internal.h" +#define ANSI +#include + + +extern "C" void port_longjump_stub(void); +#define DIR_FLAG ((uint32)0x00000400) + +void port_set_longjump_regs(void* fn, Registers* regs, int num, ...) +{ + void** sp; + va_list ap; + int i; + size_t align; + void** p_pregs; + size_t rcount = + (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); + + if (!regs) + return; + + sp = (void**)regs->rsp - 16 - 1; /* preserve 128-bytes area */ + *sp = (void*)regs->rip; + align = !((rcount & 1) ^ (((uint64)sp & sizeof(void*)) != 0)); + p_pregs = sp - rcount - align - 1; + sp = sp - rcount; + *((Registers*)sp) = *regs; + *p_pregs = (void*)sp; + + sp = p_pregs - 6 - 1; + + va_start(ap, num); + + if (num > 0) + { + void* arg = va_arg(ap, void*); + if (arg == regs) + regs->rcx = (uint64)(*p_pregs); /* Replace 1st arg */ + else + regs->rcx = (uint64)arg; + } + + if (num > 1) + regs->rdx = (uint64)va_arg(ap, void*); + + if (num > 2) + regs->r8 = (uint64)va_arg(ap, void*); + + if (num > 3) + regs->r9 = (uint64)va_arg(ap, void*); + + for (i = 5; i <= num; i = i + 1) + { + sp[i] = va_arg(ap, void*); + } + + *sp = (void*)&port_longjump_stub; + regs->rsp = (uint64)sp; + regs->rip = (uint64)fn; + regs->eflags = regs->eflags & ~DIR_FLAG; +} + +void port_transfer_to_function(void* fn, Registers* pregs, int num, ...) +{ + void** sp; + va_list ap; + int i; + size_t align; + void** p_pregs; + size_t rcount = + (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); + Registers regs; + + if (!pregs) + return; + + regs = *pregs; + + sp = (void**)regs.rsp - 16 - 1; /* preserve 128-bytes area */ + *sp = (void*)regs.rip; + align = !((rcount & 1) ^ (((uint64)sp & sizeof(void*)) != 0)); + p_pregs = sp - rcount - align - 1; + sp = sp - rcount; + *((Registers*)sp) = regs; + *p_pregs = (void*)sp; + + sp = p_pregs - 6 - 1; + + va_start(ap, num); + + if (num > 0) + { + void* arg = va_arg(ap, void*); + if (arg == pregs) + regs.rcx = (uint64)(*p_pregs); /* Replace 1st arg */ + else + regs.rcx = (uint64)arg; + } + + if (num > 1) + regs.rdx = (uint64)va_arg(ap, void*); + + if (num > 2) + regs.r8 = (uint64)va_arg(ap, void*); + + if (num > 3) + regs.r9 = (uint64)va_arg(ap, void*); + + for (i = 5; i <= num; i = i + 1) + { + sp[i] = va_arg(ap, void*); + } + + *sp = (void*)&port_longjump_stub; + regs.rsp = (uint64)sp; + regs.rip = (uint64)fn; + regs.eflags = regs.eflags & ~DIR_FLAG; + + port_transfer_to_regs(®s); +} diff --git a/vm/port/src/signals/win/signals_ia32.cpp b/vm/port/src/signals/win/signals_ia32.cpp index 187645e..0417793 100644 --- a/vm/port/src/signals/win/signals_ia32.cpp +++ b/vm/port/src/signals/win/signals_ia32.cpp @@ -16,6 +16,8 @@ */ #include "signals_internal.h" +#define ANSI +#include LONG __declspec(naked) NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_exception) @@ -33,3 +35,88 @@ LONG __declspec(naked) NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_ ret 4 } } + + +extern "C" void port_longjump_stub(void); +#define DIR_FLAG ((uint32)0x00000400) + +void port_set_longjump_regs(void* fn, Registers* regs, int num, ...) +{ + void** sp; + va_list ap; + int i; + size_t rcount = + (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); + + if (!regs) + return; + + sp = (void**)regs->esp - 1; + *sp = (void*)regs->eip; + sp = sp - rcount - 1; + *((Registers*)(sp + 1)) = *regs; + *sp = (void*)(sp + 1); + regs->ebp = (uint32)sp; + + sp = sp - num - 1; + + va_start(ap, num); + + for (i = 1; i <= num; i = i + 1) + { + void* arg = va_arg(ap, void*); + + if (i == 1 && arg == regs) + sp[i] = *((void**)regs->ebp); /* Replace 1st arg */ + else + sp[i] = arg; + } + + *sp = (void*)&port_longjump_stub; + regs->esp = (uint32)sp; + regs->eip = (uint32)fn; + regs->eflags = regs->eflags & ~DIR_FLAG; +} + +void port_transfer_to_function(void* fn, Registers* pregs, int num, ...) +{ + void** sp; + va_list ap; + int i; + size_t rcount = + (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); + Registers regs; + + if (!pregs) + return; + + regs = *pregs; + + sp = (void**)regs.esp - 1; + *sp = (void*)regs.eip; + sp = sp - rcount - 1; + *((Registers*)(sp + 1)) = regs; + *sp = (void*)(sp + 1); + regs.ebp = (uint32)sp; + + sp = sp - num - 1; + + va_start(ap, num); + + for (i = 1; i <= num; i = i + 1) + { + void* arg = va_arg(ap, void*); + + if (i == 1 && arg == pregs) + sp[i] = *((void**)regs.ebp); /* Replace 1st arg */ + else + sp[i] = arg; + } + + *sp = (void*)&port_longjump_stub; + regs.esp = (uint32)sp; + regs.eip = (uint32)fn; + regs.eflags = regs.eflags & ~DIR_FLAG; + + port_transfer_to_regs(®s); +} diff --git a/vm/port/src/thread/linux/thread_em64t.c b/vm/port/src/thread/linux/thread_em64t.c index a07057d..63de96d 100644 --- a/vm/port/src/thread/linux/thread_em64t.c +++ b/vm/port/src/thread/linux/thread_em64t.c @@ -64,124 +64,3 @@ void port_thread_regs_to_context(ucontext_t *uc, Registers* regs) uc->uc_mcontext.gregs[REG_R15] = regs->r15; uc->uc_mcontext.gregs[REG_EFL] = regs->eflags; } - - -void port_longjump_stub(void); -#define DIR_FLAG ((uint32)0x00000400) - -void port_set_longjump_regs(void* fn, Registers* regs, int num, ...) -{ - void** sp; - va_list ap; - int i; - size_t align; - void** p_pregs; - size_t rcount = - (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); - - if (!regs) - return; - - sp = (void**)regs->rsp - 16 - 1; /* preserve 128-bytes 'red zone' */ - *sp = (void*)regs->rip; - align = !((rcount & 1) ^ (((uint64)sp & sizeof(void*)) != 0)); - p_pregs = sp - rcount - align - 1; - sp = sp - rcount; - *((Registers*)sp) = *regs; - *p_pregs = (void*)sp; - -// sp = p_pregs - 16 - 1; /* preserve 128-bytes 'red zone' */ - sp = p_pregs - 1; /* set sp to return address */ - - va_start(ap, num); - - if (num > 0) - { - void* arg = va_arg(ap, void*); - if (arg == regs) - regs->rdi = (uint64)(*p_pregs); /* Replace 1st arg */ - else - regs->rdi = (uint64)arg; - } - - if (num > 1) - regs->rsi = (uint64)va_arg(ap, void*); - - if (num > 2) - regs->rdx = (uint64)va_arg(ap, void*); - - if (num > 3) - regs->rcx = (uint64)va_arg(ap, void*); - - if (num > 4) - regs->r8 = (uint64)va_arg(ap, void*); - - if (num > 5) - regs->r9 = (uint64)va_arg(ap, void*); - - *sp = (void*)&port_longjump_stub; - regs->rsp = (uint64)sp; - regs->rip = (uint64)fn; - regs->eflags = regs->eflags & ~DIR_FLAG; -} - -void port_transfer_to_function(void* fn, Registers* pregs, int num, ...) -{ - void** sp; - va_list ap; - int i; - size_t align; - void** p_pregs; - size_t rcount = - (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); - Registers regs; - - if (!pregs) - return; - - regs = *pregs; - - sp = (void**)regs.rsp - 16 - 1; /* preserve 128-bytes 'red zone' */ - *sp = (void*)regs.rip; - align = !((rcount & 1) ^ (((uint64)sp & sizeof(void*)) != 0)); - p_pregs = sp - rcount - align - 1; - sp = sp - rcount; - *((Registers*)sp) = regs; - *p_pregs = (void*)sp; - -// sp = p_pregs - 16 - 1; /* preserve 128-bytes 'red zone' */ - sp = p_pregs - 1; /* set sp to return address */ - - va_start(ap, num); - - if (num > 0) - { - void* arg = va_arg(ap, void*); - if (arg == pregs) - regs.rdi = (uint64)(*p_pregs); /* Replace 1st arg */ - else - regs.rdi = (uint64)arg; - } - - if (num > 1) - regs.rsi = (uint64)va_arg(ap, void*); - - if (num > 2) - regs.rdx = (uint64)va_arg(ap, void*); - - if (num > 3) - regs.rcx = (uint64)va_arg(ap, void*); - - if (num > 4) - regs.r8 = (uint64)va_arg(ap, void*); - - if (num > 5) - regs.r9 = (uint64)va_arg(ap, void*); - - *sp = (void*)&port_longjump_stub; - regs.rsp = (uint64)sp; - regs.rip = (uint64)fn; - regs.eflags = regs.eflags & ~DIR_FLAG; - - port_transfer_to_regs(®s); -} diff --git a/vm/port/src/thread/linux/thread_ia32.c b/vm/port/src/thread/linux/thread_ia32.c index 45ad9bc..29b8340 100644 --- a/vm/port/src/thread/linux/thread_ia32.c +++ b/vm/port/src/thread/linux/thread_ia32.c @@ -83,88 +83,3 @@ void port_thread_regs_to_context(ucontext_t *uc, Registers* regs) #else #error need to add correct mcontext_t lookup for registers #endif - - -void port_longjump_stub(void); -#define DIR_FLAG ((uint32)0x00000400) - -void port_set_longjump_regs(void* fn, Registers* regs, int num, ...) -{ - void** sp; - va_list ap; - int i; - size_t rcount = - (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); - - if (!regs) - return; - - sp = (void**)regs->esp - 1; - *sp = (void*)regs->eip; - sp = sp - rcount - 1; - *((Registers*)(sp + 1)) = *regs; - *sp = (void*)(sp + 1); - regs->ebp = (uint32)sp; - - sp = sp - num - 1; - - va_start(ap, num); - - for (i = 1; i <= num; i = i + 1) - { - void* arg = va_arg(ap, void*); - - if (i == 1 && arg == regs) - sp[i] = *((void**)regs->ebp); /* Replace 1st arg */ - else - sp[i] = arg; - } - - *sp = (void*)&port_longjump_stub; - regs->esp = (uint32)sp; - regs->eip = (uint32)fn; - regs->eflags = regs->eflags & ~DIR_FLAG; -} - -void port_transfer_to_function(void* fn, Registers* pregs, int num, ...) -{ - void** sp; - va_list ap; - int i; - size_t rcount = - (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); - Registers regs; - - if (!pregs) - return; - - regs = *pregs; - - sp = (void**)regs.esp - 1; - *sp = (void*)regs.eip; - sp = sp - rcount - 1; - *((Registers*)(sp + 1)) = regs; - *sp = (void*)(sp + 1); - regs.ebp = (uint32)sp; - - sp = sp - num - 1; - - va_start(ap, num); - - for (i = 1; i <= num; i = i + 1) - { - void* arg = va_arg(ap, void*); - - if (i == 1 && arg == pregs) - sp[i] = *((void**)regs.ebp); /* Replace 1st arg */ - else - sp[i] = arg; - } - - *sp = (void*)&port_longjump_stub; - regs.esp = (uint32)sp; - regs.eip = (uint32)fn; - regs.eflags = regs.eflags & ~DIR_FLAG; - - port_transfer_to_regs(®s); -} diff --git a/vm/port/src/thread/linux/thread_ipf.c b/vm/port/src/thread/linux/thread_ipf.c index 6497900..2cb2072 100644 --- a/vm/port/src/thread/linux/thread_ipf.c +++ b/vm/port/src/thread/linux/thread_ipf.c @@ -22,14 +22,6 @@ #include "port_thread.h" -void port_transfer_to_regs(Registers* regs) -{ - // FIXME: not implemented - fprintf(stderr, "FIXME: port_transfer_to_regs: not implemented\n"); - assert(0); - abort(); -} - void port_thread_context_to_regs(Registers* regs, ucontext_t* uc) { memcpy(regs->gr, uc->uc_mcontext.sc_gr, sizeof(regs->gr)); @@ -55,19 +47,3 @@ void port_thread_regs_to_context(ucontext_t* uc, Registers* regs) uc->uc_mcontext.sc_ar_bsp = (uint64)regs->bsp; uc->uc_mcontext.sc_ip = regs->ip; } - -void port_set_longjump_regs(void* fn, Registers* regs, int num, ...) -{ - // FIXME: not implemented - fprintf(stderr, "FIXME: port_set_longjump_regs: not implemented\n"); - assert(0); - abort(); -} - -void port_transfer_to_function(void* fn, Registers* pregs, int num, ...) -{ - // FIXME: not implemented - fprintf(stderr, "FIXME: port_transfer_to_function: not implemented\n"); - assert(0); - abort(); -} diff --git a/vm/port/src/thread/win/thread_asm_em64t.asm b/vm/port/src/thread/win/thread_asm_em64t.asm deleted file mode 100644 index 3f5a453..0000000 --- a/vm/port/src/thread/win/thread_asm_em64t.asm +++ /dev/null @@ -1,133 +0,0 @@ -; -; Licensed to the Apache Software Foundation (ASF) under one or more -; contributor license agreements. See the NOTICE file distributed with -; this work for additional information regarding copyright ownership. -; The ASF licenses this file to You under the Apache License, Version 2.0 -; (the "License"); you may not use this file except in compliance with -; the License. You may obtain a copy of the License at -; -; http://www.apache.org/licenses/LICENSE-2.0 -; -; Unless required by applicable law or agreed to in writing, software -; distributed under the License is distributed on an "AS IS" BASIS, -; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -; See the License for the specific language governing permissions and -; limitations under the License. - - -_TEXT SEGMENT - -; struct Registers { -; uint64 rsp; ; 00h -; uint64 rbp; ; 08h -; uint64 rip; ; 10h -; // callee-saved -; uint64 rbx; ; 18h -; uint64 r12; ; 20h -; uint64 r13; ; 28h -; uint64 r14; ; 30h -; uint64 r15; ; 38h -; // scratched -; uint64 rax; ; 40h -; uint64 rcx; ; 48h -; uint64 rdx; ; 50h -; uint64 rsi; ; 58h -; uint64 rdi; ; 60h -; uint64 r8; ; 68h -; uint64 r9; ; 70h -; uint64 r10; ; 78h -; uint64 r11; ; 80h -; -; uint32 eflags;; 88h -; }; -; -; void port_transfer_to_regs(Registers* regs) - -PUBLIC port_transfer_to_regs - -port_transfer_to_regs PROC - - mov rdx, rcx ; regs pointer (1st param - RCX) -> RDX - - mov rbp, qword ptr [rdx+08h] ; RBP field - mov rbx, qword ptr [rdx+18h] ; RBX field - mov r12, qword ptr [rdx+20h] ; R12 field - mov r13, qword ptr [rdx+28h] ; R13 field - mov r14, qword ptr [rdx+30h] ; R14 field - mov r15, qword ptr [rdx+38h] ; R15 field - mov rsi, qword ptr [rdx+58h] ; RSI field - mov rdi, qword ptr [rdx+60h] ; RDI field - mov r8, qword ptr [rdx+68h] ; R8 field - mov r9, qword ptr [rdx+70h] ; R9 field - mov r10, qword ptr [rdx+78h] ; R10 field - mov r11, qword ptr [rdx+80h] ; R11 field - - mov rax, qword ptr [rdx+00h] ; (new RSP) -> RAX - mov qword ptr [rsp], rax ; (new RSP) -> [RSP] for future use - mov rcx, qword ptr [rdx+10h] ; (new RIP) -> RCX - mov qword ptr [rax-88h],rcx ; (new RIP) -> [(new RSP) - 128 - 8] - mov rax, qword ptr [rdx+40h] ; RAX field - - movzx rcx, word ptr [rdx+88h] ; (word)EFLAGS -> RCX - test rcx, rcx - je __skipefl__ - pushfq - and dword ptr [rsp], 003F7202h ; Clear OF, DF, TF, SF, ZF, AF, PF, CF - and ecx, 00000CD5h ; Clear all except OF, DF, SF, ZF, AF, PF, CF - or dword ptr [rsp], ecx - popfq ; restore RFLAGS -__skipefl__: - - mov rcx, qword ptr [rdx+48h] ; RCX field - mov rdx, qword ptr [rdx+50h] ; RDX field - - mov rsp, qword ptr [rsp] ; load new RSP - jmp qword ptr [rsp-88h] ; JMP to new RIP - -port_transfer_to_regs ENDP - - -; void port_longjump_stub(void) -; -; after returning from the called function, RSP points to the 2 argument -; slots in the stack. Saved Registers structure pointer is (RSP + 48) -; -; | interrupted | -; | program | <- RSP where the program was interrupted by exception -; |-------------| -; | 0x80 bytes | <- preserved stack area - we will not change it -; |-------------| -; | return addr | -; | from stub | <- for using in port_transfer_to_regs as [(new RSP) - 128 - 8] -; |-------------| -; | saved | -; | Registers | <- to restore register context -; |-------------| -; | [alignment] | <- align Regs pointer to 16-bytes boundary -; |-------------| -; | pointer to | -; | saved Regs | <- (RSP + 48) -; |-------------| -; | arg 5 | <- present even if not used -; |-------------| -; | arg 4 | <- present even if not used -; |-------------| -; | 32 bytes | <- 'red zone' for argument registers flushing -; |-------------| -; | return addr | -; | from 'fn' | <- address to return to the port_longjump_stub -; |-------------| - -PUBLIC port_longjump_stub - -port_longjump_stub PROC - - mov rcx, qword ptr [rsp + 48] ; load RCX with the address of saved Registers - call port_transfer_to_regs ; restore context - ret ; dummy RET - unreachable -port_longjump_stub ENDP - - -_TEXT ENDS - -END diff --git a/vm/port/src/thread/win/thread_em64t.c b/vm/port/src/thread/win/thread_em64t.c index ab51f75..206a37d 100644 --- a/vm/port/src/thread/win/thread_em64t.c +++ b/vm/port/src/thread/win/thread_em64t.c @@ -67,125 +67,3 @@ void port_thread_regs_to_context(PCONTEXT pcontext, Registers* regs) pcontext->EFlags = regs->eflags; } - -void* regs_get_sp(Registers* pregs) -{ - return (void*)pregs->rsp; -} - - -void port_longjump_stub(void); -#define DIR_FLAG ((uint32)0x00000400) - -void port_set_longjump_regs(void* fn, Registers* regs, int num, ...) -{ - void** sp; - va_list ap; - int i; - size_t align; - void** p_pregs; - size_t rcount = - (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); - - if (!regs) - return; - - sp = (void**)regs->rsp - 16 - 1; /* preserve 128-bytes area */ - *sp = (void*)regs->rip; - align = !((rcount & 1) ^ (((uint64)sp & sizeof(void*)) != 0)); - p_pregs = sp - rcount - align - 1; - sp = sp - rcount; - *((Registers*)sp) = *regs; - *p_pregs = (void*)sp; - - sp = p_pregs - 6 - 1; - - va_start(ap, num); - - if (num > 0) - { - void* arg = va_arg(ap, void*); - if (arg == regs) - regs->rcx = (uint64)(*p_pregs); /* Replace 1st arg */ - else - regs->rcx = (uint64)arg; - } - - if (num > 1) - regs->rdx = (uint64)va_arg(ap, void*); - - if (num > 2) - regs->r8 = (uint64)va_arg(ap, void*); - - if (num > 3) - regs->r9 = (uint64)va_arg(ap, void*); - - for (i = 5; i <= num; i = i + 1) - { - sp[i] = va_arg(ap, void*); - } - - *sp = (void*)&port_longjump_stub; - regs->rsp = (uint64)sp; - regs->rip = (uint64)fn; - regs->eflags = regs->eflags & ~DIR_FLAG; -} - -void port_transfer_to_function(void* fn, Registers* pregs, int num, ...) -{ - void** sp; - va_list ap; - int i; - size_t align; - void** p_pregs; - size_t rcount = - (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); - Registers regs; - - if (!pregs) - return; - - regs = *pregs; - - sp = (void**)regs.rsp - 16 - 1; /* preserve 128-bytes area */ - *sp = (void*)regs.rip; - align = !((rcount & 1) ^ (((uint64)sp & sizeof(void*)) != 0)); - p_pregs = sp - rcount - align - 1; - sp = sp - rcount; - *((Registers*)sp) = regs; - *p_pregs = (void*)sp; - - sp = p_pregs - 6 - 1; - - va_start(ap, num); - - if (num > 0) - { - void* arg = va_arg(ap, void*); - if (arg == pregs) - regs.rcx = (uint64)(*p_pregs); /* Replace 1st arg */ - else - regs.rcx = (uint64)arg; - } - - if (num > 1) - regs.rdx = (uint64)va_arg(ap, void*); - - if (num > 2) - regs.r8 = (uint64)va_arg(ap, void*); - - if (num > 3) - regs.r9 = (uint64)va_arg(ap, void*); - - for (i = 5; i <= num; i = i + 1) - { - sp[i] = va_arg(ap, void*); - } - - *sp = (void*)&port_longjump_stub; - regs.rsp = (uint64)sp; - regs.rip = (uint64)fn; - regs.eflags = regs.eflags & ~DIR_FLAG; - - port_transfer_to_regs(®s); -} diff --git a/vm/port/src/thread/win/thread_ia32.c b/vm/port/src/thread/win/thread_ia32.c index d97c9d7..82d7a1b 100644 --- a/vm/port/src/thread/win/thread_ia32.c +++ b/vm/port/src/thread/win/thread_ia32.c @@ -47,88 +47,3 @@ void port_thread_regs_to_context(PCONTEXT context, Registers* regs) context->Edx = regs->edx; context->EFlags = regs->eflags; } - - -void port_longjump_stub(void); -#define DIR_FLAG ((uint32)0x00000400) - -void port_set_longjump_regs(void* fn, Registers* regs, int num, ...) -{ - void** sp; - va_list ap; - int i; - size_t rcount = - (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); - - if (!regs) - return; - - sp = (void**)regs->esp - 1; - *sp = (void*)regs->eip; - sp = sp - rcount - 1; - *((Registers*)(sp + 1)) = *regs; - *sp = (void*)(sp + 1); - regs->ebp = (uint32)sp; - - sp = sp - num - 1; - - va_start(ap, num); - - for (i = 1; i <= num; i = i + 1) - { - void* arg = va_arg(ap, void*); - - if (i == 1 && arg == regs) - sp[i] = *((void**)regs->ebp); /* Replace 1st arg */ - else - sp[i] = arg; - } - - *sp = (void*)&port_longjump_stub; - regs->esp = (uint32)sp; - regs->eip = (uint32)fn; - regs->eflags = regs->eflags & ~DIR_FLAG; -} - -void port_transfer_to_function(void* fn, Registers* pregs, int num, ...) -{ - void** sp; - va_list ap; - int i; - size_t rcount = - (sizeof(Registers) + sizeof(void*) - 1) / sizeof(void*); - Registers regs; - - if (!pregs) - return; - - regs = *pregs; - - sp = (void**)regs.esp - 1; - *sp = (void*)regs.eip; - sp = sp - rcount - 1; - *((Registers*)(sp + 1)) = regs; - *sp = (void*)(sp + 1); - regs.ebp = (uint32)sp; - - sp = sp - num - 1; - - va_start(ap, num); - - for (i = 1; i <= num; i = i + 1) - { - void* arg = va_arg(ap, void*); - - if (i == 1 && arg == pregs) - sp[i] = *((void**)regs.ebp); /* Replace 1st arg */ - else - sp[i] = arg; - } - - *sp = (void*)&port_longjump_stub; - regs.esp = (uint32)sp; - regs.eip = (uint32)fn; - regs.eflags = regs.eflags & ~DIR_FLAG; - - port_transfer_to_regs(®s); -} diff --git a/vm/port/src/thread/win/thread_os.c b/vm/port/src/thread/win/thread_os.c index f59b307..a83c63b 100644 --- a/vm/port/src/thread/win/thread_os.c +++ b/vm/port/src/thread/win/thread_os.c @@ -16,7 +16,7 @@ */ -#include +#include #include "port_thread.h" @@ -297,13 +297,13 @@ int port_thread_set_context(osthread_t thread, thread_context_t *context) static int suspend_init_lock() { - static uint32 initialized = 0; + static uint16 initialized = 0; if (!initialized) { // Critical section should be initialized only once, // do nothing in case someone else already initialized it. - if (apr_atomic_cas32((volatile uint32*)&initialized, 1, 0) == 0) + if (port_atomic_cas16((volatile uint16*)&initialized, 1, 0) == 0) InitializeCriticalSectionAndSpinCount(&g_crit_section, 400); } -- 1.5.4