]> sourceware.org Git - newlib-cygwin.git/commitdiff
Implement getcontext, setcontext, makecontext, swapcontext
authorCorinna Vinschen <corinna@vinschen.de>
Fri, 17 Jul 2015 12:31:12 +0000 (14:31 +0200)
committerCorinna Vinschen <corinna@vinschen.de>
Fri, 17 Jul 2015 12:31:12 +0000 (14:31 +0200)
        * common.din (getcontext): Export.
        (makecontext): Export.
        (setcontext): Export.
        (swapcontext): Export.
        * exceptions.cc (__unwind_single_frame): New static functions, 64 bit
        only.
        (setcontext): New function.
        (getcontext): New function.
        (swapcontext): New function.
        (__cont_link_context): New function.
        (makecontext): New function.
        * include/cygwin/version.h (CYGWIN_VERSION_DLL_MAJOR): Bump to 2002.
        (CYGWIN_VERSION_API_MINOR): Bump.
        * include/ucontext.h (getcontext): Add prototype.
        (setcontext): Ditto.
        (swapcontext): Ditto.
        (makecontext): Ditto.
        * ntdll.h (NtContinue): Ditto.

        * new-features.xml (ov-new2.2): Add new section.  Document getcontext,
        setcontext, makecontext, swapcontext.
        * posix.xml (std-deprec): Add getcontext, setcontext, makecontext,
        swapcontext.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
winsup/cygwin/ChangeLog
winsup/cygwin/common.din
winsup/cygwin/exceptions.cc
winsup/cygwin/include/cygwin/version.h
winsup/cygwin/include/ucontext.h
winsup/cygwin/ntdll.h
winsup/cygwin/release/2.2.0 [new file with mode: 0644]
winsup/doc/ChangeLog
winsup/doc/new-features.xml
winsup/doc/posix.xml

index db7d723c3b6c56703d41fe092a2343537409f803..f2aabf706f018853ac9a6201e148ebdda2da5f7d 100644 (file)
@@ -1,3 +1,24 @@
+2015-07-17  Corinna Vinschen  <corinna@vinschen.de>
+
+       * common.din (getcontext): Export.
+       (makecontext): Export.
+       (setcontext): Export.
+       (swapcontext): Export.
+       * exceptions.cc (__unwind_single_frame): New static functions, 64 bit
+       only.
+       (setcontext): New function.
+       (getcontext): New function.
+       (swapcontext): New function.
+       (__cont_link_context): New function.
+       (makecontext): New function.
+       * include/cygwin/version.h (CYGWIN_VERSION_DLL_MAJOR): Bump to 2002.
+       (CYGWIN_VERSION_API_MINOR): Bump.
+       * include/ucontext.h (getcontext): Add prototype.
+       (setcontext): Ditto.
+       (swapcontext): Ditto.
+       (makecontext): Ditto.
+       * ntdll.h (NtContinue): Ditto.
+
 2015-07-17  Corinna Vinschen  <corinna@vinschen.de>
 
        * include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Document the
index 644eb2eaea37ec53a0b0d10164e2ca62c651dba8..e89a6bdb7f44fa094edb0f74fc2523d7cd93eca2 100644 (file)
@@ -503,6 +503,7 @@ getc SIGFE
 getc_unlocked SIGFE
 getchar SIGFE
 getchar_unlocked SIGFE
+getcontext NOSIGFE
 getcwd SIGFE
 getdelim = __getdelim SIGFE
 getdomainname SIGFE
@@ -717,6 +718,7 @@ lsetxattr SIGFE
 lstat SIGFE
 lutimes SIGFE
 madvise = posix_madvise SIGFE
+makecontext NOSIGFE
 mallinfo SIGFE
 malloc SIGFE
 malloc_stats SIGFE
@@ -1054,6 +1056,7 @@ sendmsg = cygwin_sendmsg SIGFE
 sendto = cygwin_sendto SIGFE
 setbuf SIGFE
 setbuffer SIGFE
+setcontext NOSIGFE
 sethostname SIGFE
 setdtablesize SIGFE
 setegid SIGFE
@@ -1199,6 +1202,7 @@ strtoumax = strtoull NOSIGFE
 strupr NOSIGFE
 strxfrm NOSIGFE
 swab NOSIGFE
+swapcontext NOSIGFE
 swprintf SIGFE
 swscanf SIGFE
 symlink SIGFE
index 67df4fec337b47ca420a02b55d4317a65fe6a71c..eea2be375932042e7593c9046ac04a88138f4296 100644 (file)
@@ -14,6 +14,7 @@ details. */
 #include "miscfuncs.h"
 #include <imagehlp.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <syslog.h>
 #include <wchar.h>
 #include <ucontext.h>
@@ -1863,3 +1864,226 @@ _cygtls::signal_debugger (siginfo_t& si)
       ResumeThread (th);
     }
 }
+
+#ifdef __x86_64__
+static inline void
+__unwind_single_frame (PCONTEXT ctx)
+{
+  /* Amazing, but true:  On 32 bit, RtlCaptureContext returns the context
+     matching the caller of getcontext, so all we have to do is call it.
+     On 64 bit, RtlCaptureContext returns the exact context of its own
+     caller, so we have to unwind virtually by a single frame to get the
+     context of the caller of getcontext. */
+  PRUNTIME_FUNCTION f;
+  ULONG64 imagebase;
+  UNWIND_HISTORY_TABLE hist;
+  DWORD64 establisher;
+  PVOID hdl;
+
+  f = RtlLookupFunctionEntry (ctx->Rip, &imagebase, &hist);
+  if (f)
+    RtlVirtualUnwind (0, imagebase, ctx->Rip, f, ctx, &hdl, &establisher,
+                     NULL);
+  else
+    {
+      ctx->Rip = *(ULONG_PTR *) ctx->Rsp;
+      ctx->Rsp += 8;
+    }
+}
+#endif
+
+extern "C" int
+setcontext (const ucontext_t *ucp)
+{
+  PCONTEXT ctx = (PCONTEXT) &ucp->uc_mcontext;
+  _my_tls.sigmask = ucp->uc_sigmask;
+#ifdef __x86_64__
+  /* Apparently a call to NtContinue works on 64 bit as well, but using
+     RtlRestoreContext is the blessed way. */
+  RtlRestoreContext (ctx, NULL);
+#else
+  NtContinue (ctx, FALSE);
+#endif
+  /* If we got here, something was wrong. */
+  set_errno (EINVAL);
+  return -1;
+}
+
+#ifdef __x86_64__
+
+extern "C" int
+getcontext (ucontext_t *ucp)
+{
+  PCONTEXT ctx = (PCONTEXT) &ucp->uc_mcontext;
+  ctx->ContextFlags = CONTEXT_FULL;
+  RtlCaptureContext (ctx);
+  __unwind_single_frame (ctx);
+  /* Successful getcontext is supposed to return 0.  If we don't set rax to 0
+     here, there's a chance that code like this:
+
+       if (getcontext (&ctx) != 0)
+
+     assumes that getcontext failed after calling setcontext (&ctx).
+     Same goes for eax on 32 bit, see assembler implementation below. */
+  ucp->uc_mcontext.rax = 0;
+  ucp->uc_sigmask = ucp->uc_mcontext.oldmask = _my_tls.sigmask;
+  /* Do not touch any other member of ucontext_t. */
+  return 0;
+}
+
+extern "C" int
+swapcontext (ucontext_t *oucp, const ucontext_t *ucp)
+{
+  PCONTEXT ctx = (PCONTEXT) &oucp->uc_mcontext;
+  ctx->ContextFlags = CONTEXT_FULL;
+  RtlCaptureContext (ctx);
+  __unwind_single_frame (ctx);
+  /* See above. */
+  oucp->uc_mcontext.rax = 0;
+  oucp->uc_sigmask = oucp->uc_mcontext.oldmask = _my_tls.sigmask;
+  return setcontext (ucp);
+}
+
+/* Trampoline function to set the context to uc_link.  The pointer to the
+   address of uc_link is stored in the callee-saved register $rbx.  If uc_link
+   is NULL, call exit. */
+__asm__ ("                             \n\
+       .global __cont_link_context     \n\
+__cont_link_context:                   \n\
+       movq    %rbx, %rsp              \n\
+       popq    %rcx                    \n\
+       testq   %rcx, %rcx              \n\
+       je      1f                      \n\
+       call    setcontext              \n\
+       movq    $0xff, %rcx             \n\
+1:                                     \n\
+       call    cygwin_exit             \n\
+       nop                             \n\
+       ");
+
+#else
+
+/* On 32 bit it's crucial to call RtlCaptureContext in a way which makes sure
+   the callee-saved registers, especially $ebx, are not changed by the calling
+   function.  If so, makecontext/__cont_link_context would be broken.
+
+   Both functions are split into the first half in assembler, and the second
+   half in C to allow easy access to _my_tls. */
+
+extern "C" int
+__getcontext (ucontext_t *ucp)
+{
+  ucp->uc_mcontext.eax = 0;
+  ucp->uc_sigmask = ucp->uc_mcontext.oldmask = _my_tls.sigmask;
+  return 0;
+}
+
+__asm__ ("                             \n\
+       .global _getcontext             \n\
+_getcontext:                           \n\
+       pushl   %ebp                    \n\
+       movl    %esp, %ebp              \n\
+       movl    8(%esp), %eax           \n\
+       pushl   %eax                    \n\
+       call    _RtlCaptureContext@4    \n\
+       popl    %ebp                    \n\
+       jmp     ___getcontext           \n\
+       nop                             \n\
+       ");
+
+extern "C" int
+__swapcontext (ucontext_t *oucp, const ucontext_t *ucp)
+{
+  oucp->uc_mcontext.eax = 0;
+  oucp->uc_sigmask = oucp->uc_mcontext.oldmask = _my_tls.sigmask;
+  return setcontext (ucp);
+}
+
+__asm__ ("                             \n\
+       .global _swapcontext            \n\
+_swapcontext:                          \n\
+       pushl   %ebp                    \n\
+       movl    %esp, %ebp              \n\
+       movl    8(%esp), %eax           \n\
+       pushl   %eax                    \n\
+       call    _RtlCaptureContext@4    \n\
+       popl    %ebp                    \n\
+       jmp     ___swapcontext          \n\
+       nop                             \n\
+       ");
+
+/* Trampoline function to set the context to uc_link.  The pointer to the
+   address of uc_link is stored in the callee-saved register $ebx.  If uc_link
+   is NULL, call exit. */
+__asm__ ("                             \n\
+       .global ___cont_link_context    \n\
+___cont_link_context:                  \n\
+       movl    %ebx, %esp              \n\
+       movl    (%esp), %eax            \n\
+       testl   %eax, %eax              \n\
+       je      1f                      \n\
+       call    _setcontext             \n\
+       movl    $0xff, (%esp)           \n\
+1:                                     \n\
+       call    _cygwin_exit            \n\
+       nop                             \n\
+       ");
+#endif
+
+/* makecontext is modelled after GLibc's makecontext.  The stack from uc_stack
+   is prepared so that it starts with a pointer to the linked context uc_link,
+   followed by the arguments to func, and finally at the bottom the "return"
+   address set to __cont_link_context.  In the ucp context, rbx/ebx is set to
+   point to the stack address where the pointer to uc_link is stored.  The
+   requirement to make this work is that rbx/ebx are callee-saved registers
+   per the ABI.  If any function is called which doesn't follow the ABI
+   conventions, e.g. assembler code, this method will break.  But that's ok. */
+extern "C" void
+makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
+{
+  extern void __cont_link_context (void);
+  uintptr_t *sp;
+  va_list ap;
+
+  sp = (uintptr_t *) ((uintptr_t) ucp->uc_stack.ss_sp
+                               + ucp->uc_stack.ss_size);
+  sp -= (argc + 1);
+  sp = (uintptr_t *) ((uintptr_t) sp & ~0xf);
+  --sp;
+  sp[0] = (uintptr_t) __cont_link_context;
+  sp[argc + 1] = (uintptr_t) ucp->uc_link;
+#ifdef __x86_64__
+  ucp->uc_mcontext.rip = (uint64_t) func;
+  ucp->uc_mcontext.rbx = (uint64_t) (sp + argc + 1);
+  ucp->uc_mcontext.rsp = (uint64_t) sp;
+#else
+  ucp->uc_mcontext.eip = (uint32_t) func;
+  ucp->uc_mcontext.ebx = (uint32_t) (sp + argc + 1);
+  ucp->uc_mcontext.esp = (uint32_t) sp;
+#endif
+  va_start (ap, argc);
+  for (int i = 0; i < argc; ++i)
+#ifdef __x86_64__
+    switch (i)
+      {
+      case 0:
+       ucp->uc_mcontext.rcx = va_arg (ap, uintptr_t);
+       break;
+      case 1:
+       ucp->uc_mcontext.rdx = va_arg (ap, uintptr_t);
+       break;
+      case 2:
+       ucp->uc_mcontext.r8 = va_arg (ap, uintptr_t);
+       break;
+      case 3:
+       ucp->uc_mcontext.r9 = va_arg (ap, uintptr_t);
+       break;
+      default:
+       sp[i + 1] = va_arg (ap, uintptr_t);
+       break;
+      }
+#else
+    sp[i + 1] = va_arg (ap, uintptr_t);
+#endif
+  va_end (ap);
+}
index 7843136b0d24e3e83beb73a8a47a0170b3f6fcce..d909ec3ce242b9b86e3bf549654c47beee011163 100644 (file)
@@ -42,7 +42,7 @@ details. */
         the Cygwin shared library".  This version is used to track important
         changes to the DLL and is mainly informative in nature. */
 
-#define CYGWIN_VERSION_DLL_MAJOR 2001
+#define CYGWIN_VERSION_DLL_MAJOR 2002
 #define CYGWIN_VERSION_DLL_MINOR 0
 
       /* Major numbers before CYGWIN_VERSION_DLL_EPOCH are
@@ -469,13 +469,14 @@ details. */
       285: Export wcstold.
       286: Export cabsl, cimagl, creall, finitel, hypotl, sqrtl.
       287: Export issetugid.
+      288: Export getcontext, makecontext, setcontext, swapcontext.
      */
 
      /* Note that we forgot to bump the api for ualarm, strtoll, strtoull,
        sigaltstack, sethostname. */
 
 #define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 287
+#define CYGWIN_VERSION_API_MINOR 288
 
      /* There is also a compatibity version number associated with the
        shared memory regions.  It is incremented when incompatible
index 4240597b8381fd555f0323e1a0155ff7e52dbb7c..dd44d750b5583487ddcda4187c2a87a74cc294e5 100644 (file)
@@ -11,6 +11,18 @@ details. */
 #ifndef _UCONTEXT_H
 #define _UCONTEXT_H
 
+#include <sys/cdefs.h>
 #include <sys/ucontext.h>
 
+__BEGIN_DECLS
+
+extern int getcontext (ucontext_t *) __attribute__((__nonnull__));
+extern int setcontext (const ucontext_t *) __attribute__((__nonnull__));
+extern int swapcontext (ucontext_t *, const ucontext_t *)
+                                       __attribute__((__nonnull__));
+extern void makecontext (ucontext_t *, void (*) (void), int, ...)
+                                       __attribute__((__nonnull__ (1)));
+
+__END_DECLS
+
 #endif /* _UCONTEXT_H */
index 7d8ccbec38a65bfb3e5e69fac62bec8c5569e94b..27a50be392a0e04de90630f813c44ddf4347f06c 100644 (file)
@@ -1258,6 +1258,7 @@ extern "C"
   NTSTATUS NTAPI NtCancelTimer (HANDLE, PBOOLEAN);
   NTSTATUS NTAPI NtClose (HANDLE);
   NTSTATUS NTAPI NtCommitTransaction (HANDLE, BOOLEAN);
+  NTSTATUS NTAPI NtContinue (PCONTEXT, BOOLEAN);
   NTSTATUS NTAPI NtCreateDirectoryObject (PHANDLE, ACCESS_MASK,
                                          POBJECT_ATTRIBUTES);
   NTSTATUS NTAPI NtCreateKey (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG,
diff --git a/winsup/cygwin/release/2.2.0 b/winsup/cygwin/release/2.2.0
new file mode 100644 (file)
index 0000000..7831178
--- /dev/null
@@ -0,0 +1,13 @@
+What's new:
+-----------
+
+- New APIs: getcontext, setcontext, makecontext, swapcontext.
+
+
+What changed:
+-------------
+
+
+Bug Fixes
+---------
+
index b452fa9062ff114c531d53d505642924b7146831..a4c30369aad7bb9298324a9845f9d8c3dd94b025 100644 (file)
@@ -1,3 +1,10 @@
+2015-07-17  Corinna Vinschen  <corinna@vinschen.de>
+
+       * new-features.xml (ov-new2.2): Add new section.  Document getcontext,
+       setcontext, makecontext, swapcontext.
+       * posix.xml (std-deprec): Add getcontext, setcontext, makecontext,
+       swapcontext.
+
 2015-07-05  Jon Turney  <jon.turney@dronecode.org.uk>
 
        * configure.ac: Add check for DOCBOOK2XTEXI
index c52574ce4d3719ca49696fe4444ae3bdaed00072..85d6ec78002d25e826a6976c910a464b7ee1a90b 100644 (file)
@@ -4,6 +4,18 @@
 
 <sect1 id="ov-new"><title>What's new and what changed in Cygwin</title>
 
+<sect2 id="ov-new2.2"><title>What's new and what changed in 2.2</title>
+
+<itemizedlist mark="bullet">
+
+<listitem><para>
+New APIs: getcontext, setcontext, makecontext, swapcontext.
+</para></listitem>
+
+</itemizedlist>
+
+</sect2>
+
 <sect2 id="ov-new2.1"><title>What's new and what changed in 2.1</title>
 
 <itemizedlist mark="bullet">
index 8a74f24f053635ea9b6aad29cce473b04b72c7d6..112ddc8eeaf02287f491268b89ef85107b6b9b87 100644 (file)
@@ -1322,6 +1322,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
     fcvt                       (SUSv3)
     ftime                      (SUSv3)
     gcvt                       (SUSv3)
+    getcontext                 (SUSv3)
     gethostbyaddr              (SUSv3)
     gethostbyname              (SUSv3)
     gethostbyname2             (first defined in BIND 4.9.4)
@@ -1333,6 +1334,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
     getwd                      (SUSv3)
     h_errno                    (SUSv3)
     index                      (SUSv3)
+    makecontext                        (SUSv3)
     mallinfo                   (SVID)
     mallopt                    (SVID)
     mktemp                     (SUSv3)
@@ -1347,8 +1349,10 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
     putw                       (SVID)
     rindex                     (SUSv3)
     scalb                      (SUSv3)
+    setcontext                 (SUSv3)
     setutent                   (XPG2)
     stime                      (SVID)
+    swapcontext                        (SUSv3)
     sys_errlist                        (BSD)
     sys_nerr                   (BSD)
     sys_siglist                        (BSD)
This page took 0.076878 seconds and 5 git commands to generate.