1 /* @(#)raisecond.c	1.22 09/07/10 Copyright 1985, 1989, 1995-2004 J. Schilling */
2 /*
3  *	raise a condition (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  *	Check for installed condition handlers.
20  *	If a handler is found, the function is called with the appropriate args.
21  *	If no handler is found or no handler signals success,
22  *	the program will be aborted.
23  *
24  *	Copyright (c) 1985, 1989, 1995-2004 J. Schilling
25  */
26 #include <schily/mconfig.h>
27 #include <schily/stdio.h>
28 #include <schily/standard.h>
29 #include <schily/sigblk.h>
30 #include <schily/unistd.h>
31 #include <schily/stdlib.h>
32 #include <schily/string.h>
33 #include <schily/avoffset.h>
34 #include <schily/schily.h>
35 
36 #if	!defined(AV_OFFSET) || !defined(FP_INDIR)
37 #	ifdef	HAVE_SCANSTACK
38 #	undef	HAVE_SCANSTACK
39 #	endif
40 #endif
41 
42 /*
43  * Macros to print to stderr without stdio, to avoid screwing up.
44  */
45 #ifndef	STDERR_FILENO
46 #define	STDERR_FILENO	2
47 #endif
48 #define	eprints(a)	(void)write(STDERR_FILENO, (a), sizeof (a)-1)
49 #define	eprintl(a)	(void)write(STDERR_FILENO, (a), strlen(a))
50 
51 #define	is_even(p)	((((long)(p)) & 1) == 0)
52 #define	even(p)		(((long)(p)) & ~1L)
53 #ifdef	__future__
54 #define	even(p)		(((long)(p)) - 1) /* will this work with 64 bit ?? */
55 #endif
56 
57 
58 LOCAL	void raiseabort  __PR((const char *));
59 
60 #ifdef	HAVE_SCANSTACK
61 #include <schily/stkframe.h>
62 #define	next_frame(vp)	do {						    \
63 				if (((struct frame *)(vp))->fr_savfp == 0) { \
64 					vp = (void *)0;			    \
65 					break;				    \
66 				}					    \
67 				if (((struct frame *)(vp))->fr_savpc == 0) { \
68 					vp = (void *)0;			    \
69 					break;				    \
70 				}					    \
71 				vp =					    \
72 				    (void *)((struct frame *)(vp))->fr_savfp; \
73 			} while (vp != NULL && is_even(vp));		    \
74 			vp = (struct frame *)even(vp);
75 #else
76 #if	defined(IS_MACOS_X)
77 /*
78  * The MAC OS X linker does not grok "common" varaibles.
79  * Make __roothandle a "data" variable.
80  */
81 EXPORT	SIGBLK	*__roothandle = 0;
82 #else
83 EXPORT	SIGBLK	*__roothandle;
84 #endif
85 
86 #define	next_frame(vp)	vp = (((SIGBLK *)(vp))->sb_savfp);
87 #endif
88 
89 LOCAL	BOOL framehandle __PR((SIGBLK *, const char *, const char *, long));
90 
91 /*
92  *	Loop through the chain of procedure frames on the stack.
93  *
94  *	Frame pointers normally have even values.
95  *	Frame pointers of procedures with an installed handler are marked odd.
96  *	The even base value, in this case actually points to a SIGBLK which
97  *	holds the saved "real" frame pointer.
98  *	The SIGBLK mentioned above may me the start of a chain of SIGBLK's,
99  *	containing different handlers.
100  */
101 EXPORT void
raisecond(signame,arg2)102 raisecond(signame, arg2)
103 	const char	*signame;
104 	long		arg2;
105 {
106 	register void	*vp = NULL;
107 
108 #ifdef	HAVE_SCANSTACK
109 	/*
110 	 * As the SCO OpenServer C-Compiler has a bug that may cause
111 	 * the first function call to getfp() been done before the
112 	 * new stack frame is created, we call getfp() twice.
113 	 */
114 	(void) getfp();
115 	vp = getfp();
116 	next_frame(vp);
117 #else
118 	vp = __roothandle;
119 #endif
120 
121 	while (vp) {
122 		if (framehandle((SIGBLK *)vp, signame, signame, arg2))
123 			return;
124 		else if (framehandle((SIGBLK *)vp, "any_other", signame, arg2))
125 			return;
126 #ifdef	HAVE_SCANSTACK
127 		vp = (struct frame *)((SIGBLK *)vp)->sb_savfp;
128 #endif
129 		next_frame(vp);
130 	}
131 	/*
132 	 * No matching handler that signals success found.
133 	 * Print error message and abort.
134 	 */
135 	raiseabort(signame);
136 	/* NOTREACHED */
137 }
138 
139 /*
140  *	Loop through the handler chain for a procedure frame.
141  *
142  *	If no handler with matching name is found, return FALSE,
143  *	otherwise the first handler with matching name is called.
144  *	The return value in the latter case depends on the called function.
145  */
146 LOCAL BOOL
framehandle(sp,handlename,signame,arg2)147 framehandle(sp, handlename, signame, arg2)
148 	register SIGBLK *sp;
149 	const char	*handlename;
150 	const char	*signame;
151 	long		arg2;
152 {
153 	for (; sp; sp = sp->sb_signext) {
154 		if (sp->sb_signame != NULL &&
155 		    streql(sp->sb_signame, handlename)) {
156 			if (sp->sb_sigfun == NULL) {	/* deactivated */
157 				return (FALSE);
158 			} else {
159 				return (*sp->sb_sigfun)(signame,
160 							sp->sb_sigarg, arg2);
161 			}
162 		}
163 	}
164 	return (FALSE);
165 }
166 
167 LOCAL void
raiseabort(signame)168 raiseabort(signame)
169 	const	char	*signame;
170 {
171 	eprints("Condition not caught: "); eprintl(signame); eprints(".\n");
172 	abort();
173 	/* NOTREACHED */
174 }
175