1 /*
2 * This file has been modified for the cdrkit suite.
3 *
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
6 *
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
10 *
11 */
12
13 /* @(#)handlecond.c 1.22 04/05/09 Copyright 1985-2004 J. Schilling */
14 /*
15 * setup/clear a condition handler for a software signal
16 */
17 /*
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License version 2
20 * as published by the Free Software Foundation.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License along with
28 * this program; see the file COPYING. If not, write to the Free Software
29 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 */
31 /*
32 * A procedure frame is marked to have handlers if the
33 * previous freme pointer for this procedure is odd.
34 * The even base value, in this case actually points to a SIGBLK which
35 * holds the saved "real" frame pointer.
36 * The SIGBLK mentioned above may me the start of a chain of SIGBLK's,
37 * containing different handlers.
38 *
39 * This will work on processors which support a frame pointer chain
40 * on the stack.
41 * On a processor which doesn't support this I think of a method
42 * where handlecond() has an own chain of frames, holding chains of
43 * SIGBLK's.
44 * In this case, a parameter has to be added to handlecond() and
45 * unhandlecond(). This parameter will be an opaque cookie which is zero
46 * on the first call to handlecond() in a procedure.
47 * A new cookie will be returned by handlecond() which must be used on
48 * each subsequent call to handlecond() and unhandlecond() in the same
49 * procedure.
50 *
51 * Copyright (c) 1985-2004 J. Schilling
52 */
53 #include <mconfig.h>
54 #include <sigblk.h>
55 #include <standard.h>
56 #include <stdxlib.h>
57 #include <strdefs.h>
58 #include <avoffset.h>
59 #include <utypes.h>
60 #include <schily.h>
61
62 #if !defined(AV_OFFSET) || !defined(FP_INDIR)
63 # ifdef HAVE_SCANSTACK
64 # undef HAVE_SCANSTACK
65 # endif
66 #endif
67
68 #ifdef HAVE_SCANSTACK
69 #include <stkframe.h>
70 #else
71 extern SIGBLK *__roothandle;
72 #endif /* HAVE_SCANSTACK */
73
74 #define is_even(p) ((((long)(p)) & 1) == 0)
75 #define even(p) (((long)(p)) & ~1L)
76 #if defined(__sun) && defined(__i386)
77 /*
78 * Solaris x86 has a broken frame.h which defines the frame ptr to int.
79 */
80 #define odd(p) (((Intptr_t)(p)) | 1)
81 #else
82 #define odd(p) (void *)(((Intptr_t)(p)) | 1)
83 #endif
84
85 #ifdef __future__
86 #define even(p) (((long)(p)) - 1) /* will this work with 64 bit ?? */
87 #endif
88
89 EXPORT void starthandlecond __PR((SIGBLK *sp));
90
91 #ifdef PROTOTYPES
92 EXPORT void
handlecond(const char * signame,register SIGBLK * sp,int (* func)(const char *,long,long),long arg1)93 handlecond(const char *signame,
94 register SIGBLK *sp,
95 int (*func)(const char *, long, long),
96 long arg1)
97 #else
98 EXPORT void
99 handlecond(signame, sp, func, arg1)
100 char *signame;
101 register SIGBLK *sp;
102 BOOL (*func)();
103 long arg1;
104 #endif
105 {
106 register SIGBLK *this;
107 register SIGBLK *last = (SIGBLK *)NULL;
108 #ifdef HAVE_SCANSTACK
109 struct frame *fp = (struct frame *)NULL;
110 #endif
111 int slen;
112
113 if (signame == NULL || (slen = strlen(signame)) == 0) {
114 raisecond("handle_bad_name", (long)signame);
115 abort();
116 }
117
118 #ifdef HAVE_SCANSTACK
119 fp = (struct frame *)getfp();
120 fp = (struct frame *)fp->fr_savfp; /* point to frame of caller */
121 if (is_even(fp->fr_savfp)) {
122 /*
123 * Easy case: no handlers yet
124 * save real framepointer in sp->sb_savfp
125 */
126 sp->sb_savfp = (long **)fp->fr_savfp;
127 this = (SIGBLK *)NULL;
128 } else {
129 this = (SIGBLK *)even(fp->fr_savfp);
130 }
131 #else
132 this = __roothandle;
133 #endif
134
135 for (; this; this = this->sb_signext) {
136 if (this == sp) {
137 /*
138 * If a SIGBLK is reused, the name must not change.
139 */
140 if (this->sb_signame != NULL &&
141 !streql(this->sb_signame, signame)) {
142 raisecond("handle_reused_block", (long)signame);
143 abort();
144 }
145 sp->sb_sigfun = func;
146 sp->sb_sigarg = arg1;
147 return;
148 }
149 if (this->sb_signame != NULL &&
150 streql(this->sb_signame, signame)) {
151 if (last == (SIGBLK *)NULL) {
152 /*
153 * 'this' is the first entry in chain
154 */
155 if (this->sb_signext == (SIGBLK *)NULL) {
156 /*
157 * only 'this' entry is in chain, copy
158 * saved real frame pointer into new sp
159 */
160 sp->sb_savfp = this->sb_savfp;
161 } else {
162 #ifdef HAVE_SCANSTACK
163 /*
164 * make second entry first link in chain
165 */
166 this->sb_signext->sb_savfp =
167 this->sb_savfp;
168 fp->fr_savfp = odd(this->sb_signext);
169 #else
170 /*
171 * Cannot happen if scanning the stack
172 * is not possible...
173 */
174 raisecond("handle_is_empty", (long)0);
175 abort();
176 #endif
177 }
178 continue; /* don't trash 'last' ptr */
179 } else {
180 last->sb_signext = this->sb_signext;
181 }
182 }
183 last = this;
184 }
185 sp->sb_signext = (SIGBLK *)NULL;
186 sp->sb_signame = signame;
187 sp->sb_siglen = slen;
188 sp->sb_sigfun = func;
189 sp->sb_sigarg = arg1;
190 /*
191 * If there is a chain append to end of the chain, else make it first
192 */
193 if (last)
194 last->sb_signext = sp;
195 #ifdef HAVE_SCANSTACK
196 else
197 fp->fr_savfp = odd(sp);
198 #else
199 /*
200 * Cannot happen if scanning the stack is not possible...
201 */
202 else {
203 raisecond("handle_is_empty", (long)0);
204 abort();
205 }
206 #endif
207 }
208
209 EXPORT void
starthandlecond(sp)210 starthandlecond(sp)
211 register SIGBLK *sp;
212 {
213 #ifdef HAVE_SCANSTACK
214 struct frame *fp = NULL;
215
216 /*
217 * As the SCO OpenServer C-Compiler has a bug that may cause
218 * the first function call to getfp() been done before the
219 * new stack frame is created, we call getfp() twice.
220 */
221 (void) getfp();
222 #endif
223
224 sp->sb_signext = (SIGBLK *)NULL;
225 sp->sb_signame = NULL;
226 sp->sb_siglen = 0;
227 sp->sb_sigfun = (handlefunc_t)NULL;
228 sp->sb_sigarg = 0;
229
230 #ifdef HAVE_SCANSTACK
231 fp = (struct frame *)getfp();
232 fp = (struct frame *)fp->fr_savfp; /* point to frame of caller */
233
234 if (is_even(fp->fr_savfp)) {
235 /*
236 * Easy case: no handlers yet
237 * save real framepointer in sp
238 */
239 sp->sb_savfp = (long **)fp->fr_savfp;
240 fp->fr_savfp = odd(sp);
241 } else {
242 raisecond("handle_not_empty", (long)0);
243 abort();
244 }
245 #else
246 sp->sb_savfp = (long **)__roothandle;
247 __roothandle = sp;
248 #endif
249 }
250
251 EXPORT void
unhandlecond(sp)252 unhandlecond(sp)
253 register SIGBLK *sp;
254 {
255 #ifdef HAVE_SCANSTACK
256 register struct frame *fp;
257 register SIGBLK *sps;
258
259 /*
260 * As the SCO OpenServer C-Compiler has a bug that may cause
261 * the first function call to getfp() been done before the
262 * new stack frame is created, we call getfp() twice.
263 */
264 (void) getfp();
265 fp = (struct frame *)getfp();
266 fp = (struct frame *)fp->fr_savfp; /* point to frame of caller */
267
268 if (!is_even(fp->fr_savfp)) { /* if handlers */
269 sps = (SIGBLK *)even(fp->fr_savfp); /* point to SIGBLK */
270 /* real framepointer */
271 #if defined(__sun) && defined(__i386)
272 fp->fr_savfp = (intptr_t)sps->sb_savfp;
273 #else
274 fp->fr_savfp = (struct frame *)sps->sb_savfp;
275 #endif
276 }
277 #else
278 if (__roothandle == NULL) {
279 raisecond("handle_is_empty", (long)0);
280 abort();
281 }
282 /*
283 * Pop top level handler chain.
284 */
285 __roothandle = (SIGBLK *)__roothandle->sb_savfp;
286 #endif
287 }
288