This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] ld.so: Introduce struct dl_exception
- From: Carlos O'Donell <carlos at redhat dot com>
- To: Florian Weimer <fweimer at redhat dot com>, libc-alpha at sourceware dot org
- Date: Thu, 10 Aug 2017 10:23:28 -0400
- Subject: Re: [PATCH] ld.so: Introduce struct dl_exception
- Authentication-results: sourceware.org; auth=none
- References: <20170619152936.C6D63402AEC2B@oldenburg.str.redhat.com> <14388f99-d227-a01a-45f6-df66a40574b9@redhat.com>
On 08/10/2017 07:56 AM, Florian Weimer wrote:
> On 06/19/2017 05:29 PM, Florian Weimer wrote:
>> 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.
> Ping?
>
> I rebased the attached patch to current master.
>
> I plan to remove the old handler functions in a subsequent patch. This
> patch only removes the alloca-based string manipulation, but leaves some
> uses of the legacy interfaces in place.
Yeah, I noticed while reviewing that the old handler was almost unused after
you split up the sequence into create/throw/free.
Thanks for doing this kind of structured cleanup and for introducing more
structure to the internals of ld.so.
(1) High level.
The idea of grouping the exception data into a single structure is both
logical and modular and provides for a cleaner interface.
(2) Design.
The removal of the intermediate alloca's from strdupa'ing the strings is
big win. It clarifies the semantics of ownership of the string storage
and is a good step forward in improving the internal structure of the
loader.
(3) Implementation.
You added a minimal number of key functions to create, free, and use the
new dl_exception structure. You made good use of the API internally to
delete a lot of boilerplate code. The existing tests should cover the
exception code well so no new tests need to be added.
Overall it looks good to me.
> 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.
>
> 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.
>
> diff --git a/elf/Makefile b/elf/Makefile
> index b54ebf8a98..d314a5fa7e 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)
OK.
> 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
OK.
> 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 e65f2fac20..79ffaf73d2 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;
OK.
> _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;
OK.
> +
> # Internal error handling support. Interposed by libc.so.
> + _dl_signal_exception; _dl_catch_exception;
OK.
> _dl_signal_error; _dl_catch_error;
>
> # Set value of a tunable.
> diff --git a/elf/dl-deps.c b/elf/dl-deps.c
> index 1b8bac6593..7c82d42be9 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);
OK.
> }
> diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c
> index 8e5888d4bd..8de6c87abf 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. */
OK.
> 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";
> -
OK.
> #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)
> + : ""));
> +}
OK.
> +
> +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)
OK.
> +
> 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);
OK.
> *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);
OK.
> }
> 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);
> +}
OK.
> +
> +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)
OK.
> {
> /* 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;
OK.
> 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;
> +}
OK.
> 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 0000000000..b4d0ca7578
> --- /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);
> + }
OK.
> +
> + 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);
> + }
> +}
OK.
> +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 3d2369dbf2..645dc3ebb4 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; \
> - })
> -
OK.
> /* 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);
OK.
> }
> *ref = NULL;
> return 0;
> diff --git a/elf/dl-open.c b/elf/dl-open.c
> index cec54db413..91a1d1a4f8 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);
OK.
> }
>
> assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
> diff --git a/elf/dl-sym.c b/elf/dl-sym.c
> index 7cd6e97643..fb54a91858 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);
>
OK.
> result = args.map;
> }
> diff --git a/elf/dl-version.c b/elf/dl-version.c
> index c00078e5e4..c0d76ad42a 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; \
> - })
> -
> -
OK.
> 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 4508365871..1c0b9cb32e 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
>
OK.
> @@ -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;
OK.
> 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 81c741b038..2d5c66ae28 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 bb18ff9bb2..a60053b914 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 1f0e3b494e..c69eb04ce5 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 19d3299d98..7bd541c28a 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 db9e24b090..3279c0af05 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 8ea4333846..f6f20a5d15 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 fd2b98c8b6..3820e2a4e6 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 1a2acfdb93..c70d6ea301 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 ca476bedd8..8ca23897df 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 b0d6dcae55..4430a5891e 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 50006317c7..e822e0a480 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 1c20d2f2b4..fead931d4e 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 6f8ed25922..c1209336d2 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 50006317c7..e822e0a480 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 f1f5effc24..2753547d97 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 2f6ff3c3a6..1668f4017e 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 912bd1a16e..b881b9096d 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 a1840cff31..c27a02b66a 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
OK.
--
Cheers,
Carlos.