Blame nptl/unwind.c

Packit 6c4009
/* Copyright (C) 2003-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@redhat.com>
Packit 6c4009
   and Richard Henderson <rth@redhat.com>, 2003.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <setjmp.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include "pthreadP.h"
Packit 6c4009
#include <jmpbuf-unwind.h>
Packit 6c4009
Packit 6c4009
#ifdef _STACK_GROWS_DOWN
Packit 6c4009
# define FRAME_LEFT(frame, other, adj) \
Packit 6c4009
  ((uintptr_t) frame - adj >= (uintptr_t) other - adj)
Packit 6c4009
#elif _STACK_GROWS_UP
Packit 6c4009
# define FRAME_LEFT(frame, other, adj) \
Packit 6c4009
  ((uintptr_t) frame - adj <= (uintptr_t) other - adj)
Packit 6c4009
#else
Packit 6c4009
# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
static _Unwind_Reason_Code
Packit 6c4009
unwind_stop (int version, _Unwind_Action actions,
Packit 6c4009
	     _Unwind_Exception_Class exc_class,
Packit 6c4009
	     struct _Unwind_Exception *exc_obj,
Packit 6c4009
	     struct _Unwind_Context *context, void *stop_parameter)
Packit 6c4009
{
Packit 6c4009
  struct pthread_unwind_buf *buf = stop_parameter;
Packit 6c4009
  struct pthread *self = THREAD_SELF;
Packit 6c4009
  struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup);
Packit 6c4009
  int do_longjump = 0;
Packit 6c4009
Packit 6c4009
  /* Adjust all pointers used in comparisons, so that top of thread's
Packit 6c4009
     stack is at the top of address space.  Without that, things break
Packit 6c4009
     if stack is allocated above the main stack.  */
Packit 6c4009
  uintptr_t adj = (uintptr_t) self->stackblock + self->stackblock_size;
Packit 6c4009
Packit 6c4009
  /* Do longjmp if we're at "end of stack", aka "end of unwind data".
Packit 6c4009
     We assume there are only C frame without unwind data in between
Packit 6c4009
     here and the jmp_buf target.  Otherwise simply note that the CFA
Packit 6c4009
     of a function is NOT within it's stack frame; it's the SP of the
Packit 6c4009
     previous frame.  */
Packit 6c4009
  if ((actions & _UA_END_OF_STACK)
Packit 6c4009
      || ! _JMPBUF_CFA_UNWINDS_ADJ (buf->cancel_jmp_buf[0].jmp_buf, context,
Packit 6c4009
				    adj))
Packit 6c4009
    do_longjump = 1;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (curp != NULL))
Packit 6c4009
    {
Packit 6c4009
      /* Handle the compatibility stuff.  Execute all handlers
Packit 6c4009
	 registered with the old method which would be unwound by this
Packit 6c4009
	 step.  */
Packit 6c4009
      struct _pthread_cleanup_buffer *oldp = buf->priv.data.cleanup;
Packit 6c4009
      void *cfa = (void *) (_Unwind_Ptr) _Unwind_GetCFA (context);
Packit 6c4009
Packit 6c4009
      if (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp, adj)))
Packit 6c4009
	{
Packit 6c4009
	  do
Packit 6c4009
	    {
Packit 6c4009
	      /* Pointer to the next element.  */
Packit 6c4009
	      struct _pthread_cleanup_buffer *nextp = curp->__prev;
Packit 6c4009
Packit 6c4009
	      /* Call the handler.  */
Packit 6c4009
	      curp->__routine (curp->__arg);
Packit 6c4009
Packit 6c4009
	      /* To the next.  */
Packit 6c4009
	      curp = nextp;
Packit 6c4009
	    }
Packit 6c4009
	  while (curp != oldp
Packit 6c4009
		 && (do_longjump || FRAME_LEFT (cfa, curp, adj)));
Packit 6c4009
Packit 6c4009
	  /* Mark the current element as handled.  */
Packit 6c4009
	  THREAD_SETMEM (self, cleanup, curp);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (do_longjump)
Packit 6c4009
    __libc_unwind_longjmp ((struct __jmp_buf_tag *) buf->cancel_jmp_buf, 1);
Packit 6c4009
Packit 6c4009
  return _URC_NO_REASON;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
unwind_cleanup (_Unwind_Reason_Code reason, struct _Unwind_Exception *exc)
Packit 6c4009
{
Packit 6c4009
  /* When we get here a C++ catch block didn't rethrow the object.  We
Packit 6c4009
     cannot handle this case and therefore abort.  */
Packit 6c4009
  __libc_fatal ("FATAL: exception not rethrown\n");
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__cleanup_fct_attribute __attribute ((noreturn))
Packit 6c4009
__pthread_unwind (__pthread_unwind_buf_t *buf)
Packit 6c4009
{
Packit 6c4009
  struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
Packit 6c4009
  struct pthread *self = THREAD_SELF;
Packit 6c4009
Packit 6c4009
  /* This is not a catchable exception, so don't provide any details about
Packit 6c4009
     the exception type.  We do need to initialize the field though.  */
Packit 6c4009
  THREAD_SETMEM (self, exc.exception_class, 0);
Packit 6c4009
  THREAD_SETMEM (self, exc.exception_cleanup, &unwind_cleanup);
Packit 6c4009
Packit 6c4009
  _Unwind_ForcedUnwind (&self->exc, unwind_stop, ibuf);
Packit 6c4009
  /* NOTREACHED */
Packit 6c4009
Packit 6c4009
  /* We better do not get here.  */
Packit 6c4009
  abort ();
Packit 6c4009
}
Packit 6c4009
hidden_def (__pthread_unwind)
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__cleanup_fct_attribute __attribute ((noreturn))
Packit 6c4009
__pthread_unwind_next (__pthread_unwind_buf_t *buf)
Packit 6c4009
{
Packit 6c4009
  struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
Packit 6c4009
Packit 6c4009
  __pthread_unwind ((__pthread_unwind_buf_t *) ibuf->priv.data.prev);
Packit 6c4009
}
Packit 6c4009
hidden_def (__pthread_unwind_next)