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