]>
Commit | Line | Data |
---|---|---|
d66e34cd | 1 | /* Error handling for runtime dynamic linker. |
df4ef2ab | 2 | Copyright (C) 1995, 1996, 1997 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 | |
6 | modify it under the terms of the GNU Library General Public License as | |
7 | published by the Free Software Foundation; either version 2 of the | |
8 | License, or (at your option) any later version. | |
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 | |
13 | Library General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Library General Public | |
16 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
d66e34cd RM |
19 | |
20 | #include <stddef.h> | |
21 | #include <link.h> | |
22 | #include <setjmp.h> | |
14bab8de | 23 | #include <stdlib.h> |
0200214b RM |
24 | #include <string.h> |
25 | ||
1618c590 UD |
26 | /* This is the internal function we use to generate the error string. */ |
27 | extern char *_strerror_internal __P ((int, char *, size_t)); | |
28 | ||
0200214b RM |
29 | /* This structure communicates state between _dl_catch_error and |
30 | _dl_signal_error. */ | |
31 | struct catch | |
32 | { | |
14bab8de UD |
33 | char *errstring; /* Error detail filled in here. */ |
34 | const char *objname; | |
0200214b RM |
35 | jmp_buf env; /* longjmp here on error. */ |
36 | }; | |
37 | ||
38 | /* This points to such a structure during a call to _dl_catch_error. | |
39 | During implicit startup and run-time work for needed shared libraries, | |
40 | this is null. */ | |
41 | static struct catch *catch; | |
d66e34cd | 42 | |
fd26970f UD |
43 | /* This points to a function which is called when an error is |
44 | received. Unlike the handling of `catch' this function may return. | |
45 | The arguments will be the `errstring' and `objname'. */ | |
46 | static receiver_fct receiver; | |
47 | ||
d66e34cd RM |
48 | |
49 | void | |
421f82e5 RM |
50 | _dl_signal_error (int errcode, |
51 | const char *objname, | |
52 | const char *errstring) | |
d66e34cd | 53 | { |
0200214b RM |
54 | if (! errstring) |
55 | errstring = "DYNAMIC LINKER BUG!!!"; | |
56 | ||
57 | if (catch) | |
58 | { | |
dcf0671d UD |
59 | /* We are inside _dl_catch_error. Return to it. We have to |
60 | duplicate the error string since it might be allocated on the | |
61 | stack. */ | |
62 | size_t len = strlen (errstring) + 1; | |
63 | catch->errstring = malloc (len); | |
64 | if (catch->errstring != NULL) | |
65 | memcpy (catch->errstring, errstring, len); | |
0200214b RM |
66 | catch->objname = objname; |
67 | longjmp (catch->env, errcode ?: -1); | |
68 | } | |
fd26970f UD |
69 | else if (receiver) |
70 | { | |
71 | /* We are inside _dl_receive_error. Call the user supplied | |
c84142e8 | 72 | handler and resume the work. The receiver will still be |
fd26970f | 73 | installed. */ |
c84142e8 | 74 | (*receiver) (errcode, objname, errstring); |
fd26970f | 75 | } |
0200214b RM |
76 | else |
77 | { | |
78 | /* Lossage while resolving the program's own symbols is always fatal. */ | |
79 | extern char **_dl_argv; /* Set in rtld.c at startup. */ | |
1618c590 | 80 | char buffer[1024]; |
0200214b | 81 | _dl_sysdep_fatal (_dl_argv[0] ?: "<program name unknown>", |
40a55d20 | 82 | ": error in loading shared libraries: ", |
f43ce637 | 83 | objname ?: "", objname && *objname ? ": " : "", |
0200214b | 84 | errstring, errcode ? ": " : "", |
1618c590 UD |
85 | (errcode |
86 | ? _strerror_internal (errcode, buffer, sizeof buffer) | |
87 | : ""), "\n", NULL); | |
0200214b | 88 | } |
d66e34cd RM |
89 | } |
90 | ||
91 | int | |
14bab8de | 92 | _dl_catch_error (char **errstring, |
421f82e5 | 93 | const char **objname, |
993b3242 UD |
94 | void (*operate) (void *), |
95 | void *args) | |
d66e34cd RM |
96 | { |
97 | int errcode; | |
993b3242 UD |
98 | struct catch *old, c; |
99 | /* We need not handle `receiver' since setting a `catch' is handled | |
fd26970f | 100 | before it. */ |
d66e34cd | 101 | |
1618c590 | 102 | /* Some systems (e.g., SPARC) handle constructors to local variables |
993b3242 UD |
103 | inefficient. So we initialize `c' by hand. */ |
104 | c.errstring = NULL; | |
105 | c.objname = NULL; | |
106 | ||
df4ef2ab | 107 | old = catch; |
0200214b | 108 | errcode = setjmp (c.env); |
a1a9d215 RM |
109 | if (errcode == 0) |
110 | { | |
0200214b | 111 | catch = &c; |
993b3242 | 112 | (*operate) (args); |
df4ef2ab | 113 | catch = old; |
14bab8de UD |
114 | *errstring = NULL; |
115 | *objname = NULL; | |
a1a9d215 RM |
116 | return 0; |
117 | } | |
118 | ||
119 | /* We get here only if we longjmp'd out of OPERATE. */ | |
df4ef2ab | 120 | catch = old; |
0200214b RM |
121 | *errstring = c.errstring; |
122 | *objname = c.objname; | |
a1a9d215 | 123 | return errcode == -1 ? 0 : errcode; |
d66e34cd | 124 | } |
fd26970f UD |
125 | |
126 | void | |
993b3242 | 127 | _dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args) |
fd26970f UD |
128 | { |
129 | struct catch *old_catch; | |
130 | receiver_fct old_receiver; | |
131 | ||
132 | old_catch = catch; | |
133 | old_receiver = receiver; | |
134 | ||
135 | /* Set the new values. */ | |
136 | catch = NULL; | |
137 | receiver = fct; | |
138 | ||
993b3242 | 139 | (*operate) (args); |
fd26970f UD |
140 | |
141 | catch = old_catch; | |
142 | receiver = old_receiver; | |
143 | } |