aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2017-08-10 13:40:22 +0200
committerFlorian Weimer <fweimer@redhat.com>2017-08-10 16:54:57 +0200
commit2449ae7b2da24c9940962304a3e44bc80e389265 (patch)
treec2cfdcfc3a90731d2da26dda79984eda95e9079e
parentf87cc2bfba9b844da48a63441c6099342b1551c7 (diff)
downloadglibc-2449ae7b2da24c9940962304a3e44bc80e389265.zip
glibc-2449ae7b2da24c9940962304a3e44bc80e389265.tar.gz
glibc-2449ae7b2da24c9940962304a3e44bc80e389265.tar.bz2
ld.so: Introduce struct dl_exception
This commit separates allocating and raising exceptions. This simplifies catching and re-raising them because it is no longer necessary to make a temporary, on-stack copy of the exception message.
-rw-r--r--ChangeLog60
-rw-r--r--elf/Makefile5
-rw-r--r--elf/Versions5
-rw-r--r--elf/dl-deps.c39
-rw-r--r--elf/dl-error-skeleton.c147
-rw-r--r--elf/dl-exception.c202
-rw-r--r--elf/dl-lookup.c48
-rw-r--r--elf/dl-open.c31
-rw-r--r--elf/dl-sym.c23
-rw-r--r--elf/dl-version.c65
-rw-r--r--sysdeps/generic/ldsodefs.h107
-rw-r--r--sysdeps/generic/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/aarch64/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/arm/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/hppa/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/i386/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/ia64/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/m68k/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/microblaze/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/nios2/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/s390/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/sh/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data2
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data2
-rw-r--r--sysdeps/x86_64/localplt.data2
29 files changed, 529 insertions, 239 deletions
diff --git a/ChangeLog b/ChangeLog
index 6648ce1..dcf8626 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,65 @@
2017-08-10 Florian Weimer <fweimer@redhat.com>
+ Introduce ld.so exceptions.
+ * sysdeps/generic/ldsodefs.h (struct dl_exception): Define.
+ (_dl_exception_create, _dl_exception_create_format)
+ (_dl_exception_free, _dl_signal_exception, _dl_signal_cexception)
+ (_dl_catch_exception): Declare.
+ (_dl_catch_error): Update comment.
+ * elf/dl-error-skeleton.c (struct catch): Replace objname,
+ errstring, malloced members with exception member.
+ (_dl_out_of_memory): Remove.
+ (fatal_error): New function, extracted from _dl_signal_error.
+ (_dl_signal_exception, _dl_signal_cexception): New functions.
+ (_dl_signal_error): Call _dl_exception_create to allocate an
+ exception object.
+ (_dl_catch_exception): New function, based on _dl_catch_error.
+ (_dl_catch_error): Implement using _dl_catch_exception.
+ * elf/dl-exception.c: New file.
+ * elf/Makefile (dl-routines): Add dl-exception.
+ (elide-routines.os): Likewise.
+ * elf/Version (ld/GLIBC_PRIVATE): Add _dl_exception_create,
+ _dl_exception_create_format, _dl_exception_free.
+ * elf/dl-deps.c (_dl_map_object_deps): Use _dl_catch_exception and
+ _dl_signal_exception.
+ * elf/dl-lookup.c (make_string): Remove.
+ (_dl_lookup_symbol_x): Use _dl_exception_create_format,
+ _dl_signal_cexception, _dl_exception_free.
+ * elf/dl-open.c (_dl_open): Use _dl_catch_exception and
+ _dl_signal_exception.
+ * elf/dl-sym.c (do_sym): Likewise.
+ * elf/dl-version.c (make_string): Remove.
+ (match_symbol): Use _dl_exception_create_format,
+ _dl_signal_cexception, _dl_exception_free.
+ (_dl_check_map_versions): Likewise.
+ * sysdeps/generic/localplt.data (ld.so): Add _dl_signal_exception,
+ _dl_catch_exception.
+ * sysdeps/unix/sysv/linux/aarch64/localplt.data (ld.so): Likewise.
+ * sysdeps/unix/sysv/linux/alpha/localplt.data (ld.so): Likewise.
+ * sysdeps/unix/sysv/linux/arm/localplt.data (ld.so): Likewise.
+ * sysdeps/unix/sysv/linux/hppa/localplt.data (ld.so): Likewise.
+ * sysdeps/unix/sysv/linux/i386/localplt.data (ld.so): Likewise.
+ * sysdeps/unix/sysv/linux/ia64/localplt.data (ld.so): Likewise.
+ * sysdeps/unix/sysv/linux/m68k/localplt.data (ld.so): Likewise.
+ * sysdeps/unix/sysv/linux/microblaze/localplt.data (ld.so):
+ Likewise.
+ * sysdeps/unix/sysv/linux/nios2/localplt.data (ld.so): Likewise.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
+ (ld.so): Likewise.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
+ (ld.so): Likewise.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data (ld.so):
+ Likewise.
+ * sysdeps/unix/sysv/linux/s390/localplt.data (ld.so): Likewise.
+ * sysdeps/unix/sysv/linux/sh/localplt.data (ld.so): Likewise.
+ * sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data (ld.so):
+ Likewise.
+ * sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data (ld.so):
+ Likewise.
+ * sysdeps/x86_64/localplt.data (ld.so): Likewise.
+
+2017-08-10 Florian Weimer <fweimer@redhat.com>
+
* inet/net-internal.h (__inet6_scopeid_pton): Remove
attribute_hidden, internal_function.
* inet/inet6_scopeid_pton.c (__inet6_scopeid_pton): Remove
diff --git a/elf/Makefile b/elf/Makefile
index b54ebf8..d314a5f 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -31,7 +31,8 @@ routines = $(all-dl-routines) dl-support dl-iteratephdr \
dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \
runtime init fini debug misc \
version profile tls origin scope \
- execstack caller open close trampoline)
+ execstack caller open close trampoline \
+ exception)
ifeq (yes,$(use-ldconfig))
dl-routines += dl-cache
endif
@@ -51,7 +52,7 @@ endif
all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
# But they are absent from the shared libc, because that code is in ld.so.
elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \
- dl-sysdep
+ dl-sysdep dl-exception
shared-only-routines += dl-caller
# ld.so uses those routines, plus some special stuff for being the program
diff --git a/elf/Versions b/elf/Versions
index e65f2fa..79ffaf7 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -28,6 +28,7 @@ libc {
__libc_dlclose; __libc_dlopen_mode; __libc_dlsym;
# Internal error handling support. Interposes the functions in ld.so.
+ _dl_signal_exception; _dl_catch_exception;
_dl_signal_error; _dl_catch_error;
}
}
@@ -68,7 +69,11 @@ ld {
# Pointer protection.
__pointer_chk_guard;
+ # Internal error handling support.
+ _dl_exception_create; _dl_exception_create_format; _dl_exception_free;
+
# Internal error handling support. Interposed by libc.so.
+ _dl_signal_exception; _dl_catch_exception;
_dl_signal_error; _dl_catch_error;
# Set value of a tunable.
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 1b8bac6..7c82d42 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -165,8 +165,7 @@ _dl_map_object_deps (struct link_map *map,
const char *name;
int errno_saved;
int errno_reason;
- const char *errstring;
- const char *objname;
+ struct dl_exception exception;
/* No loaded object so far. */
nlist = 0;
@@ -200,7 +199,6 @@ _dl_map_object_deps (struct link_map *map,
alloca means we cannot use recursive function calls. */
errno_saved = errno;
errno_reason = 0;
- errstring = NULL;
errno = 0;
name = NULL;
for (runp = known; runp; )
@@ -250,17 +248,9 @@ _dl_map_object_deps (struct link_map *map,
/* Store the tag in the argument structure. */
args.name = name;
- bool malloced;
- int err = _dl_catch_error (&objname, &errstring, &malloced,
- openaux, &args);
- if (__glibc_unlikely (errstring != NULL))
+ int err = _dl_catch_exception (&exception, openaux, &args);
+ if (__glibc_unlikely (exception.errstring != NULL))
{
- char *new_errstring = strdupa (errstring);
- objname = strdupa (objname);
- if (malloced)
- free ((char *) errstring);
- errstring = new_errstring;
-
if (err)
errno_reason = err;
else
@@ -313,31 +303,18 @@ _dl_map_object_deps (struct link_map *map,
/* We must be prepared that the addressed shared
object is not available. For filter objects the dependency
must be available. */
- bool malloced;
- int err = _dl_catch_error (&objname, &errstring, &malloced,
- openaux, &args);
-
- if (__glibc_unlikely (errstring != NULL))
+ int err = _dl_catch_exception (&exception, openaux, &args);
+ if (__glibc_unlikely (exception.errstring != NULL))
{
if (d->d_tag == DT_AUXILIARY)
{
/* We are not interested in the error message. */
- assert (errstring != NULL);
- if (malloced)
- free ((char *) errstring);
-
+ _dl_exception_free (&exception);
/* Simply ignore this error and continue the work. */
continue;
}
else
{
-
- char *new_errstring = strdupa (errstring);
- objname = strdupa (objname);
- if (malloced)
- free ((char *) errstring);
- errstring = new_errstring;
-
if (err)
errno_reason = err;
else
@@ -683,6 +660,6 @@ Filters not supported with LD_TRACE_PRELINKING"));
_dl_scope_free (old_l_initfini);
if (errno_reason)
- _dl_signal_error (errno_reason == -1 ? 0 : errno_reason, objname,
- NULL, errstring);
+ _dl_signal_exception (errno_reason == -1 ? 0 : errno_reason,
+ &exception, NULL);
}
diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c
index 8e5888d..8de6c87 100644
--- a/elf/dl-error-skeleton.c
+++ b/elf/dl-error-skeleton.c
@@ -39,10 +39,7 @@
_dl_signal_error. */
struct catch
{
- const char **objname; /* Object/File name. */
- const char **errstring; /* Error detail filled in here. */
- bool *malloced; /* Nonzero if the string is malloced
- by the libc malloc. */
+ struct dl_exception *exception; /* The exception data is stored there. */
volatile int *errcode; /* Return value of _dl_signal_error. */
jmp_buf env; /* longjmp here on error. */
};
@@ -60,11 +57,6 @@ static __thread struct catch *catch_hook attribute_tls_model_ie;
static struct catch *catch_hook;
#endif
-/* This message we return as a last resort. We define the string in a
- variable since we have to avoid freeing it and so have to enable
- a pointer comparison. See below and in dlfcn/dlerror.c. */
-static const char _dl_out_of_memory[] = "out of memory";
-
#if DL_ERROR_BOOTSTRAP
/* This points to a function which is called when an continuable error is
received. Unlike the handling of `catch' this function may return.
@@ -76,6 +68,41 @@ static const char _dl_out_of_memory[] = "out of memory";
static receiver_fct receiver;
#endif /* DL_ERROR_BOOTSTRAP */
+/* Lossage while resolving the program's own symbols is always fatal. */
+static void
+__attribute__ ((noreturn))
+fatal_error (int errcode, const char *objname, const char *occasion,
+ const char *errstring)
+{
+ char buffer[1024];
+ _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n",
+ RTLD_PROGNAME,
+ occasion ?: N_("error while loading shared libraries"),
+ objname, *objname ? ": " : "",
+ errstring, errcode ? ": " : "",
+ (errcode
+ ? __strerror_r (errcode, buffer, sizeof buffer)
+ : ""));
+}
+
+void
+_dl_signal_exception (int errcode, struct dl_exception *exception,
+ const char *occasion)
+{
+ struct catch *lcatch = catch_hook;
+ if (lcatch != NULL)
+ {
+ *lcatch->exception = *exception;
+ *lcatch->errcode = errcode;
+
+ /* We do not restore the signal mask because none was saved. */
+ __longjmp (lcatch->env[0].__jmpbuf, 1);
+ }
+ else
+ fatal_error (errcode, exception->objname, occasion, exception->errstring);
+}
+libc_hidden_def (_dl_signal_exception)
+
void
internal_function
_dl_signal_error (int errcode, const char *objname, const char *occation,
@@ -86,66 +113,43 @@ _dl_signal_error (int errcode, const char *objname, const char *occation,
if (! errstring)
errstring = N_("DYNAMIC LINKER BUG!!!");
- if (objname == NULL)
- objname = "";
if (lcatch != NULL)
{
- /* We are inside _dl_catch_error. Return to it. We have to
- duplicate the error string since it might be allocated on the
- stack. The object name is always a string constant. */
- size_t len_objname = strlen (objname) + 1;
- size_t len_errstring = strlen (errstring) + 1;
-
- char *errstring_copy = malloc (len_objname + len_errstring);
- if (errstring_copy != NULL)
- {
- /* Make a copy of the object file name and the error string. */
- *lcatch->objname = memcpy (__mempcpy (errstring_copy,
- errstring, len_errstring),
- objname, len_objname);
- *lcatch->errstring = errstring_copy;
-
- /* If the main executable is relocated it means the libc's malloc
- is used. */
- bool malloced = true;
-#ifdef SHARED
- malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
- && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0));
-#endif
- *lcatch->malloced = malloced;
- }
- else
- {
- /* This is better than nothing. */
- *lcatch->objname = "";
- *lcatch->errstring = _dl_out_of_memory;
- *lcatch->malloced = false;
- }
-
+ _dl_exception_create (lcatch->exception, objname, errstring);
*lcatch->errcode = errcode;
/* We do not restore the signal mask because none was saved. */
__longjmp (lcatch->env[0].__jmpbuf, 1);
}
else
- {
- /* Lossage while resolving the program's own symbols is always fatal. */
- char buffer[1024];
- _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n",
- RTLD_PROGNAME,
- occation ?: N_("error while loading shared libraries"),
- objname, *objname ? ": " : "",
- errstring, errcode ? ": " : "",
- (errcode
- ? __strerror_r (errcode, buffer, sizeof buffer)
- : ""));
- }
+ fatal_error (errcode, objname, occation, errstring);
}
libc_hidden_def (_dl_signal_error)
#if DL_ERROR_BOOTSTRAP
void
+_dl_signal_cexception (int errcode, struct dl_exception *exception,
+ const char *occasion)
+{
+ if (__builtin_expect (GLRO(dl_debug_mask)
+ & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
+ _dl_debug_printf ("%s: error: %s: %s (%s)\n",
+ exception->objname, occasion,
+ exception->errstring, receiver ? "continued" : "fatal");
+
+ if (receiver)
+ {
+ /* We are inside _dl_receive_error. Call the user supplied
+ handler and resume the work. The receiver will still be
+ installed. */
+ (*receiver) (errcode, exception->objname, exception->errstring);
+ }
+ else
+ _dl_signal_exception (errcode, exception, occasion);
+}
+
+void
internal_function
_dl_signal_cerror (int errcode, const char *objname, const char *occation,
const char *errstring)
@@ -167,11 +171,9 @@ _dl_signal_cerror (int errcode, const char *objname, const char *occation,
}
#endif /* DL_ERROR_BOOTSTRAP */
-
int
-internal_function
-_dl_catch_error (const char **objname, const char **errstring,
- bool *mallocedp, void (*operate) (void *), void *args)
+_dl_catch_exception (struct dl_exception *exception,
+ void (*operate) (void *), void *args)
{
/* We need not handle `receiver' since setting a `catch' is handled
before it. */
@@ -184,9 +186,7 @@ _dl_catch_error (const char **objname, const char **errstring,
struct catch c;
/* Don't use an initializer since we don't need to clear C.env. */
- c.objname = objname;
- c.errstring = errstring;
- c.malloced = mallocedp;
+ c.exception = exception;
c.errcode = &errcode;
struct catch *const old = catch_hook;
@@ -197,17 +197,30 @@ _dl_catch_error (const char **objname, const char **errstring,
{
(*operate) (args);
catch_hook = old;
- *objname = NULL;
- *errstring = NULL;
- *mallocedp = false;
+ *exception = (struct dl_exception) { NULL };
return 0;
}
- /* We get here only if we longjmp'd out of OPERATE. _dl_signal_error has
- already stored values into *OBJNAME, *ERRSTRING, and *MALLOCEDP. */
+ /* We get here only if we longjmp'd out of OPERATE.
+ _dl_signal_exception has already stored values into
+ *EXCEPTION. */
catch_hook = old;
return errcode;
}
+libc_hidden_def (_dl_catch_exception)
+
+int
+internal_function
+_dl_catch_error (const char **objname, const char **errstring,
+ bool *mallocedp, void (*operate) (void *), void *args)
+{
+ struct dl_exception exception;
+ int errorcode = _dl_catch_exception (&exception, operate, args);
+ *objname = exception.objname;
+ *errstring = exception.errstring;
+ *mallocedp = exception.message_buffer == exception.errstring;
+ return errorcode;
+}
libc_hidden_def (_dl_catch_error)
#if DL_ERROR_BOOTSTRAP
diff --git a/elf/dl-exception.c b/elf/dl-exception.c
new file mode 100644
index 0000000..b4d0ca7
--- /dev/null
+++ b/elf/dl-exception.c
@@ -0,0 +1,202 @@
+/* ld.so error exception allocation and deallocation.
+ Copyright (C) 1995-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <ldsodefs.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+/* This message we return as a last resort. We define the string in a
+ variable since we have to avoid freeing it and so have to enable
+ a pointer comparison. See below and in dlfcn/dlerror.c. */
+static const char _dl_out_of_memory[] = "out of memory";
+
+/* Dummy allocation object used if allocating the message buffer
+ fails. */
+static void
+oom_exception (struct dl_exception *exception)
+{
+ exception->objname = "";
+ exception->errstring = _dl_out_of_memory;
+ exception->message_buffer = NULL;
+}
+
+static void
+__attribute__ ((noreturn))
+length_mismatch (void)
+{
+ _dl_fatal_printf ("Fatal error: "
+ "length accounting in _dl_exception_create_format\n");
+}
+
+/* Adjust the message buffer to indicate whether it is possible to
+ free it. EXCEPTION->errstring must be a potentially deallocatable
+ pointer. */
+static void
+adjust_message_buffer (struct dl_exception *exception)
+{
+ /* If the main executable is relocated it means the libc's malloc
+ is used. */
+ bool malloced = true;
+#ifdef SHARED
+ malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
+ && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0));
+#endif
+ if (malloced)
+ exception->message_buffer = (char *) exception->errstring;
+ else
+ exception->message_buffer = NULL;
+}
+
+void
+_dl_exception_create (struct dl_exception *exception, const char *objname,
+ const char *errstring)
+{
+ if (objname == NULL)
+ objname = "";
+ size_t len_objname = strlen (objname) + 1;
+ size_t len_errstring = strlen (errstring) + 1;
+ char *errstring_copy = malloc (len_objname + len_errstring);
+ if (errstring_copy != NULL)
+ {
+ /* Make a copy of the object file name and the error string. */
+ exception->objname = memcpy (__mempcpy (errstring_copy,
+ errstring, len_errstring),
+ objname, len_objname);
+ exception->errstring = errstring_copy;
+ adjust_message_buffer (exception);
+ }
+ else
+ oom_exception (exception);
+}
+rtld_hidden_def (_dl_exception_create)
+
+void
+_dl_exception_create_format (struct dl_exception *exception, const char *objname,
+ const char *fmt, ...)
+{
+ if (objname == NULL)
+ objname = "";
+ size_t len_objname = strlen (objname) + 1;
+ /* Compute the length of the result. Include room for two NUL
+ bytes. */
+ size_t length = len_objname + 1;
+ {
+ va_list ap;
+ va_start (ap, fmt);
+ for (const char *p = fmt; *p != '\0'; ++p)
+ if (*p == '%')
+ {
+ ++p;
+ switch (*p)
+ {
+ case 's':
+ length += strlen (va_arg (ap, const char *));
+ break;
+ default:
+ /* Assumed to be '%'. */
+ ++length;
+ break;
+ }
+ }
+ else
+ ++length;
+ va_end (ap);
+ }
+
+ if (length > PTRDIFF_MAX)
+ {
+ oom_exception (exception);
+ return;
+ }
+ char *errstring = malloc (length);
+ if (errstring == NULL)
+ {
+ oom_exception (exception);
+ return;
+ }
+ exception->errstring = errstring;
+ adjust_message_buffer (exception);
+
+ /* Copy the error message to errstring. */
+ {
+ /* Next byte to be written in errstring. */
+ char *wptr = errstring;
+ /* End of the allocated string. */
+ char *const end = errstring + length;
+
+ va_list ap;
+ va_start (ap, fmt);
+
+ for (const char *p = fmt; *p != '\0'; ++p)
+ if (*p == '%')
+ {
+ ++p;
+ switch (*p)
+ {
+ case 's':
+ {
+ const char *ptr = va_arg (ap, const char *);
+ size_t len_ptr = strlen (ptr);
+ if (len_ptr > end - wptr)
+ length_mismatch ();
+ wptr = __mempcpy (wptr, ptr, len_ptr);
+ }
+ break;
+ case '%':
+ if (wptr == end)
+ length_mismatch ();
+ *wptr = '%';
+ ++wptr;
+ break;
+ default:
+ _dl_fatal_printf ("Fatal error:"
+ " invalid format in exception string\n");
+ }
+ }
+ else
+ {
+ if (wptr == end)
+ length_mismatch ();
+ *wptr = *p;
+ ++wptr;
+ }
+
+ if (wptr == end)
+ length_mismatch ();
+ *wptr = '\0';
+ ++wptr;
+ if (len_objname != end - wptr)
+ length_mismatch ();
+ exception->objname = memcpy (wptr, objname, len_objname);
+ }
+}
+rtld_hidden_def (_dl_exception_create_format)
+
+void
+_dl_exception_free (struct dl_exception *exception)
+{
+ free (exception->message_buffer);
+ exception->objname = NULL;
+ exception->errstring = NULL;
+ exception->message_buffer = NULL;
+}
+rtld_hidden_def (_dl_exception_free)
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 3d2369d..645dc3e 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -47,23 +47,6 @@ struct sym_val
};
-#define make_string(string, rest...) \
- ({ \
- const char *all[] = { string, ## rest }; \
- size_t len, cnt; \
- char *result, *cp; \
- \
- len = 1; \
- for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
- len += strlen (all[cnt]); \
- \
- cp = result = alloca (len); \
- for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
- cp = __stpcpy (cp, all[cnt]); \
- \
- result; \
- })
-
/* Statistics function. */
#ifdef SHARED
# define bump_num_relocations() ++GL(dl_num_relocations)
@@ -843,17 +826,16 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
for unversioned lookups. */
assert (version != NULL);
const char *reference_name = undef_map ? undef_map->l_name : "";
-
+ struct dl_exception exception;
/* XXX We cannot translate the message. */
- _dl_signal_cerror (0, DSO_FILENAME (reference_name),
- N_("relocation error"),
- make_string ("symbol ", undef_name, ", version ",
- version->name,
- " not defined in file ",
- version->filename,
- " with link time reference",
- res == -2
- ? " (no version symbols)" : ""));
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (reference_name),
+ "symbol %s version %s not defined in file %s"
+ " with link time reference%s",
+ undef_name, version->name, version->filename,
+ res == -2 ? " (no version symbols)" : "");
+ _dl_signal_cexception (0, &exception, N_("relocation error"));
+ _dl_exception_free (&exception);
*ref = NULL;
return 0;
}
@@ -869,12 +851,14 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
const char *versionstr = version ? ", version " : "";
const char *versionname = (version && version->name
? version->name : "");
-
+ struct dl_exception exception;
/* XXX We cannot translate the message. */
- _dl_signal_cerror (0, DSO_FILENAME (reference_name),
- N_("symbol lookup error"),
- make_string ("undefined symbol: ", undef_name,
- versionstr, versionname));
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (reference_name),
+ "undefined symbol: %s%s%s",
+ undef_name, versionstr, versionname);
+ _dl_signal_cexception (0, &exception, N_("symbol lookup error"));
+ _dl_exception_free (&exception);
}
*ref = NULL;
return 0;
diff --git a/elf/dl-open.c b/elf/dl-open.c
index cec54db..91a1d1a 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -643,11 +643,8 @@ no more namespaces available for dlmopen()"));
args.argv = argv;
args.env = env;
- const char *objname;
- const char *errstring;
- bool malloced;
- int errcode = _dl_catch_error (&objname, &errstring, &malloced,
- dl_open_worker, &args);
+ struct dl_exception exception;
+ int errcode = _dl_catch_exception (&exception, dl_open_worker, &args);
#if defined USE_LDCONFIG && !defined MAP_COPY
/* We must unmap the cache file. */
@@ -655,7 +652,7 @@ no more namespaces available for dlmopen()"));
#endif
/* See if an error occurred during loading. */
- if (__glibc_unlikely (errstring != NULL))
+ if (__glibc_unlikely (exception.errstring != NULL))
{
/* Remove the object from memory. It may be in an inconsistent
state if relocation failed, for example. */
@@ -679,28 +676,8 @@ no more namespaces available for dlmopen()"));
/* Release the lock. */
__rtld_lock_unlock_recursive (GL(dl_load_lock));
- /* Make a local copy of the error string so that we can release the
- memory allocated for it. */
- size_t len_errstring = strlen (errstring) + 1;
- char *local_errstring;
- if (objname == errstring + len_errstring)
- {
- size_t total_len = len_errstring + strlen (objname) + 1;
- local_errstring = alloca (total_len);
- memcpy (local_errstring, errstring, total_len);
- objname = local_errstring + len_errstring;
- }
- else
- {
- local_errstring = alloca (len_errstring);
- memcpy (local_errstring, errstring, len_errstring);
- }
-
- if (malloced)
- free ((char *) errstring);
-
/* Reraise the error. */
- _dl_signal_error (errcode, objname, NULL, local_errstring);
+ _dl_signal_exception (errcode, &exception, NULL);
}
assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index 7cd6e97..fb54a91 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -119,26 +119,11 @@ do_sym (void *handle, const char *name, void *who,
args.refp = &ref;
THREAD_GSCOPE_SET_FLAG ();
-
- const char *objname;
- const char *errstring = NULL;
- bool malloced;
- int err = _dl_catch_error (&objname, &errstring, &malloced,
- call_dl_lookup, &args);
-
+ struct dl_exception exception;
+ int err = _dl_catch_exception (&exception, call_dl_lookup, &args);
THREAD_GSCOPE_RESET_FLAG ();
-
- if (__glibc_unlikely (errstring != NULL))
- {
- /* The lookup was unsuccessful. Rethrow the error. */
- char *errstring_dup = strdupa (errstring);
- char *objname_dup = strdupa (objname);
- if (malloced)
- free ((char *) errstring);
-
- _dl_signal_error (err, objname_dup, NULL, errstring_dup);
- /* NOTREACHED */
- }
+ if (__glibc_unlikely (exception.errstring != NULL))
+ _dl_signal_exception (err, &exception, NULL);
result = args.map;
}
diff --git a/elf/dl-version.c b/elf/dl-version.c
index c00078e..c0d76ad 100644
--- a/elf/dl-version.c
+++ b/elf/dl-version.c
@@ -27,25 +27,6 @@
#include <assert.h>
-
-#define make_string(string, rest...) \
- ({ \
- const char *all[] = { string, ## rest }; \
- size_t len, cnt; \
- char *result, *cp; \
- \
- len = 1; \
- for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
- len += strlen (all[cnt]); \
- \
- cp = result = alloca (len); \
- for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
- cp = __stpcpy (cp, all[cnt]); \
- \
- result; \
- })
-
-
static inline struct link_map *
__attribute ((always_inline))
find_needed (const char *name, struct link_map *map)
@@ -78,8 +59,8 @@ match_symbol (const char *name, Lmid_t ns, ElfW(Word) hash, const char *string,
ElfW(Addr) def_offset;
ElfW(Verdef) *def;
/* Initialize to make the compiler happy. */
- const char *errstring = NULL;
int result = 0;
+ struct dl_exception exception;
/* Display information about what we are doing while debugging. */
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS))
@@ -96,8 +77,9 @@ checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
if (verbose)
{
/* XXX We cannot translate the messages. */
- errstring = make_string ("\
-no version information available (required by ", name, ")");
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (map->l_name),
+ "no version information available (required by %s)", name);
goto call_cerror;
}
return 0;
@@ -116,10 +98,10 @@ no version information available (required by ", name, ")");
char buf[20];
buf[sizeof (buf) - 1] = '\0';
/* XXX We cannot translate the message. */
- errstring = make_string ("unsupported version ",
- _itoa (def->vd_version,
- &buf[sizeof (buf) - 1], 10, 0),
- " of Verdef record");
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (map->l_name),
+ "unsupported version %s of Verdef record",
+ _itoa (def->vd_version, &buf[sizeof (buf) - 1], 10, 0));
result = 1;
goto call_cerror;
}
@@ -150,20 +132,22 @@ no version information available (required by ", name, ")");
if (verbose)
{
/* XXX We cannot translate the message. */
- errstring = make_string ("weak version `", string,
- "' not found (required by ", name, ")");
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (map->l_name),
+ "weak version `%s' not found (required by %s)", string, name);
goto call_cerror;
}
return 0;
}
/* XXX We cannot translate the message. */
- errstring = make_string ("version `", string, "' not found (required by ",
- name, ")");
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (map->l_name),
+ "version `%s' not found (required by %s)", string, name);
result = 1;
call_cerror:
- _dl_signal_cerror (0, DSO_FILENAME (map->l_name),
- N_("version lookup error"), errstring);
+ _dl_signal_cexception (0, &exception, N_("version lookup error"));
+ _dl_exception_free (&exception);
return result;
}
@@ -181,8 +165,8 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
/* We need to find out which is the highest version index used
in a dependecy. */
unsigned int ndx_high = 0;
+ struct dl_exception exception;
/* Initialize to make the compiler happy. */
- const char *errstring = NULL;
int errval = 0;
/* If we don't have a string table, we must be ok. */
@@ -205,13 +189,12 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
char buf[20];
buf[sizeof (buf) - 1] = '\0';
/* XXX We cannot translate the message. */
- errstring = make_string ("unsupported version ",
- _itoa (ent->vn_version,
- &buf[sizeof (buf) - 1], 10, 0),
- " of Verneed record\n");
+ _dl_exception_create_format
+ (&exception, DSO_FILENAME (map->l_name),
+ "unsupported version %s of Verneed record",
+ _itoa (ent->vn_version, &buf[sizeof (buf) - 1], 10, 0));
call_error:
- _dl_signal_error (errval, DSO_FILENAME (map->l_name),
- NULL, errstring);
+ _dl_signal_exception (errval, &exception, NULL);
}
while (1)
@@ -293,7 +276,9 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
calloc (ndx_high + 1, sizeof (*map->l_versions));
if (__glibc_unlikely (map->l_versions == NULL))
{
- errstring = N_("cannot allocate version reference table");
+ _dl_exception_create
+ (&exception, DSO_FILENAME (map->l_name),
+ N_("cannot allocate version reference table"));
errval = ENOMEM;
goto call_error;
}
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 4508365..1c0b9cb 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -732,31 +732,88 @@ _dl_dprintf (int fd, const char *fmt, ...)
while (1)
-/* This function is called by all the internal dynamic linker functions
- when they encounter an error. ERRCODE is either an `errno' code or
- zero; OBJECT is the name of the problematical shared object, or null if
- it is a general problem; ERRSTRING is a string describing the specific
- problem. */
+/* An exception raised by the _dl_signal_error function family and
+ caught by _dl_catch_error function family. Exceptions themselves
+ are copied as part of the raise operation, but the strings are
+ not. */
+struct dl_exception
+{
+ const char *objname;
+ const char *errstring;
+
+ /* This buffer typically stores both objname and errstring
+ above. */
+ char *message_buffer;
+};
+
+/* Creates a new exception. This calls malloc; if allocation fails,
+ dummy values are inserted. OBJECT is the name of the problematical
+ shared object, or null if its a general problem. ERRSTRING is a
+ string describing the specific problem. */
+void _dl_exception_create (struct dl_exception *, const char *object,
+ const char *errstring)
+ __attribute__ ((nonnull (1, 3)));
+rtld_hidden_proto (_dl_exception_create)
+
+/* Like _dl_exception_create, but create errstring from a format
+ string FMT. Currently, only "%s" and "%%" are supported as format
+ directives. */
+void _dl_exception_create_format (struct dl_exception *, const char *objname,
+ const char *fmt, ...)
+ __attribute__ ((nonnull (1, 3), format (printf, 3, 4)));
+rtld_hidden_proto (_dl_exception_create_format)
+
+/* Deallocate the exception, freeing allocated buffers (if
+ possible). */
+void _dl_exception_free (struct dl_exception *)
+ __attribute__ ((nonnull (1)));
+rtld_hidden_proto (_dl_exception_free)
+
+/* This function is called by all the internal dynamic linker
+ functions when they encounter an error. ERRCODE is either an
+ `errno' code or zero; it specifies the return value of
+ _dl_catch_error. OCCASION is included in the error message if the
+ process is terminated immediately. */
+void _dl_signal_exception (int errcode, struct dl_exception *,
+ const char *occasion)
+ __attribute__ ((__noreturn__));
+libc_hidden_proto (_dl_signal_exception)
+
+/* Like _dl_signal_exception, but creates the exception first. */
extern void _dl_signal_error (int errcode, const char *object,
- const char *occurred, const char *errstring)
+ const char *occasion, const char *errstring)
internal_function __attribute__ ((__noreturn__));
libc_hidden_proto (_dl_signal_error)
-/* Like _dl_signal_error, but may return when called in the context of
- _dl_receive_error. This is only used during ld.so bootstrap. In
- static and profiled builds, this is equivalent to
- _dl_signal_error. */
+/* Like _dl_signal_exception, but may return when called in the
+ context of _dl_receive_error. This is only used during ld.so
+ bootstrap. In static and profiled builds, this is equivalent to
+ _dl_signal_exception. */
+#if IS_IN (rtld)
+extern void _dl_signal_cexception (int errcode, struct dl_exception *,
+ const char *occasion) attribute_hidden;
+#else
+__attribute__ ((always_inline))
+static inline void
+_dl_signal_cexception (int errcode, struct dl_exception *exception,
+ const char *occasion)
+{
+ _dl_signal_exception (errcode, exception, occasion);
+}
+#endif
+
+/* See _dl_signal_cexception above. */
#if IS_IN (rtld)
extern void _dl_signal_cerror (int errcode, const char *object,
- const char *occation, const char *errstring)
+ const char *occasion, const char *errstring)
internal_function attribute_hidden;
#else
__attribute__ ((always_inline))
static inline void
_dl_signal_cerror (int errcode, const char *object,
- const char *occation, const char *errstring)
+ const char *occasion, const char *errstring)
{
- _dl_signal_error (errcode, object, occation, errstring);
+ _dl_signal_error (errcode, object, occasion, errstring);
}
#endif
@@ -768,20 +825,28 @@ extern void _dl_receive_error (receiver_fct fct, void (*operate) (void *),
void *args)
internal_function attribute_hidden;
-/* Call OPERATE, catching errors from `dl_signal_error'. If there is no
- error, *ERRSTRING is set to null. If there is an error, *ERRSTRING is
- set to a string constructed from the strings passed to _dl_signal_error,
- and the error code passed is the return value and *OBJNAME is set to
- the object name which experienced the problems. ERRSTRING if nonzero
- points to a malloc'ed string which the caller has to free after use.
- ARGS is passed as argument to OPERATE. MALLOCEDP is set to true only
- if the returned string is allocated using the libc's malloc. */
+/* Call OPERATE, catching errors from `_dl_signal_error' and related
+ functions. If there is no error, *ERRSTRING is set to null. If
+ there is an error, *ERRSTRING is set to a string constructed from
+ the strings passed to _dl_signal_error, and the error code passed
+ is the return value and *OBJNAME is set to the object name which
+ experienced the problems. ERRSTRING if nonzero points to a
+ malloc'ed string which the caller has to free after use. ARGS is
+ passed as argument to OPERATE. MALLOCEDP is set to true only if
+ the returned string is allocated using the libc's malloc. */
extern int _dl_catch_error (const char **objname, const char **errstring,
bool *mallocedp, void (*operate) (void *),
void *args)
internal_function;
libc_hidden_proto (_dl_catch_error)
+/* Call OPERATE (ARGS). If no error occurs, set *EXCEPTION to zero.
+ Otherwise, store a copy of the raised exception in *EXCEPTION,
+ which has to be freed by _dl_exception_free. */
+int _dl_catch_exception (struct dl_exception *exception,
+ void (*operate) (void *), void *args);
+libc_hidden_proto (_dl_catch_exception)
+
/* Open the shared object NAME and map in its segments.
LOADER's DT_RPATH is used in searching for NAME.
If the object is already opened, returns its existing map. */
diff --git a/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data
index 81c741b..2d5c66a 100644
--- a/sysdeps/generic/localplt.data
+++ b/sysdeps/generic/localplt.data
@@ -16,3 +16,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data
index bb18ff9..a60053b 100644
--- a/sysdeps/unix/sysv/linux/aarch64/localplt.data
+++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data
@@ -18,3 +18,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data
index 1f0e3b4..c69eb04 100644
--- a/sysdeps/unix/sysv/linux/alpha/localplt.data
+++ b/sysdeps/unix/sysv/linux/alpha/localplt.data
@@ -35,3 +35,5 @@ ld.so: free + RELA R_ALPHA_GLOB_DAT
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error + RELA R_ALPHA_GLOB_DAT
ld.so: _dl_catch_error + RELA R_ALPHA_GLOB_DAT
+ld.so: _dl_signal_exception + RELA R_ALPHA_GLOB_DAT
+ld.so: _dl_catch_exception + RELA R_ALPHA_GLOB_DAT
diff --git a/sysdeps/unix/sysv/linux/arm/localplt.data b/sysdeps/unix/sysv/linux/arm/localplt.data
index 19d3299..7bd541c 100644
--- a/sysdeps/unix/sysv/linux/arm/localplt.data
+++ b/sysdeps/unix/sysv/linux/arm/localplt.data
@@ -17,3 +17,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data
index db9e24b..3279c0a 100644
--- a/sysdeps/unix/sysv/linux/hppa/localplt.data
+++ b/sysdeps/unix/sysv/linux/hppa/localplt.data
@@ -21,3 +21,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data
index 8ea4333..f6f20a5 100644
--- a/sysdeps/unix/sysv/linux/i386/localplt.data
+++ b/sysdeps/unix/sysv/linux/i386/localplt.data
@@ -16,3 +16,5 @@ ld.so: free + REL R_386_GLOB_DAT
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error + REL R_386_GLOB_DAT
ld.so: _dl_catch_error + REL R_386_GLOB_DAT
+ld.so: _dl_signal_exception + REL R_386_GLOB_DAT
+ld.so: _dl_catch_exception + REL R_386_GLOB_DAT
diff --git a/sysdeps/unix/sysv/linux/ia64/localplt.data b/sysdeps/unix/sysv/linux/ia64/localplt.data
index fd2b98c..3820e2a 100644
--- a/sysdeps/unix/sysv/linux/ia64/localplt.data
+++ b/sysdeps/unix/sysv/linux/ia64/localplt.data
@@ -15,3 +15,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/m68k/localplt.data b/sysdeps/unix/sysv/linux/m68k/localplt.data
index 1a2acfd..c70d6ea 100644
--- a/sysdeps/unix/sysv/linux/m68k/localplt.data
+++ b/sysdeps/unix/sysv/linux/m68k/localplt.data
@@ -15,3 +15,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/microblaze/localplt.data b/sysdeps/unix/sysv/linux/microblaze/localplt.data
index ca476be..8ca2389 100644
--- a/sysdeps/unix/sysv/linux/microblaze/localplt.data
+++ b/sysdeps/unix/sysv/linux/microblaze/localplt.data
@@ -16,3 +16,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/nios2/localplt.data b/sysdeps/unix/sysv/linux/nios2/localplt.data
index b0d6dca..4430a58 100644
--- a/sysdeps/unix/sysv/linux/nios2/localplt.data
+++ b/sysdeps/unix/sysv/linux/nios2/localplt.data
@@ -36,3 +36,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
index 5000631..e822e0a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
@@ -14,3 +14,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
index 1c20d2f..fead931 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
@@ -44,3 +44,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
index 6f8ed25..c120933 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
@@ -13,3 +13,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/s390/localplt.data b/sysdeps/unix/sysv/linux/s390/localplt.data
index 5000631..e822e0a 100644
--- a/sysdeps/unix/sysv/linux/s390/localplt.data
+++ b/sysdeps/unix/sysv/linux/s390/localplt.data
@@ -14,3 +14,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/sh/localplt.data b/sysdeps/unix/sysv/linux/sh/localplt.data
index f1f5eff..2753547 100644
--- a/sysdeps/unix/sysv/linux/sh/localplt.data
+++ b/sysdeps/unix/sysv/linux/sh/localplt.data
@@ -19,3 +19,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
index 2f6ff3c..1668f40 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
@@ -26,3 +26,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
index 912bd1a..b881b90 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
@@ -27,3 +27,5 @@ ld.so: free
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error
ld.so: _dl_catch_error
+ld.so: _dl_signal_exception
+ld.so: _dl_catch_exception
diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data
index a1840cf..c27a02b 100644
--- a/sysdeps/x86_64/localplt.data
+++ b/sysdeps/x86_64/localplt.data
@@ -18,3 +18,5 @@ ld.so: free + RELA R_X86_64_GLOB_DAT
# The TLS-enabled version of these functions is interposed from libc.so.
ld.so: _dl_signal_error + RELA R_X86_64_GLOB_DAT
ld.so: _dl_catch_error + RELA R_X86_64_GLOB_DAT
+ld.so: _dl_signal_exception + RELA R_X86_64_GLOB_DAT
+ld.so: _dl_catch_exception + RELA R_X86_64_GLOB_DAT