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