Blame elf/dl-error-skeleton.c

Packit Service 82fcde
/* Template for error handling for runtime dynamic linker.
Packit Service 82fcde
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
/* The following macro needs to be defined before including this
Packit Service 82fcde
   skeleton file:
Packit Service 82fcde
Packit Service 82fcde
   DL_ERROR_BOOTSTRAP
Packit Service 82fcde
Packit Service 82fcde
     If 1, do not use TLS and implement _dl_signal_cerror and
Packit Service 82fcde
     _dl_receive_error.  If 0, TLS is used, and the variants with
Packit Service 82fcde
     error callbacks are not provided.  */
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
#include <libintl.h>
Packit Service 82fcde
#include <setjmp.h>
Packit Service 82fcde
#include <stdbool.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <ldsodefs.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
Packit Service 82fcde
/* This structure communicates state between _dl_catch_error and
Packit Service 82fcde
   _dl_signal_error.  */
Packit Service 82fcde
struct catch
Packit Service 82fcde
  {
Packit Service 82fcde
    struct dl_exception *exception; /* The exception data is stored there.  */
Packit Service 82fcde
    volatile int *errcode;	/* Return value of _dl_signal_error.  */
Packit Service 82fcde
    jmp_buf env;		/* longjmp here on error.  */
Packit Service 82fcde
  };
Packit Service 82fcde
Packit Service 82fcde
/* Multiple threads at once can use the `_dl_catch_error' function.  The
Packit Service 82fcde
   calls can come from `_dl_map_object_deps', `_dlerror_run', or from
Packit Service 82fcde
   any of the libc functionality which loads dynamic objects (NSS, iconv).
Packit Service 82fcde
   Therefore we have to be prepared to save the state in thread-local
Packit Service 82fcde
   memory.  */
Packit Service 82fcde
#if !DL_ERROR_BOOTSTRAP
Packit Service 82fcde
static __thread struct catch *catch_hook attribute_tls_model_ie;
Packit Service 82fcde
#else
Packit Service 82fcde
/* The version of this code in ld.so cannot use thread-local variables
Packit Service 82fcde
   and is used during bootstrap only.  */
Packit Service 82fcde
static struct catch *catch_hook;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if DL_ERROR_BOOTSTRAP
Packit Service 82fcde
/* This points to a function which is called when an continuable error is
Packit Service 82fcde
   received.  Unlike the handling of `catch' this function may return.
Packit Service 82fcde
   The arguments will be the `errstring' and `objname'.
Packit Service 82fcde
Packit Service 82fcde
   Since this functionality is not used in normal programs (only in ld.so)
Packit Service 82fcde
   we do not care about multi-threaded programs here.  We keep this as a
Packit Service 82fcde
   global variable.  */
Packit Service 82fcde
static receiver_fct receiver;
Packit Service 82fcde
#endif /* DL_ERROR_BOOTSTRAP */
Packit Service 82fcde
Packit Service 82fcde
/* Lossage while resolving the program's own symbols is always fatal.  */
Packit Service 82fcde
static void
Packit Service 82fcde
__attribute__ ((noreturn))
Packit Service 82fcde
fatal_error (int errcode, const char *objname, const char *occasion,
Packit Service 82fcde
	     const char *errstring)
Packit Service 82fcde
{
Packit Service 82fcde
  char buffer[1024];
Packit Service 82fcde
  _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n",
Packit Service 82fcde
		    RTLD_PROGNAME,
Packit Service 82fcde
		    occasion ?: N_("error while loading shared libraries"),
Packit Service 82fcde
		    objname, *objname ? ": " : "",
Packit Service 82fcde
		    errstring, errcode ? ": " : "",
Packit Service 82fcde
		    (errcode
Packit Service 82fcde
		     ? __strerror_r (errcode, buffer, sizeof buffer)
Packit Service 82fcde
		     : ""));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_dl_signal_exception (int errcode, struct dl_exception *exception,
Packit Service 82fcde
		      const char *occasion)
Packit Service 82fcde
{
Packit Service 82fcde
  struct catch *lcatch = catch_hook;
Packit Service 82fcde
  if (lcatch != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      *lcatch->exception = *exception;
Packit Service 82fcde
      *lcatch->errcode = errcode;
Packit Service 82fcde
Packit Service 82fcde
      /* We do not restore the signal mask because none was saved.  */
Packit Service 82fcde
      __longjmp (lcatch->env[0].__jmpbuf, 1);
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    fatal_error (errcode, exception->objname, occasion, exception->errstring);
Packit Service 82fcde
}
Packit Service 82fcde
libc_hidden_def (_dl_signal_exception)
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_dl_signal_error (int errcode, const char *objname, const char *occation,
Packit Service 82fcde
		  const char *errstring)
Packit Service 82fcde
{
Packit Service 82fcde
  struct catch *lcatch = catch_hook;
Packit Service 82fcde
Packit Service 82fcde
  if (! errstring)
Packit Service 82fcde
    errstring = N_("DYNAMIC LINKER BUG!!!");
Packit Service 82fcde
Packit Service 82fcde
  if (lcatch != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      _dl_exception_create (lcatch->exception, objname, errstring);
Packit Service 82fcde
      *lcatch->errcode = errcode;
Packit Service 82fcde
Packit Service 82fcde
      /* We do not restore the signal mask because none was saved.  */
Packit Service 82fcde
      __longjmp (lcatch->env[0].__jmpbuf, 1);
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    fatal_error (errcode, objname, occation, errstring);
Packit Service 82fcde
}
Packit Service 82fcde
libc_hidden_def (_dl_signal_error)
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
#if DL_ERROR_BOOTSTRAP
Packit Service 82fcde
void
Packit Service 82fcde
_dl_signal_cexception (int errcode, struct dl_exception *exception,
Packit Service 82fcde
		       const char *occasion)
Packit Service 82fcde
{
Packit Service 82fcde
  if (__builtin_expect (GLRO(dl_debug_mask)
Packit Service 82fcde
			& ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
Packit Service 82fcde
    _dl_debug_printf ("%s: error: %s: %s (%s)\n",
Packit Service 82fcde
		      exception->objname, occasion,
Packit Service 82fcde
		      exception->errstring, receiver ? "continued" : "fatal");
Packit Service 82fcde
Packit Service 82fcde
  if (receiver)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We are inside _dl_receive_error.  Call the user supplied
Packit Service 82fcde
	 handler and resume the work.  The receiver will still be
Packit Service 82fcde
	 installed.  */
Packit Service 82fcde
      (*receiver) (errcode, exception->objname, exception->errstring);
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    _dl_signal_exception (errcode, exception, occasion);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_dl_signal_cerror (int errcode, const char *objname, const char *occation,
Packit Service 82fcde
		   const char *errstring)
Packit Service 82fcde
{
Packit Service 82fcde
  if (__builtin_expect (GLRO(dl_debug_mask)
Packit Service 82fcde
			& ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
Packit Service 82fcde
    _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation,
Packit Service 82fcde
		      errstring, receiver ? "continued" : "fatal");
Packit Service 82fcde
Packit Service 82fcde
  if (receiver)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We are inside _dl_receive_error.  Call the user supplied
Packit Service 82fcde
	 handler and resume the work.  The receiver will still be
Packit Service 82fcde
	 installed.  */
Packit Service 82fcde
      (*receiver) (errcode, objname, errstring);
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    _dl_signal_error (errcode, objname, occation, errstring);
Packit Service 82fcde
}
Packit Service 82fcde
#endif /* DL_ERROR_BOOTSTRAP */
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
_dl_catch_exception (struct dl_exception *exception,
Packit Service 82fcde
		     void (*operate) (void *), void *args)
Packit Service 82fcde
{
Packit Service 20a200
  /* If exception is NULL, temporarily disable exception handling.
Packit Service 20a200
     Exceptions during operate (args) are fatal.  */
Packit Service 20a200
  if (exception == NULL)
Packit Service 20a200
    {
Packit Service 20a200
      struct catch *const old = catch_hook;
Packit Service 20a200
      catch_hook = NULL;
Packit Service 20a200
      operate (args);
Packit Service 20a200
      /* If we get here, the operation was successful.  */
Packit Service 20a200
      catch_hook = old;
Packit Service 20a200
      return 0;
Packit Service 20a200
    }
Packit Service 20a200
Packit Service 82fcde
  /* We need not handle `receiver' since setting a `catch' is handled
Packit Service 82fcde
     before it.  */
Packit Service 82fcde
Packit Service 82fcde
  /* Only this needs to be marked volatile, because it is the only local
Packit Service 82fcde
     variable that gets changed between the setjmp invocation and the
Packit Service 82fcde
     longjmp call.  All others are just set here (before setjmp) and read
Packit Service 82fcde
     in _dl_signal_error (before longjmp).  */
Packit Service 82fcde
  volatile int errcode;
Packit Service 82fcde
Packit Service 82fcde
  struct catch c;
Packit Service 82fcde
  /* Don't use an initializer since we don't need to clear C.env.  */
Packit Service 82fcde
  c.exception = exception;
Packit Service 82fcde
  c.errcode = &errcode;
Packit Service 82fcde
Packit Service 82fcde
  struct catch *const old = catch_hook;
Packit Service 82fcde
  catch_hook = &c;
Packit Service 82fcde
Packit Service 82fcde
  /* Do not save the signal mask.  */
Packit Service 82fcde
  if (__builtin_expect (__sigsetjmp (c.env, 0), 0) == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      (*operate) (args);
Packit Service 82fcde
      catch_hook = old;
Packit Service 82fcde
      *exception = (struct dl_exception) { NULL };
Packit Service 82fcde
      return 0;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* We get here only if we longjmp'd out of OPERATE.
Packit Service 82fcde
     _dl_signal_exception has already stored values into
Packit Service 82fcde
     *EXCEPTION.  */
Packit Service 82fcde
  catch_hook = old;
Packit Service 82fcde
  return errcode;
Packit Service 82fcde
}
Packit Service 82fcde
libc_hidden_def (_dl_catch_exception)
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
_dl_catch_error (const char **objname, const char **errstring,
Packit Service 82fcde
		 bool *mallocedp, void (*operate) (void *), void *args)
Packit Service 82fcde
{
Packit Service 82fcde
  struct dl_exception exception;
Packit Service 82fcde
  int errorcode = _dl_catch_exception (&exception, operate, args);
Packit Service 82fcde
  *objname = exception.objname;
Packit Service 82fcde
  *errstring = exception.errstring;
Packit Service 82fcde
  *mallocedp = exception.message_buffer == exception.errstring;
Packit Service 82fcde
  return errorcode;
Packit Service 82fcde
}
Packit Service 82fcde
libc_hidden_def (_dl_catch_error)
Packit Service 82fcde
Packit Service 82fcde
#if DL_ERROR_BOOTSTRAP
Packit Service 82fcde
void
Packit Service 82fcde
_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args)
Packit Service 82fcde
{
Packit Service 82fcde
  struct catch *old_catch = catch_hook;
Packit Service 82fcde
  receiver_fct old_receiver = receiver;
Packit Service 82fcde
Packit Service 82fcde
  /* Set the new values.  */
Packit Service 82fcde
  catch_hook = NULL;
Packit Service 82fcde
  receiver = fct;
Packit Service 82fcde
Packit Service 82fcde
  (*operate) (args);
Packit Service 82fcde
Packit Service 82fcde
  catch_hook = old_catch;
Packit Service 82fcde
  receiver = old_receiver;
Packit Service 82fcde
}
Packit Service 82fcde
#endif /* DL_ERROR_BOOTSTRAP */