(_nss_nisplus_parse_netent): Significant cleanups. Correct
[glibc/history.git] / elf / dl-error.c
blob79ebaaf01b51ad138d0857720a1f41d5fd3aae71
1 /* Error handling for runtime dynamic linker.
2 Copyright (C) 1995-2002,2004,2005 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
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.
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
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <libintl.h>
21 #include <setjmp.h>
22 #include <stdbool.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <ldsodefs.h>
28 /* This structure communicates state between _dl_catch_error and
29 _dl_signal_error. */
30 struct catch
32 const char *objname; /* Object/File name. */
33 const char *errstring; /* Error detail filled in here. */
34 bool malloced; /* Nonzero if the string is malloced
35 by the libc malloc. */
36 jmp_buf env; /* longjmp here on error. */
39 /* Multiple threads at once can use the `_dl_catch_error' function. The
40 calls can come from `_dl_map_object_deps', `_dlerror_run', or from
41 any of the libc functionality which loads dynamic objects (NSS, iconv).
42 Therefore we have to be prepared to save the state in thread-local
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. */
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. */
50 static const char _dl_out_of_memory[] = "out of memory";
53 /* This points to a function which is called when an continuable error is
54 received. Unlike the handling of `catch' this function may return.
55 The arguments will be the `errstring' and `objname'.
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. */
60 static receiver_fct receiver;
62 #ifdef _LIBC_REENTRANT
63 # define CATCH_HOOK (*(struct catch **) (*GL(dl_error_catch_tsd)) ())
64 #else
65 static struct catch *catch_hook;
66 # define CATCH_HOOK catch_hook
67 #endif
69 void
70 internal_function
71 _dl_signal_error (int errcode, const char *objname, const char *occation,
72 const char *errstring)
74 struct catch *lcatch;
76 if (! errstring)
77 errstring = N_("DYNAMIC LINKER BUG!!!");
79 lcatch = CATCH_HOOK;
80 if (objname == NULL)
81 objname = "";
82 if (lcatch != NULL)
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
86 stack. The object name is always a string constant. */
87 size_t len_objname = strlen (objname) + 1;
88 size_t len_errstring = strlen (errstring) + 1;
90 lcatch->errstring = (char *) malloc (len_objname + len_errstring);
91 if (lcatch->errstring != NULL)
93 /* Make a copy of the object file name and the error string. */
94 lcatch->objname = memcpy (__mempcpy ((char *) lcatch->errstring,
95 errstring, len_errstring),
96 objname, len_objname);
98 /* If the main executable is relocated it means the libc's malloc
99 is used. */
100 #ifdef SHARED
101 lcatch->malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
102 && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated
103 != 0));
104 #else
105 lcatch->malloced = true;
106 #endif
108 else
110 /* This is better than nothing. */
111 lcatch->objname = "";
112 lcatch->errstring = _dl_out_of_memory;
113 lcatch->malloced = false;
115 /* We do not restore the signal mask because none was saved. */
116 __longjmp (lcatch->env[0].__jmpbuf, errcode ?: -1);
118 else
120 /* Lossage while resolving the program's own symbols is always fatal. */
121 char buffer[1024];
122 _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n",
123 rtld_progname ?: "<program name unknown>",
124 occation ?: N_("error while loading shared libraries"),
125 objname, *objname ? ": " : "",
126 errstring, errcode ? ": " : "",
127 (errcode
128 ? __strerror_r (errcode, buffer, sizeof buffer)
129 : ""));
134 void
135 internal_function
136 _dl_signal_cerror (int errcode, const char *objname, const char *occation,
137 const char *errstring)
139 if (__builtin_expect (GLRO(dl_debug_mask)
140 & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
141 _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation,
142 errstring, receiver ? "continued" : "fatal");
144 if (receiver)
146 /* We are inside _dl_receive_error. Call the user supplied
147 handler and resume the work. The receiver will still be
148 installed. */
149 (*receiver) (errcode, objname, errstring);
151 else
152 _dl_signal_error (errcode, objname, occation, errstring);
157 internal_function
158 _dl_catch_error (const char **objname, const char **errstring,
159 bool *mallocedp, void (*operate) (void *), void *args)
161 int errcode;
162 struct catch *volatile old;
163 struct catch c;
164 /* We need not handle `receiver' since setting a `catch' is handled
165 before it. */
167 /* Some systems (e.g., SPARC) handle constructors to local variables
168 inefficient. So we initialize `c' by hand. */
169 c.errstring = NULL;
171 struct catch **const catchp = &CATCH_HOOK;
172 old = *catchp;
173 /* Do not save the signal mask. */
174 errcode = __sigsetjmp (c.env, 0);
175 if (__builtin_expect (errcode, 0) == 0)
177 *catchp = &c;
178 (*operate) (args);
179 *catchp = old;
180 *objname = NULL;
181 *errstring = NULL;
182 *mallocedp = false;
183 return 0;
186 /* We get here only if we longjmp'd out of OPERATE. */
187 *catchp = old;
188 *objname = c.objname;
189 *errstring = c.errstring;
190 *mallocedp = c.malloced;
191 return errcode == -1 ? 0 : errcode;
195 void
196 internal_function
197 _dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args)
199 struct catch **const catchp = &CATCH_HOOK;
200 struct catch *old_catch;
201 receiver_fct old_receiver;
203 old_catch = *catchp;
204 old_receiver = receiver;
206 /* Set the new values. */
207 *catchp = NULL;
208 receiver = fct;
210 (*operate) (args);
212 *catchp = old_catch;
213 receiver = old_receiver;