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