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