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