]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dl-error.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / elf / dl-error.c
CommitLineData
d66e34cd 1/* Error handling for runtime dynamic linker.
b168057a 2 Copyright (C) 1995-2015 Free Software Foundation, Inc.
afd4eb37
UD
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
afd4eb37
UD
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 13 Lesser General Public License for more details.
afd4eb37 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
d66e34cd 18
8e17ea58 19#include <libintl.h>
d66e34cd 20#include <setjmp.h>
74780cf6 21#include <stdbool.h>
14bab8de 22#include <stdlib.h>
0200214b 23#include <string.h>
7dea968e 24#include <unistd.h>
a42195db 25#include <ldsodefs.h>
0200214b
RM
26
27/* This structure communicates state between _dl_catch_error and
28 _dl_signal_error. */
29struct catch
30 {
eacfdfbf
RM
31 const char **objname; /* Object/File name. */
32 const char **errstring; /* Error detail filled in here. */
33 bool *malloced; /* Nonzero if the string is malloced
74780cf6 34 by the libc malloc. */
eacfdfbf 35 volatile int *errcode; /* Return value of _dl_signal_error. */
0200214b
RM
36 jmp_buf env; /* longjmp here on error. */
37 };
38
be935610 39/* Multiple threads at once can use the `_dl_catch_error' function. The
6e4c40ba 40 calls can come from `_dl_map_object_deps', `_dlerror_run', or from
be935610 41 any of the libc functionality which loads dynamic objects (NSS, iconv).
6e4c40ba 42 Therefore we have to be prepared to save the state in thread-local
ce460d04
RM
43 memory. The _dl_error_catch_tsd function pointer is reset by the thread
44 library so that it returns the address of a thread-local variable. */
be935610
UD
45
46
ca3c0135
UD
47/* This message we return as a last resort. We define the string in a
48 variable since we have to avoid freeing it and so have to enable
49 a pointer comparison. See below and in dlfcn/dlerror.c. */
74780cf6 50static const char _dl_out_of_memory[] = "out of memory";
ca3c0135
UD
51
52
3f933dc2 53/* This points to a function which is called when an continuable error is
fd26970f 54 received. Unlike the handling of `catch' this function may return.
be935610
UD
55 The arguments will be the `errstring' and `objname'.
56
57 Since this functionality is not used in normal programs (only in ld.so)
58 we do not care about multi-threaded programs here. We keep this as a
59 global variable. */
fd26970f
UD
60static receiver_fct receiver;
61
bf2cc5fb
RM
62#ifdef _LIBC_REENTRANT
63# define CATCH_HOOK (*(struct catch **) (*GL(dl_error_catch_tsd)) ())
64#else
65static struct catch *catch_hook;
66# define CATCH_HOOK catch_hook
67#endif
d66e34cd
RM
68
69void
d0fc4041 70internal_function
407fe3bb
UD
71_dl_signal_error (int errcode, const char *objname, const char *occation,
72 const char *errstring)
d66e34cd 73{
be935610
UD
74 struct catch *lcatch;
75
0200214b 76 if (! errstring)
8e17ea58 77 errstring = N_("DYNAMIC LINKER BUG!!!");
0200214b 78
bf2cc5fb 79 lcatch = CATCH_HOOK;
2373b30e
UD
80 if (objname == NULL)
81 objname = "";
be935610 82 if (lcatch != NULL)
0200214b 83 {
dcf0671d
UD
84 /* We are inside _dl_catch_error. Return to it. We have to
85 duplicate the error string since it might be allocated on the
8e17ea58 86 stack. The object name is always a string constant. */
170ef42f
UD
87 size_t len_objname = strlen (objname) + 1;
88 size_t len_errstring = strlen (errstring) + 1;
89
eacfdfbf
RM
90 char *errstring_copy = malloc (len_objname + len_errstring);
91 if (errstring_copy != NULL)
74780cf6
UD
92 {
93 /* Make a copy of the object file name and the error string. */
eacfdfbf
RM
94 *lcatch->objname = memcpy (__mempcpy (errstring_copy,
95 errstring, len_errstring),
96 objname, len_objname);
97 *lcatch->errstring = errstring_copy;
74780cf6
UD
98
99 /* If the main executable is relocated it means the libc's malloc
100 is used. */
eacfdfbf 101 bool malloced = true;
74780cf6 102#ifdef SHARED
eacfdfbf
RM
103 malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
104 && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0));
74780cf6 105#endif
eacfdfbf 106 *lcatch->malloced = malloced;
74780cf6 107 }
170ef42f
UD
108 else
109 {
110 /* This is better than nothing. */
eacfdfbf
RM
111 *lcatch->objname = "";
112 *lcatch->errstring = _dl_out_of_memory;
113 *lcatch->malloced = false;
170ef42f 114 }
eacfdfbf
RM
115
116 *lcatch->errcode = errcode;
117
b15cc6a1 118 /* We do not restore the signal mask because none was saved. */
eacfdfbf 119 __longjmp (lcatch->env[0].__jmpbuf, 1);
0200214b
RM
120 }
121 else
122 {
123 /* Lossage while resolving the program's own symbols is always fatal. */
1618c590 124 char buffer[1024];
407fe3bb 125 _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n",
b9375348 126 RTLD_PROGNAME,
407fe3bb 127 occation ?: N_("error while loading shared libraries"),
2373b30e 128 objname, *objname ? ": " : "",
0200214b 129 errstring, errcode ? ": " : "",
1618c590 130 (errcode
310b3460 131 ? __strerror_r (errcode, buffer, sizeof buffer)
35fc382a 132 : ""));
0200214b 133 }
d66e34cd
RM
134}
135
3f933dc2
UD
136
137void
138internal_function
407fe3bb 139_dl_signal_cerror (int errcode, const char *objname, const char *occation,
3f933dc2
UD
140 const char *errstring)
141{
afdca0f2 142 if (__builtin_expect (GLRO(dl_debug_mask)
d92cdffb 143 & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
154d10bd
UD
144 _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation,
145 errstring, receiver ? "continued" : "fatal");
8081721a 146
3f933dc2
UD
147 if (receiver)
148 {
149 /* We are inside _dl_receive_error. Call the user supplied
150 handler and resume the work. The receiver will still be
151 installed. */
152 (*receiver) (errcode, objname, errstring);
153 }
154 else
154d10bd 155 _dl_signal_error (errcode, objname, occation, errstring);
3f933dc2
UD
156}
157
158
d66e34cd 159int
d0fc4041 160internal_function
8e17ea58 161_dl_catch_error (const char **objname, const char **errstring,
74780cf6 162 bool *mallocedp, void (*operate) (void *), void *args)
d66e34cd 163{
993b3242 164 /* We need not handle `receiver' since setting a `catch' is handled
fd26970f 165 before it. */
d66e34cd 166
eacfdfbf
RM
167 /* Only this needs to be marked volatile, because it is the only local
168 variable that gets changed between the setjmp invocation and the
169 longjmp call. All others are just set here (before setjmp) and read
170 in _dl_signal_error (before longjmp). */
171 volatile int errcode;
172
173 struct catch c;
174 /* Don't use an initializer since we don't need to clear C.env. */
175 c.objname = objname;
176 c.errstring = errstring;
177 c.malloced = mallocedp;
178 c.errcode = &errcode;
993b3242 179
bf2cc5fb 180 struct catch **const catchp = &CATCH_HOOK;
eacfdfbf
RM
181 struct catch *const old = *catchp;
182 *catchp = &c;
183
8292f6fc 184 /* Do not save the signal mask. */
eacfdfbf 185 if (__builtin_expect (__sigsetjmp (c.env, 0), 0) == 0)
a1a9d215 186 {
993b3242 187 (*operate) (args);
ce460d04 188 *catchp = old;
8e17ea58 189 *objname = NULL;
14bab8de 190 *errstring = NULL;
74780cf6 191 *mallocedp = false;
a1a9d215
RM
192 return 0;
193 }
194
eacfdfbf
RM
195 /* We get here only if we longjmp'd out of OPERATE. _dl_signal_error has
196 already stored values into *OBJNAME, *ERRSTRING, and *MALLOCEDP. */
ce460d04 197 *catchp = old;
eacfdfbf 198 return errcode;
d66e34cd 199}
7969407a 200
fd26970f
UD
201
202void
d0fc4041 203internal_function
993b3242 204_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args)
fd26970f 205{
bf2cc5fb 206 struct catch **const catchp = &CATCH_HOOK;
fd26970f
UD
207 struct catch *old_catch;
208 receiver_fct old_receiver;
209
ce460d04 210 old_catch = *catchp;
fd26970f
UD
211 old_receiver = receiver;
212
213 /* Set the new values. */
ce460d04 214 *catchp = NULL;
fd26970f
UD
215 receiver = fct;
216
993b3242 217 (*operate) (args);
fd26970f 218
ce460d04 219 *catchp = old_catch;
fd26970f
UD
220 receiver = old_receiver;
221}