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.
This commit is contained in:
Florian Weimer 2017-08-10 13:40:22 +02:00
parent f87cc2bfba
commit 2449ae7b2d
29 changed files with 529 additions and 239 deletions

View file

@ -1,3 +1,63 @@
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

View file

@ -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

View file

@ -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.

View file

@ -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);
}

View file

@ -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,65 +113,42 @@ _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,
@ -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

202
elf/dl-exception.c Normal file
View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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. */

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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