Merge pull request #2091 from kumpera/tvos_context_get_current
authorZoltan Varga <vargaz@gmail.com>
Thu, 24 Sep 2015 23:20:07 +0000 (19:20 -0400)
committerZoltan Varga <vargaz@gmail.com>
Thu, 24 Sep 2015 23:20:07 +0000 (19:20 -0400)
[tvos] Implement MONO_CONTEXT_GET_CURRENT for tvos

mono/utils/Makefile.am
mono/utils/mach-support-amd64.c
mono/utils/mach-support-arm.c
mono/utils/mach-support-arm64.c [new file with mode: 0644]
mono/utils/mach-support-unknown.c
mono/utils/mach-support-x86.c
mono/utils/mach-support.h
mono/utils/mono-context.h

index c1f632eba51d9f35abd65bfd617a98d4da706004..0b465253d540e4a65129326cf84065755f0927f7 100644 (file)
@@ -166,7 +166,7 @@ arch_sources += mach-support-arm.c
 endif
 
 if ARM64
-arch_sources += mach-support-arm.c
+arch_sources += mach-support-arm64.c
 endif
 
 else
index 7944e2c986b68ceaa2dd2b86cb2fc5d3946f2d15..1802ff79f5364d8301566717bc2da54b5bcad12d 100644 (file)
@@ -18,6 +18,9 @@
 #include "utils/mono-sigcontext.h"
 #include "mach-support.h"
 
+//For reg numbers
+#include <mono/arch/amd64/amd64-codegen.h>
+
 /* Known offsets used for TLS storage*/
 
 /* All OSX versions up to 10.8 */
@@ -73,6 +76,28 @@ mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state)
        *arch_state = ctx->__ss;
 }
 
+void
+mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext *context)
+{
+       x86_thread_state64_t *arch_state = (x86_thread_state64_t *) state;
+       context->gregs [AMD64_RAX] = arch_state->__rax;
+       context->gregs [AMD64_RBX] = arch_state->__rbx;
+       context->gregs [AMD64_RCX] = arch_state->__rcx;
+       context->gregs [AMD64_RDX] = arch_state->__rdx;
+       context->gregs [AMD64_RDI] = arch_state->__rdi;
+       context->gregs [AMD64_RBP] = arch_state->__rbp;
+       context->gregs [AMD64_RSP] = arch_state->__rsp;
+       context->gregs [AMD64_R8] = arch_state->__r8;
+       context->gregs [AMD64_R9] = arch_state->__r9;
+       context->gregs [AMD64_R10] = arch_state->__r10;
+       context->gregs [AMD64_R11] = arch_state->__r11;
+       context->gregs [AMD64_R12] = arch_state->__r12;
+       context->gregs [AMD64_R13] = arch_state->__r13;
+       context->gregs [AMD64_R14] = arch_state->__r14;
+       context->gregs [AMD64_R15] = arch_state->__r15;
+       context->gregs [AMD64_RIP] = arch_state->__rip;
+}
+
 int
 mono_mach_arch_get_thread_state_size ()
 {
index ef5e6f1f250e25496796b48106f8e41558660735..bedadbcdd83318b175876de99e13e41063d1a6b9 100644 (file)
@@ -46,81 +46,61 @@ void *
 mono_mach_arch_get_ip (thread_state_t state)
 {
        /* Can't use unified_thread_state on !ARM64 since this has to compile on armv6 too */
-#ifdef TARGET_ARM64
-       arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state;
-
-       return (void *) arch_state->ts_64.__pc;
-#else
        arm_thread_state_t *arch_state = (arm_thread_state_t *) state;
 
        return (void *) arch_state->__pc;
-#endif
 }
 
 void *
 mono_mach_arch_get_sp (thread_state_t state)
 {
-#ifdef TARGET_ARM64
-       arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state;
-
-       return (void *) arch_state->ts_64.__sp;
-#else
        arm_thread_state_t *arch_state = (arm_thread_state_t *) state;
 
        return (void *) arch_state->__sp;
-#endif
 }
 
 int
 mono_mach_arch_get_mcontext_size ()
 {
-#ifdef TARGET_ARM64
-       return sizeof (struct __darwin_mcontext64);
-#else
        return sizeof (struct __darwin_mcontext);
-#endif
 }
 
 void
 mono_mach_arch_thread_state_to_mcontext (thread_state_t state, void *context)
 {
-#ifdef TARGET_ARM64
-       arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state;
-       struct __darwin_mcontext64 *ctx = (struct __darwin_mcontext64 *) context;
-
-       ctx->__ss = arch_state->ts_64;
-#else
        arm_thread_state_t *arch_state = (arm_thread_state_t *) state;
        struct __darwin_mcontext *ctx = (struct __darwin_mcontext *) context;
 
        ctx->__ss = *arch_state;
-#endif
 }
 
 void
 mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state)
 {
-#ifdef TARGET_ARM64
-       arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state;
-       struct __darwin_mcontext64 *ctx = (struct __darwin_mcontext64 *) context;
-
-       arch_state->ts_64 = ctx->__ss;
-#else
        arm_thread_state_t *arch_state = (arm_thread_state_t *) state;
        struct __darwin_mcontext *ctx = (struct __darwin_mcontext *) context;
 
        *arch_state = ctx->__ss;
-#endif
+}
+
+void
+mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext *context)
+{
+       int i;
+       arm_thread_state_t *arch_state = (x86_thread_state64_t *) state;
+       for (i = 0; i < 13; ++i)
+               context->regs [i] = arch_state->__r [i];
+       context->regs [ARMREG_R13] = arch_state->__sp;
+       context->regs [ARMREG_R14] = arch_state->__lr;
+       context->regs [ARMREG_R15] = arch_state->__pc;
+       context->pc = arch_state->__pc;
+       context->cpsr = arch_state->__cpsr;
 }
 
 int
 mono_mach_arch_get_thread_state_size ()
 {
-#ifdef TARGET_ARM64
-       return sizeof (arm_unified_thread_state_t);
-#else
        return sizeof (arm_thread_state_t);
-#endif
 }
 
 kern_return_t
@@ -129,21 +109,12 @@ mono_mach_arch_get_thread_state (thread_port_t thread, thread_state_t state, mac
 #if defined(HOST_WATCHOS)
        g_error ("thread_get_state() is not supported by this platform");
 #else  
-#ifdef TARGET_ARM64
-       arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state;
-       kern_return_t ret;
-
-       *count = ARM_UNIFIED_THREAD_STATE_COUNT;
-
-       ret = thread_get_state (thread, ARM_UNIFIED_THREAD_STATE, (thread_state_t) arch_state, count);
-#else
        arm_thread_state_t *arch_state = (arm_thread_state_t *) state;
        kern_return_t ret;
 
        *count = ARM_THREAD_STATE_COUNT;
 
        ret = thread_get_state (thread, ARM_THREAD_STATE, (thread_state_t) arch_state, count);
-#endif
        return ret;
 #endif
 }
@@ -153,13 +124,9 @@ mono_mach_arch_set_thread_state (thread_port_t thread, thread_state_t state, mac
 {
 #if defined(HOST_WATCHOS)
        g_error ("thread_set_state() is not supported by this platform");
-#else
-#ifdef TARGET_ARM64
-       return thread_set_state (thread, ARM_UNIFIED_THREAD_STATE, state, count);
 #else
        return thread_set_state (thread, ARM_THREAD_STATE, state, count);
 #endif
-#endif
 }
 
 void *
diff --git a/mono/utils/mach-support-arm64.c b/mono/utils/mach-support-arm64.c
new file mode 100644 (file)
index 0000000..a1ef2e2
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * mach-support-arm.c: mach support for ARM
+ *
+ * Authors:
+ *   Geoff Norton (gnorton@novell.com)
+ *   Rodrigo Kumpera (kumpera@gmail.com)
+ *
+ * (C) 2010 Novell, Inc.
+ * (C) 2011 Xamarin, Inc.
+ */
+
+#include <config.h>
+
+#if defined(__MACH__)
+#include <stdint.h>
+#include <glib.h>
+#include <pthread.h>
+#include "utils/mono-sigcontext.h"
+#include "utils/mono-compiler.h"
+#include "mach-support.h"
+
+/* _mcontext.h now defines __darwin_mcontext32, not __darwin_mcontext, starting with Xcode 5.1 */
+#ifdef _STRUCT_MCONTEXT32
+       #define __darwin_mcontext       __darwin_mcontext32
+#endif
+
+/* Known offsets used for TLS storage*/
+
+
+static const int known_tls_offsets[] = {
+       0x48, /*Found on iOS 6 */
+       0xA4,
+       0xA8,
+};
+
+#define TLS_PROBE_COUNT (sizeof (known_tls_offsets) / sizeof (int))
+
+/* This is 2 slots less than the known low */
+#define TLS_PROBE_LOW_WATERMARK 0x40
+/* This is 24 slots above the know high, which is the same diff as the knowns high-low*/
+#define TLS_PROBE_HIGH_WATERMARK 0x108
+
+static int tls_vector_offset;
+
+void *
+mono_mach_arch_get_ip (thread_state_t state)
+{
+       /* Can't use unified_thread_state on !ARM64 since this has to compile on armv6 too */
+       arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state;
+
+       return (void *) arch_state->ts_64.__pc;
+}
+
+void *
+mono_mach_arch_get_sp (thread_state_t state)
+{
+       arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state;
+
+       return (void *) arch_state->ts_64.__sp;
+}
+
+int
+mono_mach_arch_get_mcontext_size ()
+{
+       return sizeof (struct __darwin_mcontext64);
+}
+
+void
+mono_mach_arch_thread_state_to_mcontext (thread_state_t state, void *context)
+{
+       arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state;
+       struct __darwin_mcontext64 *ctx = (struct __darwin_mcontext64 *) context;
+
+       ctx->__ss = arch_state->ts_64;
+}
+
+void
+mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state)
+{
+       arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state;
+       struct __darwin_mcontext64 *ctx = (struct __darwin_mcontext64 *) context;
+
+       arch_state->ts_64 = ctx->__ss;
+}
+
+void
+mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext *context)
+{
+       int i;
+       arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state;
+       for (i = 0; i < 29; ++i)
+               context->regs [i] = arch_state->uts.ts_64.__x [i];
+
+       context->regs [ARMREG_R29] = arch_state->uts.ts_64.__fp;
+       context->regs [ARMREG_R30] = arch_state->uts.ts_64.__lr;
+       context->regs [ARMREG_R31] = arch_state->uts.ts_64.__sp;
+       context->pc = arch_state->uts.ts_64.__pc;
+}
+
+int
+mono_mach_arch_get_thread_state_size ()
+{
+       return sizeof (arm_unified_thread_state_t);
+}
+
+kern_return_t
+mono_mach_arch_get_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t *count)
+{
+       arm_unified_thread_state_t *arch_state = (arm_unified_thread_state_t *) state;
+       kern_return_t ret;
+
+       *count = ARM_UNIFIED_THREAD_STATE_COUNT;
+
+       ret = thread_get_state (thread, ARM_UNIFIED_THREAD_STATE, (thread_state_t) arch_state, count);
+       return ret;
+}
+
+kern_return_t
+mono_mach_arch_set_thread_state (thread_port_t thread, thread_state_t state, mach_msg_type_number_t count)
+{
+       return thread_set_state (thread, ARM_UNIFIED_THREAD_STATE, state, count);
+}
+
+void *
+mono_mach_get_tls_address_from_thread (pthread_t thread, pthread_key_t key)
+{
+       /* Mach stores TLS values in a hidden array inside the pthread_t structure
+        * They are keyed off a giant array from a known offset into the pointer. This value
+        * is baked into their pthread_getspecific implementation
+        */
+       intptr_t *p = (intptr_t *) thread;
+       intptr_t **tsd = (intptr_t **) ((char*)p + tls_vector_offset);
+       g_assert (tls_vector_offset != -1);
+
+       return (void *) &tsd [key];
+}
+
+void *
+mono_mach_arch_get_tls_value_from_thread (pthread_t thread, guint32 key)
+{
+       return *(void**)mono_mach_get_tls_address_from_thread (thread, key);
+}
+
+void
+mono_mach_init (pthread_key_t key)
+{
+       int i;
+       void *old_value = pthread_getspecific (key);
+       void *canary = (void*)0xDEADBEEFu;
+
+       pthread_key_create (&key, NULL);
+       g_assert (old_value != canary);
+
+       pthread_setspecific (key, canary);
+
+       /*First we probe for cats*/
+       for (i = 0; i < TLS_PROBE_COUNT; ++i) {
+               tls_vector_offset = known_tls_offsets [i];
+               if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary)
+                       goto ok;
+       }
+
+       /*Fallback to scanning a large range of offsets*/
+       for (i = TLS_PROBE_LOW_WATERMARK; i <= TLS_PROBE_HIGH_WATERMARK; i += 4) {
+               tls_vector_offset = i;
+               if (mono_mach_arch_get_tls_value_from_thread (pthread_self (), key) == canary) {
+                       g_warning ("Found new TLS offset at %d", i);
+                       goto ok;
+               }
+       }
+
+       tls_vector_offset = -1;
+       g_warning ("could not discover the mach TLS offset");
+ok:
+       pthread_setspecific (key, old_value);
+}
+
+#endif
index 9fece2272160425161aa10e057a593e3183ab9e8..20012550114610c911623f8a0cbdf9af0197c277 100644 (file)
@@ -46,6 +46,11 @@ mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state)
        g_assert_not_reached ();
 }
 
+void
+mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext *context)
+{
+       g_assert_not_reached ();
+}
 
 int
 mono_mach_arch_get_thread_state_size ()
index 5650e8b92c916b7a584ccfe073d9e915a30ff489..3e8b166eaf2b51a7dc69f49d889c896762d75732 100644 (file)
@@ -72,6 +72,22 @@ mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state)
        *arch_state = ctx->__ss;
 }
 
+void
+mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext *context)
+{
+       x86_thread_state32_t *arch_state = (x86_thread_state32_t *) state;
+       context->eax = arch_state->__eax;
+       context->ebx = arch_state->__ebx;
+       context->ecx = arch_state->__ecx;
+       context->edx = arch_state->__edx;
+       context->ebp = arch_state->__ebp;
+       context->esp = arch_state->__esp;
+       context->esi = arch_state->__edi;
+       context->edi = arch_state->__esi;
+       context->eip = arch_state->__eip;
+}
+
+
 int
 mono_mach_arch_get_thread_state_size ()
 {
index 940cf0356a0cc9fa9da40490296fc52855cb5b5f..abc135bd4eb8eb9987db2bb56f5bbf6aadf59093 100644 (file)
@@ -6,6 +6,7 @@
 #include <glib.h>
 #include <pthread.h>
 #include "mono/utils/mono-compiler.h"
+#include "mono/utils/mono-context.h"
 #include <mach/task.h>
 #include <mach/mach_port.h>
 #include <mach/mach_init.h>
@@ -30,6 +31,7 @@ void mono_mach_init (pthread_key_t key);
 int mono_mach_arch_get_mcontext_size (void);
 void mono_mach_arch_thread_state_to_mcontext (thread_state_t state, void *context);
 void mono_mach_arch_mcontext_to_thread_state (void *context, thread_state_t state);
+void mono_mach_arch_thread_state_to_mono_context (thread_state_t state, MonoContext *context);
 
 int mono_mach_arch_get_thread_state_size (void);
 kern_return_t mono_mach_get_threads (thread_act_array_t *threads, guint32 *count);
index 6faaedf14aa57923cb1ad81259136ab09f2ecb39..0f1e4691b6ae7f5b5cc44a1ed8149fca4d49b075 100644 (file)
@@ -304,8 +304,14 @@ typedef struct {
 #if defined (HOST_APPLETVOS)
 
 #define MONO_CONTEXT_GET_CURRENT(ctx) do { \
-       fprintf (stderr, "MONO_CONTEXT_GET_CURRENT: Not implemented"); \
-       g_error ("MONO_CONTEXT_GET_CURRENT: Not implemented"); \
+       arm_unified_thread_state_t thread_state;        \
+       int state_flavor = ARM_UNIFIED_THREAD_STATE;    \
+       unsigned state_count = ARM_UNIFIED_THREAD_STATE_COUNT;  \
+       thread_port_t self = mach_thread_self ();       \
+       kern_return_t ret = thread_get_state (self, state_flavor, (thread_state_t) &thread_state, &state_count);        \
+       g_assert (ret == 0);    \
+       mono_mach_arch_thread_state_to_mono_context (&thread_state, &ctx);      \
+       mach_port_deallocate (current_task (), self);   \
 } while (0);
 
 #else