]>
Commit | Line | Data |
---|---|---|
38cbfe40 RK |
1 | /**************************************************************************** |
2 | * * | |
3 | * GNAT COMPILER COMPONENTS * | |
4 | * * | |
5 | * I N I T * | |
6 | * * | |
38cbfe40 RK |
7 | * C Implementation File * |
8 | * * | |
df87f988 | 9 | * Copyright (C) 1992-2003 Free Software Foundation, Inc. * |
38cbfe40 RK |
10 | * * |
11 | * GNAT is free software; you can redistribute it and/or modify it under * | |
12 | * terms of the GNU General Public License as published by the Free Soft- * | |
13 | * ware Foundation; either version 2, or (at your option) any later ver- * | |
14 | * sion. GNAT is distributed in the hope that it will be useful, but WITH- * | |
15 | * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * | |
16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * | |
17 | * for more details. You should have received a copy of the GNU General * | |
18 | * Public License distributed with GNAT; see file COPYING. If not, write * | |
19 | * to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, * | |
20 | * MA 02111-1307, USA. * | |
21 | * * | |
22 | * As a special exception, if you link this file with other files to * | |
23 | * produce an executable, this file does not by itself cause the resulting * | |
24 | * executable to be covered by the GNU General Public License. This except- * | |
25 | * ion does not however invalidate any other reasons why the executable * | |
26 | * file might be covered by the GNU Public License. * | |
27 | * * | |
28 | * GNAT was originally developed by the GNAT team at New York University. * | |
71ff80dc | 29 | * Extensive contributions were provided by Ada Core Technologies Inc. * |
38cbfe40 RK |
30 | * * |
31 | ****************************************************************************/ | |
32 | ||
33 | /* This unit contains initialization circuits that are system dependent. A | |
34 | major part of the functionality involved involves stack overflow checking. | |
35 | The GCC backend generates probe instructions to test for stack overflow. | |
36 | For details on the exact approach used to generate these probes, see the | |
37 | "Using and Porting GCC" manual, in particular the "Stack Checking" section | |
38 | and the subsection "Specifying How Stack Checking is Done". The handlers | |
39 | installed by this file are used to handle resulting signals that come | |
40 | from these probes failing (i.e. touching protected pages) */ | |
41 | ||
42 | /* The following include is here to meet the published VxWorks requirement | |
43 | that the __vxworks header appear before any other include. */ | |
44 | #ifdef __vxworks | |
45 | #include "vxWorks.h" | |
46 | #endif | |
47 | ||
48 | #ifdef IN_RTS | |
49 | #include "tconfig.h" | |
50 | #include "tsystem.h" | |
51 | #include <sys/stat.h> | |
07fc65c4 GB |
52 | |
53 | /* We don't have libiberty, so us malloc. */ | |
54 | #define xmalloc(S) malloc (S) | |
38cbfe40 RK |
55 | #else |
56 | #include "config.h" | |
57 | #include "system.h" | |
58 | #endif | |
59 | ||
60 | #include "adaint.h" | |
61 | #include "raise.h" | |
62 | ||
63 | extern void __gnat_raise_program_error (const char *, int); | |
64 | ||
65 | /* Addresses of exception data blocks for predefined exceptions. */ | |
66 | extern struct Exception_Data constraint_error; | |
67 | extern struct Exception_Data numeric_error; | |
68 | extern struct Exception_Data program_error; | |
69 | extern struct Exception_Data storage_error; | |
70 | extern struct Exception_Data tasking_error; | |
71 | extern struct Exception_Data _abort_signal; | |
72 | ||
73 | #define Lock_Task system__soft_links__lock_task | |
74 | extern void (*Lock_Task) PARAMS ((void)); | |
75 | ||
76 | #define Unlock_Task system__soft_links__unlock_task | |
77 | extern void (*Unlock_Task) PARAMS ((void)); | |
78 | ||
79 | #define Get_Machine_State_Addr \ | |
80 | system__soft_links__get_machine_state_addr | |
81 | extern struct Machine_State *(*Get_Machine_State_Addr) PARAMS ((void)); | |
82 | ||
83 | #define Check_Abort_Status \ | |
84 | system__soft_links__check_abort_status | |
85 | extern int (*Check_Abort_Status) PARAMS ((void)); | |
86 | ||
87 | #define Raise_From_Signal_Handler \ | |
88 | ada__exceptions__raise_from_signal_handler | |
89 | extern void Raise_From_Signal_Handler PARAMS ((struct Exception_Data *, | |
45659035 | 90 | const char *)); |
38cbfe40 RK |
91 | |
92 | #define Propagate_Signal_Exception \ | |
93 | __gnat_propagate_sig_exc | |
94 | extern void Propagate_Signal_Exception | |
45659035 | 95 | PARAMS ((struct Machine_State *, struct Exception_Data *, const char *)); |
38cbfe40 | 96 | |
38cbfe40 | 97 | /* Copies of global values computed by the binder */ |
07fc65c4 GB |
98 | int __gl_main_priority = -1; |
99 | int __gl_time_slice_val = -1; | |
100 | char __gl_wc_encoding = 'n'; | |
101 | char __gl_locking_policy = ' '; | |
102 | char __gl_queuing_policy = ' '; | |
07fc65c4 | 103 | char __gl_task_dispatching_policy = ' '; |
fbf5a39b AC |
104 | char *__gl_restrictions = 0; |
105 | char *__gl_interrupt_states = 0; | |
106 | int __gl_num_interrupt_states = 0; | |
07fc65c4 GB |
107 | int __gl_unreserve_all_interrupts = 0; |
108 | int __gl_exception_tracebacks = 0; | |
109 | int __gl_zero_cost_exceptions = 0; | |
38cbfe40 | 110 | |
fbf5a39b | 111 | /* Indication of whether synchronous signal handler has already been |
38cbfe40 RK |
112 | installed by a previous call to adainit */ |
113 | int __gnat_handler_installed = 0; | |
114 | ||
115 | /* HAVE_GNAT_INIT_FLOAT must be set on every targets where a __gnat_init_float | |
116 | is defined. If this is not set them a void implementation will be defined | |
117 | at the end of this unit. */ | |
118 | #undef HAVE_GNAT_INIT_FLOAT | |
119 | ||
fbf5a39b AC |
120 | /******************************/ |
121 | /* __gnat_get_interrupt_state */ | |
122 | /******************************/ | |
123 | ||
124 | char __gnat_get_interrupt_state (int); | |
125 | ||
126 | /* This routine is called from the runtime as needed to determine the state | |
127 | of an interrupt, as set by an Interrupt_State pragma appearing anywhere | |
128 | in the current partition. The input argument is the interrupt number, | |
129 | and the result is one of the following: | |
130 | ||
131 | 'n' this interrupt not set by any Interrupt_State pragma | |
132 | 'u' Interrupt_State pragma set state to User | |
133 | 'r' Interrupt_State pragma set state to Runtime | |
134 | 's' Interrupt_State pragma set state to System */ | |
135 | ||
136 | char | |
137 | __gnat_get_interrupt_state (intrup) | |
138 | int intrup; | |
139 | { | |
140 | if (intrup >= __gl_num_interrupt_states) | |
141 | return 'n'; | |
142 | else | |
143 | return __gl_interrupt_states [intrup]; | |
144 | } | |
145 | ||
38cbfe40 RK |
146 | /**********************/ |
147 | /* __gnat_set_globals */ | |
148 | /**********************/ | |
149 | ||
150 | /* This routine is called from the binder generated main program. It copies | |
151 | the values for global quantities computed by the binder into the following | |
152 | global locations. The reason that we go through this copy, rather than just | |
153 | define the global locations in the binder generated file, is that they are | |
154 | referenced from the runtime, which may be in a shared library, and the | |
155 | binder file is not in the shared library. Global references across library | |
156 | boundaries like this are not handled correctly in all systems. */ | |
157 | ||
158 | void | |
fbf5a39b AC |
159 | __gnat_set_globals (main_priority, |
160 | time_slice_val, | |
161 | wc_encoding, | |
162 | locking_policy, | |
163 | queuing_policy, | |
164 | task_dispatching_policy, | |
165 | restrictions, | |
166 | interrupt_states, | |
167 | num_interrupt_states, | |
168 | unreserve_all_interrupts, | |
169 | exception_tracebacks, | |
07fc65c4 | 170 | zero_cost_exceptions) |
38cbfe40 RK |
171 | int main_priority; |
172 | int time_slice_val; | |
07fc65c4 | 173 | char wc_encoding; |
fbf5a39b AC |
174 | char locking_policy; |
175 | char queuing_policy; | |
176 | char task_dispatching_policy; | |
07fc65c4 | 177 | char *restrictions; |
fbf5a39b AC |
178 | char *interrupt_states; |
179 | int num_interrupt_states; | |
180 | int unreserve_all_interrupts; | |
181 | int exception_tracebacks; | |
182 | int zero_cost_exceptions; | |
38cbfe40 RK |
183 | { |
184 | static int already_called = 0; | |
185 | ||
186 | /* If this procedure has been already called once, check that the | |
187 | arguments in this call are consistent with the ones in the previous | |
188 | calls. Otherwise, raise a Program_Error exception. | |
189 | ||
190 | We do not check for consistency of the wide character encoding | |
191 | method. This default affects only Wide_Text_IO where no explicit | |
192 | coding method is given, and there is no particular reason to let | |
193 | this default be affected by the source representation of a library | |
fbf5a39b AC |
194 | in any case. |
195 | ||
196 | We do not check either for the consistency of exception tracebacks, | |
197 | because exception tracebacks are not normally set in Stand-Alone | |
198 | libraries. If a library or the main program set the exception | |
199 | tracebacks, then they are never reset afterwards (see below). | |
38cbfe40 RK |
200 | |
201 | The value of main_priority is meaningful only when we are invoked | |
202 | from the main program elaboration routine of an Ada application. | |
203 | Checking the consistency of this parameter should therefore not be | |
204 | done. Since it is assured that the main program elaboration will | |
205 | always invoke this procedure before any library elaboration | |
206 | routine, only the value of main_priority during the first call | |
207 | should be taken into account and all the subsequent ones should be | |
208 | ignored. Note that the case where the main program is not written | |
209 | in Ada is also properly handled, since the default value will then | |
210 | be used for this parameter. | |
211 | ||
212 | For identical reasons, the consistency of time_slice_val should not | |
213 | be checked. */ | |
214 | ||
215 | if (already_called) | |
216 | { | |
07fc65c4 GB |
217 | if (__gl_locking_policy != locking_policy |
218 | || __gl_queuing_policy != queuing_policy | |
219 | || __gl_task_dispatching_policy != task_dispatching_policy | |
220 | || __gl_unreserve_all_interrupts != unreserve_all_interrupts | |
07fc65c4 GB |
221 | || __gl_zero_cost_exceptions != zero_cost_exceptions) |
222 | __gnat_raise_program_error (__FILE__, __LINE__); | |
223 | ||
fbf5a39b AC |
224 | /* If either a library or the main program set the exception traceback |
225 | flag, it is never reset later */ | |
226 | ||
227 | if (exception_tracebacks != 0) | |
228 | __gl_exception_tracebacks = exception_tracebacks; | |
229 | ||
38cbfe40 RK |
230 | return; |
231 | } | |
232 | already_called = 1; | |
233 | ||
234 | __gl_main_priority = main_priority; | |
235 | __gl_time_slice_val = time_slice_val; | |
236 | __gl_wc_encoding = wc_encoding; | |
237 | __gl_locking_policy = locking_policy; | |
238 | __gl_queuing_policy = queuing_policy; | |
07fc65c4 | 239 | __gl_restrictions = restrictions; |
fbf5a39b AC |
240 | __gl_interrupt_states = interrupt_states; |
241 | __gl_num_interrupt_states = num_interrupt_states; | |
38cbfe40 RK |
242 | __gl_task_dispatching_policy = task_dispatching_policy; |
243 | __gl_unreserve_all_interrupts = unreserve_all_interrupts; | |
244 | __gl_exception_tracebacks = exception_tracebacks; | |
07fc65c4 GB |
245 | |
246 | /* ??? __gl_zero_cost_exceptions is new in 3.15 and is referenced from | |
247 | a-except.adb, which is also part of the compiler sources. Since the | |
248 | compiler is built with an older release of GNAT, the call generated by | |
249 | the old binder to this function does not provide any value for the | |
250 | corresponding argument, so the global has to be initialized in some | |
251 | reasonable other way. This could be removed as soon as the next major | |
252 | release is out. */ | |
253 | ||
254 | #ifdef IN_RTS | |
255 | __gl_zero_cost_exceptions = zero_cost_exceptions; | |
256 | #else | |
257 | __gl_zero_cost_exceptions = 0; | |
258 | /* We never build the compiler to run in ZCX mode currently anyway. */ | |
259 | #endif | |
38cbfe40 RK |
260 | } |
261 | ||
262 | /*********************/ | |
263 | /* __gnat_initialize */ | |
264 | /*********************/ | |
265 | ||
266 | /* __gnat_initialize is called at the start of execution of an Ada program | |
267 | (the call is generated by the binder). The standard routine does nothing | |
268 | at all; the intention is that this be replaced by system specific | |
269 | code where initialization is required. */ | |
270 | ||
271 | /***********************************/ | |
fbf5a39b | 272 | /* __gnat_initialize (AIX Version) */ |
38cbfe40 RK |
273 | /***********************************/ |
274 | ||
275 | #if defined (_AIX) | |
276 | ||
fbf5a39b AC |
277 | #include <signal.h> |
278 | #include <sys/time.h> | |
279 | ||
280 | /* Some versions of AIX don't define SA_NODEFER. */ | |
38cbfe40 | 281 | |
fbf5a39b | 282 | #ifndef SA_NODEFER |
38cbfe40 | 283 | #define SA_NODEFER 0 |
fbf5a39b | 284 | #endif /* SA_NODEFER */ |
38cbfe40 | 285 | |
fbf5a39b AC |
286 | /* Versions of AIX before 4.3 don't have nanosleep but provide |
287 | nsleep instead. */ | |
38cbfe40 | 288 | |
fbf5a39b | 289 | #ifndef _AIXVERSION_430 |
38cbfe40 RK |
290 | |
291 | extern int nanosleep PARAMS ((struct timestruc_t *, struct timestruc_t *)); | |
38cbfe40 RK |
292 | |
293 | int | |
294 | nanosleep (Rqtp, Rmtp) | |
295 | struct timestruc_t *Rqtp, *Rmtp; | |
296 | { | |
297 | return nsleep (Rqtp, Rmtp); | |
298 | } | |
299 | ||
fbf5a39b AC |
300 | #endif /* _AIXVERSION_430 */ |
301 | ||
302 | static void __gnat_error_handler PARAMS ((int)); | |
38cbfe40 RK |
303 | |
304 | static void | |
305 | __gnat_error_handler (sig) | |
306 | int sig; | |
307 | { | |
308 | struct Exception_Data *exception; | |
45659035 | 309 | const char *msg; |
38cbfe40 RK |
310 | |
311 | switch (sig) | |
312 | { | |
313 | case SIGSEGV: | |
314 | /* FIXME: we need to detect the case of a *real* SIGSEGV */ | |
315 | exception = &storage_error; | |
316 | msg = "stack overflow or erroneous memory access"; | |
317 | break; | |
318 | ||
319 | case SIGBUS: | |
320 | exception = &constraint_error; | |
321 | msg = "SIGBUS"; | |
322 | break; | |
323 | ||
324 | case SIGFPE: | |
325 | exception = &constraint_error; | |
326 | msg = "SIGFPE"; | |
327 | break; | |
328 | ||
329 | default: | |
330 | exception = &program_error; | |
331 | msg = "unhandled signal"; | |
332 | } | |
333 | ||
334 | Raise_From_Signal_Handler (exception, msg); | |
335 | } | |
336 | ||
337 | void | |
338 | __gnat_install_handler () | |
339 | { | |
340 | struct sigaction act; | |
341 | ||
342 | /* Set up signal handler to map synchronous signals to appropriate | |
343 | exceptions. Make sure that the handler isn't interrupted by another | |
344 | signal that might cause a scheduling event! */ | |
345 | ||
346 | act.sa_handler = __gnat_error_handler; | |
347 | act.sa_flags = SA_NODEFER | SA_RESTART; | |
fbf5a39b AC |
348 | sigemptyset (&act.sa_mask); |
349 | ||
350 | /* Do not install handlers if interrupt state is "System" */ | |
351 | if (__gnat_get_interrupt_state (SIGABRT) != 's') | |
352 | sigaction (SIGABRT, &act, NULL); | |
353 | if (__gnat_get_interrupt_state (SIGFPE) != 's') | |
354 | sigaction (SIGFPE, &act, NULL); | |
355 | if (__gnat_get_interrupt_state (SIGILL) != 's') | |
356 | sigaction (SIGILL, &act, NULL); | |
357 | if (__gnat_get_interrupt_state (SIGSEGV) != 's') | |
358 | sigaction (SIGSEGV, &act, NULL); | |
359 | if (__gnat_get_interrupt_state (SIGBUS) != 's') | |
360 | sigaction (SIGBUS, &act, NULL); | |
38cbfe40 | 361 | |
38cbfe40 RK |
362 | __gnat_handler_installed = 1; |
363 | } | |
364 | ||
365 | void | |
366 | __gnat_initialize () | |
367 | { | |
368 | } | |
369 | ||
370 | /****************************************/ | |
fbf5a39b | 371 | /* __gnat_initialize (Dec Unix Version) */ |
38cbfe40 RK |
372 | /****************************************/ |
373 | ||
374 | #elif defined(__alpha__) && defined(__osf__) && ! defined(__alpha_vxworks) | |
375 | ||
376 | /* Note: it seems that __osf__ is defined for the Alpha VXWorks case. Not | |
377 | clear that this is reasonable, but in any case we have to be sure to | |
378 | exclude this case in the above test. */ | |
379 | ||
380 | #include <signal.h> | |
381 | #include <sys/siginfo.h> | |
382 | ||
383 | static void __gnat_error_handler PARAMS ((int, siginfo_t *, | |
384 | struct sigcontext *)); | |
385 | extern char *__gnat_get_code_loc PARAMS ((struct sigcontext *)); | |
386 | extern void __gnat_enter_handler PARAMS ((struct sigcontext *, char *)); | |
387 | extern size_t __gnat_machine_state_length PARAMS ((void)); | |
388 | ||
389 | extern long exc_lookup_gp PARAMS ((char *)); | |
390 | extern void exc_resume PARAMS ((struct sigcontext *)); | |
391 | ||
392 | static void | |
393 | __gnat_error_handler (sig, sip, context) | |
394 | int sig; | |
395 | siginfo_t *sip; | |
396 | struct sigcontext *context; | |
397 | { | |
398 | struct Exception_Data *exception; | |
399 | static int recurse = 0; | |
400 | struct sigcontext *mstate; | |
401 | const char *msg; | |
402 | ||
403 | /* If this was an explicit signal from a "kill", just resignal it. */ | |
404 | if (SI_FROMUSER (sip)) | |
405 | { | |
406 | signal (sig, SIG_DFL); | |
407 | kill (getpid(), sig); | |
408 | } | |
409 | ||
410 | /* Otherwise, treat it as something we handle. */ | |
411 | switch (sig) | |
412 | { | |
413 | case SIGSEGV: | |
414 | /* If the problem was permissions, this is a constraint error. | |
415 | Likewise if the failing address isn't maximally aligned or if | |
416 | we've recursed. | |
417 | ||
418 | ??? Using a static variable here isn't task-safe, but it's | |
419 | much too hard to do anything else and we're just determining | |
420 | which exception to raise. */ | |
421 | if (sip->si_code == SEGV_ACCERR | |
422 | || (((long) sip->si_addr) & 3) != 0 | |
423 | || recurse) | |
424 | { | |
425 | exception = &constraint_error; | |
426 | msg = "SIGSEGV"; | |
427 | } | |
428 | else | |
429 | { | |
638e383e | 430 | /* See if the page before the faulting page is accessible. Do that |
38cbfe40 RK |
431 | by trying to access it. We'd like to simply try to access |
432 | 4096 + the faulting address, but it's not guaranteed to be | |
433 | the actual address, just to be on the same page. */ | |
434 | recurse++; | |
435 | ((volatile char *) | |
436 | ((long) sip->si_addr & - getpagesize ()))[getpagesize ()]; | |
437 | msg = "stack overflow (or erroneous memory access)"; | |
438 | exception = &storage_error; | |
439 | } | |
440 | break; | |
441 | ||
442 | case SIGBUS: | |
443 | exception = &program_error; | |
444 | msg = "SIGBUS"; | |
445 | break; | |
446 | ||
447 | case SIGFPE: | |
448 | exception = &constraint_error; | |
449 | msg = "SIGFPE"; | |
450 | break; | |
451 | ||
452 | default: | |
453 | exception = &program_error; | |
454 | msg = "unhandled signal"; | |
455 | } | |
456 | ||
457 | recurse = 0; | |
458 | mstate = (struct sigcontext *) (*Get_Machine_State_Addr) (); | |
459 | if (mstate != 0) | |
460 | *mstate = *context; | |
461 | ||
462 | Raise_From_Signal_Handler (exception, (char *) msg); | |
463 | } | |
464 | ||
465 | void | |
466 | __gnat_install_handler () | |
467 | { | |
468 | struct sigaction act; | |
469 | ||
470 | /* Setup signal handler to map synchronous signals to appropriate | |
471 | exceptions. Make sure that the handler isn't interrupted by another | |
472 | signal that might cause a scheduling event! */ | |
473 | ||
474 | act.sa_handler = (void (*) PARAMS ((int))) __gnat_error_handler; | |
475 | act.sa_flags = SA_ONSTACK | SA_RESTART | SA_NODEFER | SA_SIGINFO; | |
fbf5a39b AC |
476 | sigemptyset (&act.sa_mask); |
477 | ||
478 | /* Do not install handlers if interrupt state is "System" */ | |
479 | if (__gnat_get_interrupt_state (SIGABRT) != 's') | |
480 | sigaction (SIGABRT, &act, NULL); | |
481 | if (__gnat_get_interrupt_state (SIGFPE) != 's') | |
482 | sigaction (SIGFPE, &act, NULL); | |
483 | if (__gnat_get_interrupt_state (SIGILL) != 's') | |
484 | sigaction (SIGILL, &act, NULL); | |
485 | if (__gnat_get_interrupt_state (SIGSEGV) != 's') | |
486 | sigaction (SIGSEGV, &act, NULL); | |
487 | if (__gnat_get_interrupt_state (SIGBUS) != 's') | |
488 | sigaction (SIGBUS, &act, NULL); | |
38cbfe40 RK |
489 | |
490 | __gnat_handler_installed = 1; | |
491 | } | |
492 | ||
493 | void | |
494 | __gnat_initialize () | |
495 | { | |
496 | } | |
497 | ||
498 | /* Routines called by 5amastop.adb. */ | |
499 | ||
500 | #define SC_GP 29 | |
501 | ||
502 | char * | |
503 | __gnat_get_code_loc (context) | |
504 | struct sigcontext *context; | |
505 | { | |
506 | return (char *) context->sc_pc; | |
507 | } | |
508 | ||
509 | void | |
510 | __gnat_enter_handler (context, pc) | |
511 | struct sigcontext *context; | |
512 | char *pc; | |
513 | { | |
514 | context->sc_pc = (long) pc; | |
515 | context->sc_regs[SC_GP] = exc_lookup_gp (pc); | |
516 | exc_resume (context); | |
517 | } | |
518 | ||
519 | size_t | |
520 | __gnat_machine_state_length () | |
521 | { | |
522 | return sizeof (struct sigcontext); | |
523 | } | |
524 | ||
fbf5a39b AC |
525 | /************************************/ |
526 | /* __gnat_initialize (HPUX Version) */ | |
527 | /************************************/ | |
38cbfe40 RK |
528 | |
529 | #elif defined (hpux) | |
530 | ||
531 | #include <signal.h> | |
532 | ||
533 | static void __gnat_error_handler PARAMS ((int)); | |
534 | ||
535 | static void | |
536 | __gnat_error_handler (sig) | |
537 | int sig; | |
538 | { | |
539 | struct Exception_Data *exception; | |
540 | char *msg; | |
541 | ||
542 | switch (sig) | |
543 | { | |
544 | case SIGSEGV: | |
545 | /* FIXME: we need to detect the case of a *real* SIGSEGV */ | |
546 | exception = &storage_error; | |
547 | msg = "stack overflow or erroneous memory access"; | |
548 | break; | |
549 | ||
550 | case SIGBUS: | |
551 | exception = &constraint_error; | |
552 | msg = "SIGBUS"; | |
553 | break; | |
554 | ||
555 | case SIGFPE: | |
556 | exception = &constraint_error; | |
557 | msg = "SIGFPE"; | |
558 | break; | |
559 | ||
560 | default: | |
561 | exception = &program_error; | |
562 | msg = "unhandled signal"; | |
563 | } | |
564 | ||
565 | Raise_From_Signal_Handler (exception, msg); | |
566 | } | |
567 | ||
568 | void | |
569 | __gnat_install_handler () | |
570 | { | |
571 | struct sigaction act; | |
572 | ||
573 | /* Set up signal handler to map synchronous signals to appropriate | |
574 | exceptions. Make sure that the handler isn't interrupted by another | |
575 | signal that might cause a scheduling event! Also setup an alternate | |
576 | stack region for the handler execution so that stack overflows can be | |
577 | handled properly, avoiding a SEGV generation from stack usage by the | |
578 | handler itself. */ | |
579 | ||
07fc65c4 GB |
580 | static char handler_stack[SIGSTKSZ*2]; |
581 | /* SIGSTKSZ appeared to be "short" for the needs in some contexts | |
582 | (e.g. experiments with GCC ZCX exceptions). */ | |
38cbfe40 RK |
583 | |
584 | stack_t stack; | |
585 | ||
586 | stack.ss_sp = handler_stack; | |
07fc65c4 | 587 | stack.ss_size = sizeof (handler_stack); |
38cbfe40 RK |
588 | stack.ss_flags = 0; |
589 | ||
fbf5a39b | 590 | sigaltstack (&stack, NULL); |
38cbfe40 RK |
591 | |
592 | act.sa_handler = __gnat_error_handler; | |
593 | act.sa_flags = SA_NODEFER | SA_RESTART | SA_ONSTACK; | |
fbf5a39b AC |
594 | sigemptyset (&act.sa_mask); |
595 | ||
596 | /* Do not install handlers if interrupt state is "System" */ | |
597 | if (__gnat_get_interrupt_state (SIGABRT) != 's') | |
598 | sigaction (SIGABRT, &act, NULL); | |
599 | if (__gnat_get_interrupt_state (SIGFPE) != 's') | |
600 | sigaction (SIGFPE, &act, NULL); | |
601 | if (__gnat_get_interrupt_state (SIGILL) != 's') | |
602 | sigaction (SIGILL, &act, NULL); | |
603 | if (__gnat_get_interrupt_state (SIGSEGV) != 's') | |
604 | sigaction (SIGSEGV, &act, NULL); | |
605 | if (__gnat_get_interrupt_state (SIGBUS) != 's') | |
606 | sigaction (SIGBUS, &act, NULL); | |
38cbfe40 | 607 | |
38cbfe40 RK |
608 | __gnat_handler_installed = 1; |
609 | } | |
610 | ||
611 | void | |
612 | __gnat_initialize () | |
613 | { | |
614 | } | |
615 | ||
fbf5a39b AC |
616 | /*****************************************/ |
617 | /* __gnat_initialize (GNU/Linux Version) */ | |
618 | /*****************************************/ | |
38cbfe40 RK |
619 | |
620 | #elif defined (linux) && defined (i386) && !defined (__RT__) | |
621 | ||
622 | #include <signal.h> | |
623 | #include <asm/sigcontext.h> | |
624 | ||
5d1a9698 GB |
625 | /* GNU/Linux, which uses glibc, does not define NULL in included |
626 | header files */ | |
38cbfe40 RK |
627 | |
628 | #if !defined (NULL) | |
629 | #define NULL ((void *) 0) | |
630 | #endif | |
631 | ||
632 | struct Machine_State | |
633 | { | |
634 | unsigned long eip; | |
635 | unsigned long ebx; | |
636 | unsigned long esp; | |
637 | unsigned long ebp; | |
638 | unsigned long esi; | |
639 | unsigned long edi; | |
640 | }; | |
641 | ||
642 | static void __gnat_error_handler PARAMS ((int)); | |
643 | ||
644 | static void | |
645 | __gnat_error_handler (sig) | |
646 | int sig; | |
647 | { | |
648 | struct Exception_Data *exception; | |
45659035 | 649 | const char *msg; |
38cbfe40 RK |
650 | static int recurse = 0; |
651 | ||
652 | struct sigcontext *info | |
653 | = (struct sigcontext *) (((char *) &sig) + sizeof (int)); | |
5d1a9698 GB |
654 | |
655 | /* The Linux kernel does not document how to get the machine state in a | |
656 | signal handler, but in fact the necessary data is in a sigcontext_struct | |
657 | value that is on the stack immediately above the signal number | |
658 | parameter, and the above messing accesses this value on the stack. */ | |
38cbfe40 RK |
659 | |
660 | struct Machine_State *mstate; | |
661 | ||
662 | switch (sig) | |
663 | { | |
664 | case SIGSEGV: | |
665 | /* If the problem was permissions, this is a constraint error. | |
666 | Likewise if the failing address isn't maximally aligned or if | |
667 | we've recursed. | |
668 | ||
669 | ??? Using a static variable here isn't task-safe, but it's | |
670 | much too hard to do anything else and we're just determining | |
671 | which exception to raise. */ | |
672 | if (recurse) | |
673 | { | |
674 | exception = &constraint_error; | |
675 | msg = "SIGSEGV"; | |
676 | } | |
677 | else | |
678 | { | |
679 | /* Here we would like a discrimination test to see whether the | |
680 | page before the faulting address is accessible. Unfortunately | |
681 | Linux seems to have no way of giving us the faulting address. | |
682 | ||
683 | In versions of a-init.c before 1.95, we had a test of the page | |
684 | before the stack pointer using: | |
685 | ||
686 | recurse++; | |
687 | ((volatile char *) | |
688 | ((long) info->esp_at_signal & - getpagesize ()))[getpagesize ()]; | |
689 | ||
690 | but that's wrong, since it tests the stack pointer location, and | |
691 | the current stack probe code does not move the stack pointer | |
692 | until all probes succeed. | |
693 | ||
694 | For now we simply do not attempt any discrimination at all. Note | |
695 | that this is quite acceptable, since a "real" SIGSEGV can only | |
696 | occur as the result of an erroneous program */ | |
697 | ||
698 | msg = "stack overflow (or erroneous memory access)"; | |
699 | exception = &storage_error; | |
700 | } | |
701 | break; | |
702 | ||
703 | case SIGBUS: | |
704 | exception = &constraint_error; | |
705 | msg = "SIGBUS"; | |
706 | break; | |
707 | ||
708 | case SIGFPE: | |
709 | exception = &constraint_error; | |
710 | msg = "SIGFPE"; | |
711 | break; | |
712 | ||
713 | default: | |
714 | exception = &program_error; | |
715 | msg = "unhandled signal"; | |
716 | } | |
717 | ||
718 | mstate = (*Get_Machine_State_Addr)(); | |
719 | if (mstate) | |
720 | { | |
721 | mstate->eip = info->eip; | |
722 | mstate->ebx = info->ebx; | |
723 | mstate->esp = info->esp_at_signal; | |
724 | mstate->ebp = info->ebp; | |
725 | mstate->esi = info->esi; | |
726 | mstate->edi = info->edi; | |
727 | } | |
728 | ||
729 | recurse = 0; | |
730 | Raise_From_Signal_Handler (exception, msg); | |
731 | } | |
732 | ||
733 | void | |
734 | __gnat_install_handler () | |
735 | { | |
736 | struct sigaction act; | |
737 | ||
738 | /* Set up signal handler to map synchronous signals to appropriate | |
739 | exceptions. Make sure that the handler isn't interrupted by another | |
740 | signal that might cause a scheduling event! */ | |
741 | ||
742 | act.sa_handler = __gnat_error_handler; | |
743 | act.sa_flags = SA_NODEFER | SA_RESTART; | |
fbf5a39b AC |
744 | sigemptyset (&act.sa_mask); |
745 | ||
746 | /* Do not install handlers if interrupt state is "System" */ | |
747 | if (__gnat_get_interrupt_state (SIGABRT) != 's') | |
748 | sigaction (SIGABRT, &act, NULL); | |
749 | if (__gnat_get_interrupt_state (SIGFPE) != 's') | |
750 | sigaction (SIGFPE, &act, NULL); | |
751 | if (__gnat_get_interrupt_state (SIGILL) != 's') | |
752 | sigaction (SIGILL, &act, NULL); | |
753 | if (__gnat_get_interrupt_state (SIGSEGV) != 's') | |
754 | sigaction (SIGSEGV, &act, NULL); | |
755 | if (__gnat_get_interrupt_state (SIGBUS) != 's') | |
756 | sigaction (SIGBUS, &act, NULL); | |
38cbfe40 | 757 | |
38cbfe40 RK |
758 | __gnat_handler_installed = 1; |
759 | } | |
760 | ||
761 | void | |
762 | __gnat_initialize () | |
763 | { | |
764 | } | |
765 | ||
766 | /******************************************/ | |
fbf5a39b | 767 | /* __gnat_initialize (NT-mingw32 Version) */ |
38cbfe40 RK |
768 | /******************************************/ |
769 | ||
770 | #elif defined (__MINGW32__) | |
771 | #include <windows.h> | |
772 | ||
fbf5a39b | 773 | static LONG WINAPI __gnat_error_handler PARAMS ((PEXCEPTION_POINTERS)); |
38cbfe40 RK |
774 | |
775 | /* __gnat_initialize (mingw32). */ | |
776 | ||
fbf5a39b | 777 | static LONG WINAPI |
38cbfe40 RK |
778 | __gnat_error_handler (info) |
779 | PEXCEPTION_POINTERS info; | |
780 | { | |
781 | static int recurse; | |
782 | struct Exception_Data *exception; | |
fbf5a39b | 783 | const char *msg; |
38cbfe40 RK |
784 | |
785 | switch (info->ExceptionRecord->ExceptionCode) | |
786 | { | |
787 | case EXCEPTION_ACCESS_VIOLATION: | |
788 | /* If the failing address isn't maximally-aligned or if we've | |
789 | recursed, this is a program error. */ | |
790 | if ((info->ExceptionRecord->ExceptionInformation[1] & 3) != 0 | |
791 | || recurse) | |
792 | { | |
793 | exception = &program_error; | |
794 | msg = "EXCEPTION_ACCESS_VIOLATION"; | |
795 | } | |
796 | else | |
797 | { | |
638e383e | 798 | /* See if the page before the faulting page is accessible. Do that |
38cbfe40 RK |
799 | by trying to access it. */ |
800 | recurse++; | |
801 | * ((volatile char *) (info->ExceptionRecord->ExceptionInformation[1] | |
802 | + 4096)); | |
803 | exception = &storage_error; | |
804 | msg = "stack overflow (or erroneous memory access)"; | |
805 | } | |
806 | break; | |
807 | ||
808 | case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: | |
809 | exception = &constraint_error; | |
810 | msg = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; | |
811 | break; | |
812 | ||
813 | case EXCEPTION_DATATYPE_MISALIGNMENT: | |
814 | exception = &constraint_error; | |
815 | msg = "EXCEPTION_DATATYPE_MISALIGNMENT"; | |
816 | break; | |
817 | ||
818 | case EXCEPTION_FLT_DENORMAL_OPERAND: | |
819 | exception = &constraint_error; | |
820 | msg = "EXCEPTION_FLT_DENORMAL_OPERAND"; | |
821 | break; | |
822 | ||
823 | case EXCEPTION_FLT_DIVIDE_BY_ZERO: | |
824 | exception = &constraint_error; | |
825 | msg = "EXCEPTION_FLT_DENORMAL_OPERAND"; | |
826 | break; | |
827 | ||
828 | case EXCEPTION_FLT_INVALID_OPERATION: | |
829 | exception = &constraint_error; | |
830 | msg = "EXCEPTION_FLT_INVALID_OPERATION"; | |
831 | break; | |
832 | ||
833 | case EXCEPTION_FLT_OVERFLOW: | |
834 | exception = &constraint_error; | |
835 | msg = "EXCEPTION_FLT_OVERFLOW"; | |
836 | break; | |
837 | ||
838 | case EXCEPTION_FLT_STACK_CHECK: | |
839 | exception = &program_error; | |
840 | msg = "EXCEPTION_FLT_STACK_CHECK"; | |
841 | break; | |
842 | ||
843 | case EXCEPTION_FLT_UNDERFLOW: | |
844 | exception = &constraint_error; | |
845 | msg = "EXCEPTION_FLT_UNDERFLOW"; | |
846 | break; | |
847 | ||
848 | case EXCEPTION_INT_DIVIDE_BY_ZERO: | |
849 | exception = &constraint_error; | |
850 | msg = "EXCEPTION_INT_DIVIDE_BY_ZERO"; | |
851 | break; | |
852 | ||
853 | case EXCEPTION_INT_OVERFLOW: | |
854 | exception = &constraint_error; | |
855 | msg = "EXCEPTION_INT_OVERFLOW"; | |
856 | break; | |
857 | ||
858 | case EXCEPTION_INVALID_DISPOSITION: | |
859 | exception = &program_error; | |
860 | msg = "EXCEPTION_INVALID_DISPOSITION"; | |
861 | break; | |
862 | ||
863 | case EXCEPTION_NONCONTINUABLE_EXCEPTION: | |
864 | exception = &program_error; | |
865 | msg = "EXCEPTION_NONCONTINUABLE_EXCEPTION"; | |
866 | break; | |
867 | ||
868 | case EXCEPTION_PRIV_INSTRUCTION: | |
869 | exception = &program_error; | |
870 | msg = "EXCEPTION_PRIV_INSTRUCTION"; | |
871 | break; | |
872 | ||
873 | case EXCEPTION_SINGLE_STEP: | |
874 | exception = &program_error; | |
875 | msg = "EXCEPTION_SINGLE_STEP"; | |
876 | break; | |
877 | ||
878 | case EXCEPTION_STACK_OVERFLOW: | |
879 | exception = &storage_error; | |
880 | msg = "EXCEPTION_STACK_OVERFLOW"; | |
881 | break; | |
882 | ||
883 | default: | |
884 | exception = &program_error; | |
885 | msg = "unhandled signal"; | |
886 | } | |
887 | ||
888 | recurse = 0; | |
889 | Raise_From_Signal_Handler (exception, msg); | |
fbf5a39b | 890 | return 0; /* This is never reached, avoid compiler warning */ |
38cbfe40 RK |
891 | } |
892 | ||
893 | void | |
894 | __gnat_install_handler () | |
895 | { | |
896 | SetUnhandledExceptionFilter (__gnat_error_handler); | |
897 | __gnat_handler_installed = 1; | |
898 | } | |
899 | ||
900 | void | |
901 | __gnat_initialize () | |
902 | { | |
903 | ||
904 | /* Initialize floating-point coprocessor. This call is needed because | |
905 | the MS libraries default to 64-bit precision instead of 80-bit | |
906 | precision, and we require the full precision for proper operation, | |
907 | given that we have set Max_Digits etc with this in mind */ | |
908 | ||
909 | __gnat_init_float (); | |
910 | ||
911 | /* initialize a lock for a process handle list - see a-adaint.c for the | |
912 | implementation of __gnat_portable_no_block_spawn, __gnat_portable_wait */ | |
913 | __gnat_plist_init(); | |
914 | } | |
915 | ||
fbf5a39b AC |
916 | /***************************************/ |
917 | /* __gnat_initialize (Interix Version) */ | |
918 | /***************************************/ | |
38cbfe40 RK |
919 | |
920 | #elif defined (__INTERIX) | |
921 | ||
922 | #include <signal.h> | |
923 | ||
924 | static void __gnat_error_handler PARAMS ((int)); | |
925 | ||
926 | static void | |
927 | __gnat_error_handler (sig) | |
928 | int sig; | |
929 | { | |
930 | struct Exception_Data *exception; | |
931 | char *msg; | |
932 | ||
933 | switch (sig) | |
934 | { | |
935 | case SIGSEGV: | |
936 | exception = &storage_error; | |
937 | msg = "stack overflow or erroneous memory access"; | |
938 | break; | |
939 | ||
940 | case SIGBUS: | |
941 | exception = &constraint_error; | |
942 | msg = "SIGBUS"; | |
943 | break; | |
944 | ||
945 | case SIGFPE: | |
946 | exception = &constraint_error; | |
947 | msg = "SIGFPE"; | |
948 | break; | |
949 | ||
950 | default: | |
951 | exception = &program_error; | |
952 | msg = "unhandled signal"; | |
953 | } | |
954 | ||
955 | Raise_From_Signal_Handler (exception, msg); | |
956 | } | |
957 | ||
958 | void | |
959 | __gnat_install_handler () | |
960 | { | |
961 | struct sigaction act; | |
962 | ||
963 | /* Set up signal handler to map synchronous signals to appropriate | |
964 | exceptions. Make sure that the handler isn't interrupted by another | |
965 | signal that might cause a scheduling event! */ | |
966 | ||
967 | act.sa_handler = __gnat_error_handler; | |
968 | act.sa_flags = 0; | |
fbf5a39b | 969 | sigemptyset (&act.sa_mask); |
38cbfe40 RK |
970 | |
971 | /* Handlers for signals besides SIGSEGV cause c974013 to hang */ | |
fbf5a39b AC |
972 | /* sigaction (SIGILL, &act, NULL); */ |
973 | /* sigaction (SIGABRT, &act, NULL); */ | |
974 | /* sigaction (SIGFPE, &act, NULL); */ | |
975 | /* sigaction (SIGBUS, &act, NULL); */ | |
07fc65c4 | 976 | |
fbf5a39b AC |
977 | /* Do not install handlers if interrupt state is "System" */ |
978 | if (__gnat_get_interrupt_state (SIGSEGV) != 's') | |
979 | sigaction (SIGSEGV, &act, NULL); | |
07fc65c4 | 980 | |
38cbfe40 RK |
981 | __gnat_handler_installed = 1; |
982 | } | |
983 | ||
984 | void | |
985 | __gnat_initialize () | |
986 | { | |
987 | __gnat_init_float (); | |
988 | } | |
989 | ||
990 | /**************************************/ | |
fbf5a39b | 991 | /* __gnat_initialize (LynxOS Version) */ |
38cbfe40 RK |
992 | /**************************************/ |
993 | ||
994 | #elif defined (__Lynx__) | |
995 | ||
996 | void | |
997 | __gnat_initialize () | |
998 | { | |
999 | __gnat_init_float (); | |
1000 | } | |
1001 | ||
1002 | /*********************************/ | |
1003 | /* __gnat_install_handler (Lynx) */ | |
1004 | /*********************************/ | |
1005 | ||
1006 | void | |
1007 | __gnat_install_handler () | |
1008 | { | |
1009 | __gnat_handler_installed = 1; | |
1010 | } | |
1011 | ||
1012 | /****************************/ | |
1013 | /* __gnat_initialize (OS/2) */ | |
1014 | /****************************/ | |
1015 | ||
1016 | #elif defined (__EMX__) /* OS/2 dependent initialization */ | |
1017 | ||
1018 | void | |
1019 | __gnat_initialize () | |
1020 | { | |
1021 | } | |
1022 | ||
1023 | /*********************************/ | |
1024 | /* __gnat_install_handler (OS/2) */ | |
1025 | /*********************************/ | |
1026 | ||
1027 | void | |
1028 | __gnat_install_handler () | |
1029 | { | |
1030 | __gnat_handler_installed = 1; | |
1031 | } | |
1032 | ||
1033 | /***********************************/ | |
fbf5a39b | 1034 | /* __gnat_initialize (SGI Version) */ |
38cbfe40 RK |
1035 | /***********************************/ |
1036 | ||
1037 | #elif defined (sgi) | |
1038 | ||
1039 | #include <signal.h> | |
1040 | #include <siginfo.h> | |
1041 | ||
1042 | #ifndef NULL | |
1043 | #define NULL 0 | |
1044 | #endif | |
1045 | ||
1046 | #define SIGADAABORT 48 | |
1047 | #define SIGNAL_STACK_SIZE 4096 | |
1048 | #define SIGNAL_STACK_ALIGNMENT 64 | |
1049 | ||
1050 | struct Machine_State | |
1051 | { | |
1052 | sigcontext_t context; | |
1053 | }; | |
1054 | ||
1055 | static void __gnat_error_handler PARAMS ((int, int, sigcontext_t *)); | |
1056 | ||
1057 | static void | |
1058 | __gnat_error_handler (sig, code, sc) | |
1059 | int sig; | |
1060 | int code; | |
1061 | sigcontext_t *sc; | |
1062 | { | |
1063 | struct Machine_State *mstate; | |
1064 | struct Exception_Data *exception; | |
1065 | char *msg; | |
1066 | ||
1067 | int i; | |
1068 | ||
1069 | switch (sig) | |
1070 | { | |
1071 | case SIGSEGV: | |
1072 | if (code == EFAULT) | |
1073 | { | |
1074 | exception = &program_error; | |
1075 | msg = "SIGSEGV: (Invalid virtual address)"; | |
1076 | } | |
1077 | else if (code == ENXIO) | |
1078 | { | |
1079 | exception = &program_error; | |
1080 | msg = "SIGSEGV: (Read beyond mapped object)"; | |
1081 | } | |
1082 | else if (code == ENOSPC) | |
1083 | { | |
1084 | exception = &program_error; /* ??? storage_error ??? */ | |
1085 | msg = "SIGSEGV: (Autogrow for file failed)"; | |
1086 | } | |
1087 | else if (code == EACCES) | |
1088 | { | |
1089 | /* ??? Re-add smarts to further verify that we launched | |
1090 | the stack into a guard page, not an attempt to | |
1091 | write to .text or something */ | |
1092 | exception = &storage_error; | |
1093 | msg = "SIGSEGV: (stack overflow or erroneous memory access)"; | |
1094 | } | |
1095 | else | |
1096 | { | |
1097 | /* Just in case the OS guys did it to us again. Sometimes | |
1098 | they fail to document all of the valid codes that are | |
1099 | passed to signal handlers, just in case someone depends | |
1100 | on knowing all the codes */ | |
1101 | exception = &program_error; | |
1102 | msg = "SIGSEGV: (Undocumented reason)"; | |
1103 | } | |
1104 | break; | |
1105 | ||
1106 | case SIGBUS: | |
1107 | /* Map all bus errors to Program_Error. */ | |
1108 | exception = &program_error; | |
1109 | msg = "SIGBUS"; | |
1110 | break; | |
1111 | ||
1112 | case SIGFPE: | |
1113 | /* Map all fpe errors to Constraint_Error. */ | |
1114 | exception = &constraint_error; | |
1115 | msg = "SIGFPE"; | |
1116 | break; | |
1117 | ||
1118 | case SIGADAABORT: | |
1119 | if ((*Check_Abort_Status) ()) | |
1120 | { | |
1121 | exception = &_abort_signal; | |
1122 | msg = ""; | |
1123 | } | |
1124 | else | |
1125 | return; | |
1126 | ||
1127 | break; | |
1128 | ||
1129 | default: | |
1130 | /* Everything else is a Program_Error. */ | |
1131 | exception = &program_error; | |
1132 | msg = "unhandled signal"; | |
1133 | } | |
1134 | ||
1135 | mstate = (*Get_Machine_State_Addr)(); | |
1136 | if (mstate != 0) | |
1137 | memcpy ((void *) mstate, (const void *) sc, sizeof (sigcontext_t)); | |
1138 | ||
1139 | Raise_From_Signal_Handler (exception, msg); | |
38cbfe40 RK |
1140 | } |
1141 | ||
1142 | void | |
1143 | __gnat_install_handler () | |
1144 | { | |
1145 | stack_t ss; | |
1146 | struct sigaction act; | |
1147 | ||
1148 | /* Setup signal handler to map synchronous signals to appropriate | |
1149 | exceptions. Make sure that the handler isn't interrupted by another | |
1150 | signal that might cause a scheduling event! */ | |
1151 | ||
1152 | act.sa_handler = __gnat_error_handler; | |
1153 | act.sa_flags = SA_NODEFER + SA_RESTART; | |
fbf5a39b AC |
1154 | sigfillset (&act.sa_mask); |
1155 | sigemptyset (&act.sa_mask); | |
1156 | ||
1157 | /* Do not install handlers if interrupt state is "System" */ | |
1158 | if (__gnat_get_interrupt_state (SIGABRT) != 's') | |
1159 | sigaction (SIGABRT, &act, NULL); | |
1160 | if (__gnat_get_interrupt_state (SIGFPE) != 's') | |
1161 | sigaction (SIGFPE, &act, NULL); | |
1162 | if (__gnat_get_interrupt_state (SIGILL) != 's') | |
1163 | sigaction (SIGILL, &act, NULL); | |
1164 | if (__gnat_get_interrupt_state (SIGSEGV) != 's') | |
1165 | sigaction (SIGSEGV, &act, NULL); | |
1166 | if (__gnat_get_interrupt_state (SIGBUS) != 's') | |
1167 | sigaction (SIGBUS, &act, NULL); | |
1168 | if (__gnat_get_interrupt_state (SIGADAABORT) != 's') | |
1169 | sigaction (SIGADAABORT, &act, NULL); | |
1170 | ||
38cbfe40 RK |
1171 | __gnat_handler_installed = 1; |
1172 | } | |
1173 | ||
1174 | void | |
1175 | __gnat_initialize () | |
1176 | { | |
1177 | } | |
1178 | ||
1179 | /*************************************************/ | |
fbf5a39b | 1180 | /* __gnat_initialize (Solaris and SunOS Version) */ |
38cbfe40 RK |
1181 | /*************************************************/ |
1182 | ||
1183 | #elif defined (sun) && defined (__SVR4) && !defined (__vxworks) | |
1184 | ||
1185 | #include <signal.h> | |
1186 | #include <siginfo.h> | |
1187 | ||
1188 | static void __gnat_error_handler PARAMS ((int, siginfo_t *)); | |
1189 | ||
1190 | static void | |
1191 | __gnat_error_handler (sig, sip) | |
1192 | int sig; | |
1193 | siginfo_t *sip; | |
1194 | { | |
1195 | struct Exception_Data *exception; | |
1196 | static int recurse = 0; | |
fbf5a39b | 1197 | char *msg; |
38cbfe40 RK |
1198 | |
1199 | /* If this was an explicit signal from a "kill", just resignal it. */ | |
1200 | if (SI_FROMUSER (sip)) | |
1201 | { | |
1202 | signal (sig, SIG_DFL); | |
1203 | kill (getpid(), sig); | |
1204 | } | |
1205 | ||
1206 | /* Otherwise, treat it as something we handle. */ | |
1207 | switch (sig) | |
1208 | { | |
1209 | case SIGSEGV: | |
1210 | /* If the problem was permissions, this is a constraint error. | |
1211 | Likewise if the failing address isn't maximally aligned or if | |
1212 | we've recursed. | |
1213 | ||
1214 | ??? Using a static variable here isn't task-safe, but it's | |
1215 | much too hard to do anything else and we're just determining | |
1216 | which exception to raise. */ | |
1217 | if (sip->si_code == SEGV_ACCERR | |
1218 | || (((long) sip->si_addr) & 3) != 0 | |
1219 | || recurse) | |
1220 | { | |
1221 | exception = &constraint_error; | |
1222 | msg = "SIGSEGV"; | |
1223 | } | |
1224 | else | |
1225 | { | |
638e383e | 1226 | /* See if the page before the faulting page is accessible. Do that |
38cbfe40 RK |
1227 | by trying to access it. We'd like to simply try to access |
1228 | 4096 + the faulting address, but it's not guaranteed to be | |
1229 | the actual address, just to be on the same page. */ | |
1230 | recurse++; | |
1231 | ((volatile char *) | |
1232 | ((long) sip->si_addr & - getpagesize ()))[getpagesize ()]; | |
1233 | exception = &storage_error; | |
1234 | msg = "stack overflow (or erroneous memory access)"; | |
1235 | } | |
1236 | break; | |
1237 | ||
1238 | case SIGBUS: | |
1239 | exception = &program_error; | |
1240 | msg = "SIGBUS"; | |
1241 | break; | |
1242 | ||
1243 | case SIGFPE: | |
1244 | exception = &constraint_error; | |
1245 | msg = "SIGFPE"; | |
1246 | break; | |
1247 | ||
1248 | default: | |
1249 | exception = &program_error; | |
1250 | msg = "unhandled signal"; | |
1251 | } | |
1252 | ||
1253 | recurse = 0; | |
1254 | ||
1255 | Raise_From_Signal_Handler (exception, msg); | |
1256 | } | |
1257 | ||
1258 | void | |
1259 | __gnat_install_handler () | |
1260 | { | |
1261 | struct sigaction act; | |
1262 | ||
1263 | /* Set up signal handler to map synchronous signals to appropriate | |
1264 | exceptions. Make sure that the handler isn't interrupted by another | |
1265 | signal that might cause a scheduling event! */ | |
1266 | ||
1267 | act.sa_handler = __gnat_error_handler; | |
1268 | act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO; | |
fbf5a39b AC |
1269 | sigemptyset (&act.sa_mask); |
1270 | ||
1271 | /* Do not install handlers if interrupt state is "System" */ | |
1272 | if (__gnat_get_interrupt_state (SIGABRT) != 's') | |
1273 | sigaction (SIGABRT, &act, NULL); | |
1274 | if (__gnat_get_interrupt_state (SIGFPE) != 's') | |
1275 | sigaction (SIGFPE, &act, NULL); | |
1276 | if (__gnat_get_interrupt_state (SIGSEGV) != 's') | |
1277 | sigaction (SIGSEGV, &act, NULL); | |
1278 | if (__gnat_get_interrupt_state (SIGBUS) != 's') | |
1279 | sigaction (SIGBUS, &act, NULL); | |
38cbfe40 | 1280 | |
38cbfe40 RK |
1281 | __gnat_handler_installed = 1; |
1282 | } | |
1283 | ||
1284 | void | |
1285 | __gnat_initialize () | |
1286 | { | |
1287 | } | |
1288 | ||
1289 | /***********************************/ | |
fbf5a39b | 1290 | /* __gnat_initialize (VMS Version) */ |
38cbfe40 RK |
1291 | /***********************************/ |
1292 | ||
1293 | #elif defined (VMS) | |
1294 | ||
1295 | /* The prehandler actually gets control first on a condition. It swaps the | |
1296 | stack pointer and calls the handler (__gnat_error_handler). */ | |
1297 | extern long __gnat_error_prehandler (); | |
1298 | ||
1299 | extern char *__gnat_error_prehandler_stack; /* Alternate signal stack */ | |
1300 | ||
1301 | /* Conditions that don't have an Ada exception counterpart must raise | |
1302 | Non_Ada_Error. Since this is defined in s-auxdec, it should only be | |
1303 | referenced by user programs, not the compiler or tools. Hence the | |
1304 | #ifdef IN_RTS. */ | |
1305 | ||
1306 | #ifdef IN_RTS | |
1307 | #define Non_Ada_Error system__aux_dec__non_ada_error | |
1308 | extern struct Exception_Data Non_Ada_Error; | |
1309 | ||
1310 | #define Coded_Exception system__vms_exception_table__coded_exception | |
1311 | extern struct Exception_Data *Coded_Exception (int); | |
1312 | #endif | |
1313 | ||
1314 | /* Define macro symbols for the VMS conditions that become Ada exceptions. | |
1315 | Most of these are also defined in the header file ssdef.h which has not | |
1316 | yet been converted to be recoginized by Gnu C. Some, which couldn't be | |
1317 | located, are assigned names based on the DEC test suite tests which | |
1318 | raise them. */ | |
1319 | ||
1320 | #define SS$_ACCVIO 12 | |
1321 | #define SS$_DEBUG 1132 | |
1322 | #define SS$_INTDIV 1156 | |
1323 | #define SS$_HPARITH 1284 | |
1324 | #define SS$_STKOVF 1364 | |
1325 | #define SS$_RESIGNAL 2328 | |
1326 | #define MTH$_FLOOVEMAT 1475268 /* Some ACVC_21 CXA tests */ | |
1327 | #define SS$_CE24VRU 3253636 /* Write to unopened file */ | |
1328 | #define SS$_C980VTE 3246436 /* AST requests time slice */ | |
1329 | #define CMA$_EXIT_THREAD 4227492 | |
1330 | #define CMA$_EXCCOPLOS 4228108 | |
1331 | #define CMA$_ALERTED 4227460 | |
1332 | ||
1333 | struct descriptor_s {unsigned short len, mbz; char *adr; }; | |
1334 | ||
07fc65c4 | 1335 | long __gnat_error_handler PARAMS ((int *, void *)); |
38cbfe40 | 1336 | |
07fc65c4 | 1337 | long |
38cbfe40 RK |
1338 | __gnat_error_handler (sigargs, mechargs) |
1339 | int *sigargs; | |
1340 | void *mechargs; | |
1341 | { | |
1342 | struct Exception_Data *exception = 0; | |
1343 | char *msg = ""; | |
07fc65c4 | 1344 | char message[256]; |
38cbfe40 RK |
1345 | long prvhnd; |
1346 | struct descriptor_s msgdesc; | |
1347 | int msg_flag = 0x000f; /* 1 bit for each of the four message parts */ | |
1348 | unsigned short outlen; | |
07fc65c4 | 1349 | char curr_icb[544]; |
38cbfe40 RK |
1350 | long curr_invo_handle; |
1351 | long *mstate; | |
1352 | ||
fbf5a39b | 1353 | /* Resignaled condtions aren't effected by by pragma Import_Exception */ |
38cbfe40 RK |
1354 | |
1355 | switch (sigargs[1]) | |
1356 | { | |
1357 | ||
1358 | case CMA$_EXIT_THREAD: | |
1359 | return SS$_RESIGNAL; | |
1360 | ||
1361 | case SS$_DEBUG: /* Gdb attach, resignal to merge activate gdbstub. */ | |
1362 | return SS$_RESIGNAL; | |
1363 | ||
1364 | case 1409786: /* Nickerson bug #33 ??? */ | |
1365 | return SS$_RESIGNAL; | |
1366 | ||
1367 | case 1381050: /* Nickerson bug #33 ??? */ | |
1368 | return SS$_RESIGNAL; | |
1369 | ||
1370 | case 11829410: /* Resignalled as Use_Error for CE10VRC */ | |
1371 | return SS$_RESIGNAL; | |
1372 | ||
1373 | } | |
1374 | ||
1375 | #ifdef IN_RTS | |
1376 | /* See if it's an imported exception. Mask off severity bits. */ | |
07fc65c4 | 1377 | exception = Coded_Exception (sigargs[1] & 0xfffffff8); |
38cbfe40 RK |
1378 | if (exception) |
1379 | { | |
1380 | msgdesc.len = 256; | |
1381 | msgdesc.mbz = 0; | |
1382 | msgdesc.adr = message; | |
1383 | SYS$GETMSG (sigargs[1], &outlen, &msgdesc, msg_flag, 0); | |
07fc65c4 | 1384 | message[outlen] = 0; |
38cbfe40 RK |
1385 | msg = message; |
1386 | ||
1387 | exception->Name_Length = 19; | |
1388 | /* The full name really should be get sys$getmsg returns. ??? */ | |
1389 | exception->Full_Name = "IMPORTED_EXCEPTION"; | |
07fc65c4 | 1390 | exception->Import_Code = sigargs[1] & 0xfffffff8; |
38cbfe40 RK |
1391 | } |
1392 | #endif | |
1393 | ||
1394 | if (exception == 0) | |
1395 | switch (sigargs[1]) | |
1396 | { | |
1397 | case SS$_ACCVIO: | |
1398 | if (sigargs[3] == 0) | |
1399 | { | |
1400 | exception = &constraint_error; | |
1401 | msg = "access zero"; | |
1402 | } | |
1403 | else | |
1404 | { | |
1405 | exception = &storage_error; | |
1406 | msg = "stack overflow (or erroneous memory access)"; | |
1407 | } | |
1408 | break; | |
1409 | ||
1410 | case SS$_STKOVF: | |
1411 | exception = &storage_error; | |
1412 | msg = "stack overflow"; | |
1413 | break; | |
1414 | ||
1415 | case SS$_INTDIV: | |
1416 | exception = &constraint_error; | |
1417 | msg = "division by zero"; | |
1418 | break; | |
1419 | ||
1420 | case SS$_HPARITH: | |
1421 | #ifndef IN_RTS | |
1422 | return SS$_RESIGNAL; /* toplev.c handles for compiler */ | |
1423 | #else | |
1424 | { | |
1425 | exception = &constraint_error; | |
1426 | msg = "arithmetic error"; | |
1427 | } | |
1428 | #endif | |
1429 | break; | |
1430 | ||
1431 | case MTH$_FLOOVEMAT: | |
1432 | exception = &constraint_error; | |
1433 | msg = "floating overflow in math library"; | |
1434 | break; | |
1435 | ||
1436 | case SS$_CE24VRU: | |
1437 | exception = &constraint_error; | |
1438 | msg = ""; | |
1439 | break; | |
1440 | ||
1441 | case SS$_C980VTE: | |
1442 | exception = &program_error; | |
1443 | msg = ""; | |
1444 | break; | |
1445 | ||
1446 | default: | |
1447 | #ifndef IN_RTS | |
1448 | exception = &program_error; | |
1449 | #else | |
1450 | /* User programs expect Non_Ada_Error to be raised, reference | |
1451 | DEC Ada test CXCONDHAN. */ | |
1452 | exception = &Non_Ada_Error; | |
1453 | #endif | |
1454 | msgdesc.len = 256; | |
1455 | msgdesc.mbz = 0; | |
1456 | msgdesc.adr = message; | |
1457 | SYS$GETMSG (sigargs[1], &outlen, &msgdesc, msg_flag, 0); | |
07fc65c4 | 1458 | message[outlen] = 0; |
38cbfe40 RK |
1459 | msg = message; |
1460 | break; | |
1461 | } | |
1462 | ||
1463 | mstate = (long *) (*Get_Machine_State_Addr) (); | |
1464 | if (mstate != 0) | |
1465 | { | |
1466 | LIB$GET_CURR_INVO_CONTEXT (&curr_icb); | |
1467 | LIB$GET_PREV_INVO_CONTEXT (&curr_icb); | |
1468 | LIB$GET_PREV_INVO_CONTEXT (&curr_icb); | |
1469 | curr_invo_handle = LIB$GET_INVO_HANDLE (&curr_icb); | |
1470 | *mstate = curr_invo_handle; | |
1471 | } | |
1472 | Raise_From_Signal_Handler (exception, msg); | |
1473 | } | |
1474 | ||
1475 | void | |
1476 | __gnat_install_handler () | |
1477 | { | |
1478 | long prvhnd; | |
1479 | char *c; | |
1480 | ||
07fc65c4 | 1481 | c = (char *) xmalloc (2049); |
38cbfe40 | 1482 | |
49bb4548 | 1483 | __gnat_error_prehandler_stack = &c[2048]; |
38cbfe40 RK |
1484 | |
1485 | /* __gnat_error_prehandler is an assembly function. */ | |
1486 | SYS$SETEXV (1, __gnat_error_prehandler, 3, &prvhnd); | |
1487 | __gnat_handler_installed = 1; | |
1488 | } | |
1489 | ||
1490 | void | |
1491 | __gnat_initialize() | |
1492 | { | |
1493 | } | |
1494 | ||
1495 | /***************************************/ | |
fbf5a39b | 1496 | /* __gnat_initialize (VXWorks Version) */ |
38cbfe40 RK |
1497 | /***************************************/ |
1498 | ||
1499 | #elif defined(__vxworks) | |
1500 | ||
1501 | #include <signal.h> | |
1502 | #include <taskLib.h> | |
1503 | #include <intLib.h> | |
1504 | #include <iv.h> | |
1505 | ||
fbf5a39b AC |
1506 | extern int __gnat_inum_to_ivec (int); |
1507 | static void __gnat_error_handler (int, int, struct sigcontext *); | |
38cbfe40 RK |
1508 | |
1509 | #ifndef __alpha_vxworks | |
1510 | ||
1511 | /* getpid is used by s-parint.adb, but is not defined by VxWorks, except | |
1512 | on Alpha VxWorks */ | |
1513 | ||
1514 | extern long getpid PARAMS ((void)); | |
1515 | ||
1516 | long | |
1517 | getpid () | |
1518 | { | |
1519 | return taskIdSelf (); | |
1520 | } | |
1521 | #endif | |
1522 | ||
1523 | /* This is needed by the GNAT run time to handle Vxworks interrupts */ | |
1524 | int | |
1525 | __gnat_inum_to_ivec (num) | |
1526 | int num; | |
1527 | { | |
1528 | return INUM_TO_IVEC (num); | |
1529 | } | |
1530 | ||
1531 | static void | |
1532 | __gnat_error_handler (sig, code, sc) | |
1533 | int sig; | |
1534 | int code; | |
1535 | struct sigcontext *sc; | |
1536 | { | |
1537 | struct Exception_Data *exception; | |
1538 | sigset_t mask; | |
1539 | int result; | |
1540 | char *msg; | |
1541 | ||
1542 | /* VxWorks will always mask out the signal during the signal handler and | |
1543 | will reenable it on a longjmp. GNAT does not generate a longjmp to | |
1544 | return from a signal handler so the signal will still be masked unless | |
1545 | we unmask it. */ | |
fbf5a39b | 1546 | sigprocmask (SIG_SETMASK, NULL, &mask); |
38cbfe40 | 1547 | sigdelset (&mask, sig); |
fbf5a39b | 1548 | sigprocmask (SIG_SETMASK, &mask, NULL); |
38cbfe40 RK |
1549 | |
1550 | /* VxWorks will suspend the task when it gets a hardware exception. We | |
1551 | take the liberty of resuming the task for the application. */ | |
1552 | if (taskIsSuspended (taskIdSelf ()) != 0) | |
fbf5a39b | 1553 | taskResume (taskIdSelf ()); |
38cbfe40 RK |
1554 | |
1555 | switch (sig) | |
1556 | { | |
1557 | case SIGFPE: | |
1558 | exception = &constraint_error; | |
1559 | msg = "SIGFPE"; | |
1560 | break; | |
1561 | case SIGILL: | |
1562 | exception = &constraint_error; | |
1563 | msg = "SIGILL"; | |
1564 | break; | |
1565 | case SIGSEGV: | |
1566 | exception = &program_error; | |
1567 | msg = "SIGSEGV"; | |
1568 | break; | |
1569 | case SIGBUS: | |
1570 | exception = &program_error; | |
1571 | msg = "SIGBUS"; | |
1572 | break; | |
1573 | default: | |
1574 | exception = &program_error; | |
1575 | msg = "unhandled signal"; | |
1576 | } | |
1577 | ||
1578 | Raise_From_Signal_Handler (exception, msg); | |
1579 | } | |
1580 | ||
1581 | void | |
1582 | __gnat_install_handler () | |
1583 | { | |
1584 | struct sigaction act; | |
1585 | ||
1586 | /* Setup signal handler to map synchronous signals to appropriate | |
1587 | exceptions. Make sure that the handler isn't interrupted by another | |
1588 | signal that might cause a scheduling event! */ | |
1589 | ||
1590 | act.sa_handler = __gnat_error_handler; | |
1591 | act.sa_flags = SA_SIGINFO | SA_ONSTACK; | |
fbf5a39b | 1592 | sigemptyset (&act.sa_mask); |
38cbfe40 | 1593 | |
fbf5a39b AC |
1594 | /* For VxWorks, install all signal handlers, since pragma Interrupt_State |
1595 | applies to vectored hardware interrupts, not signals */ | |
1596 | sigaction (SIGFPE, &act, NULL); | |
1597 | sigaction (SIGILL, &act, NULL); | |
1598 | sigaction (SIGSEGV, &act, NULL); | |
1599 | sigaction (SIGBUS, &act, NULL); | |
38cbfe40 | 1600 | |
38cbfe40 RK |
1601 | __gnat_handler_installed = 1; |
1602 | } | |
1603 | ||
1604 | #define HAVE_GNAT_INIT_FLOAT | |
1605 | ||
1606 | void | |
1607 | __gnat_init_float () | |
1608 | { | |
38cbfe40 | 1609 | /* Disable overflow/underflow exceptions on the PPC processor, this is needed |
fbf5a39b AC |
1610 | to get correct Ada semantic. */ |
1611 | #if defined (_ARCH_PPC) && !defined (_SOFT_FLOAT) | |
38cbfe40 RK |
1612 | asm ("mtfsb0 25"); |
1613 | asm ("mtfsb0 26"); | |
1614 | #endif | |
fbf5a39b AC |
1615 | |
1616 | /* Similarily for sparc64. Achieved by masking bits in the Trap Enable Mask | |
1617 | field of the Floating-point Status Register (see the Sparc Architecture | |
1618 | Manual Version 9, p 48). */ | |
1619 | #if defined (sparc64) | |
1620 | ||
1621 | #define FSR_TEM_NVM (1 << 27) /* Invalid operand */ | |
1622 | #define FSR_TEM_OFM (1 << 26) /* Overflow */ | |
1623 | #define FSR_TEM_UFM (1 << 25) /* Underflow */ | |
1624 | #define FSR_TEM_DZM (1 << 24) /* Division by Zero */ | |
1625 | #define FSR_TEM_NXM (1 << 23) /* Inexact result */ | |
1626 | { | |
1627 | unsigned int fsr; | |
1628 | ||
1629 | __asm__("st %%fsr, %0" : "=m" (fsr)); | |
1630 | fsr &= ~(FSR_TEM_OFM | FSR_TEM_UFM); | |
1631 | __asm__("ld %0, %%fsr" : : "m" (fsr)); | |
1632 | } | |
1633 | #endif | |
38cbfe40 RK |
1634 | } |
1635 | ||
1636 | void | |
1637 | __gnat_initialize () | |
1638 | { | |
fbf5a39b AC |
1639 | __gnat_init_float (); |
1640 | ||
1641 | /* Assume an environment task stack size of 20kB. | |
1642 | ||
1643 | Using a constant is necessary because we do not want each Ada application | |
1644 | to depend on the optional taskShow library, | |
1645 | which is required to get the actual stack information. | |
1646 | ||
1647 | The consequence of this is that with -fstack-check | |
1648 | the environment task must have an actual stack size | |
1649 | of at least 20kB and the usable size will be about 14kB. | |
1650 | */ | |
1651 | ||
1652 | __gnat_set_stack_size (14336); | |
1653 | /* Allow some head room for the stack checking code, and for | |
1654 | stack space consumed during initialization */ | |
1655 | } | |
1656 | ||
1657 | /********************************/ | |
1658 | /* __gnat_initialize for NetBSD */ | |
1659 | /********************************/ | |
1660 | ||
1661 | #elif defined(__NetBSD__) | |
1662 | ||
1663 | #include <signal.h> | |
1664 | #include <unistd.h> | |
1665 | ||
1666 | static void | |
1667 | __gnat_error_handler (sig) | |
1668 | int sig; | |
1669 | { | |
1670 | struct Exception_Data *exception; | |
1671 | const char *msg; | |
1672 | ||
1673 | switch(sig) | |
1674 | { | |
1675 | case SIGFPE: | |
1676 | exception = &constraint_error; | |
1677 | msg = "SIGFPE"; | |
1678 | break; | |
1679 | case SIGILL: | |
1680 | exception = &constraint_error; | |
1681 | msg = "SIGILL"; | |
1682 | break; | |
1683 | case SIGSEGV: | |
1684 | exception = &storage_error; | |
1685 | msg = "stack overflow or erroneous memory access"; | |
1686 | break; | |
1687 | case SIGBUS: | |
1688 | exception = &constraint_error; | |
1689 | msg = "SIGBUS"; | |
1690 | break; | |
1691 | default: | |
1692 | exception = &program_error; | |
1693 | msg = "unhandled signal"; | |
1694 | } | |
38cbfe40 | 1695 | |
fbf5a39b AC |
1696 | Raise_From_Signal_Handler(exception, msg); |
1697 | } | |
1698 | ||
1699 | void | |
1700 | __gnat_install_handler() | |
1701 | { | |
1702 | struct sigaction act; | |
38cbfe40 | 1703 | |
fbf5a39b AC |
1704 | act.sa_handler = __gnat_error_handler; |
1705 | act.sa_flags = SA_NODEFER | SA_RESTART; | |
1706 | sigemptyset (&act.sa_mask); | |
1707 | ||
1708 | /* Do not install handlers if interrupt state is "System" */ | |
1709 | if (__gnat_get_interrupt_state (SIGFPE) != 's') | |
1710 | sigaction (SIGFPE, &act, NULL); | |
1711 | if (__gnat_get_interrupt_state (SIGILL) != 's') | |
1712 | sigaction (SIGILL, &act, NULL); | |
1713 | if (__gnat_get_interrupt_state (SIGSEGV) != 's') | |
1714 | sigaction (SIGSEGV, &act, NULL); | |
1715 | if (__gnat_get_interrupt_state (SIGBUS) != 's') | |
1716 | sigaction (SIGBUS, &act, NULL); | |
1717 | } | |
38cbfe40 | 1718 | |
fbf5a39b AC |
1719 | void |
1720 | __gnat_initialize () | |
1721 | { | |
1722 | __gnat_install_handler (); | |
38cbfe40 | 1723 | __gnat_init_float (); |
fbf5a39b | 1724 | } |
38cbfe40 | 1725 | |
fbf5a39b AC |
1726 | /***************************************/ |
1727 | /* __gnat_initialize (RTEMS version) */ | |
1728 | /***************************************/ | |
1729 | ||
1730 | #elif defined(__rtems__) | |
1731 | ||
1732 | extern void __gnat_install_handler (); | |
1733 | ||
1734 | /* For RTEMS, each bsp will provide a custom __gnat_install_handler (). */ | |
1735 | ||
1736 | void | |
1737 | __gnat_initialize () | |
1738 | { | |
1739 | __gnat_install_handler (); | |
38cbfe40 RK |
1740 | } |
1741 | ||
c4039eb0 JS |
1742 | /***************************************/ |
1743 | /* __gnat_initialize (RTEMS version) */ | |
1744 | /***************************************/ | |
1745 | ||
1746 | #elif defined(__rtems__) | |
1747 | ||
1748 | extern void __gnat_install_handler (); | |
1749 | ||
1750 | /* For RTEMS, each bsp will provide a custom __gnat_install_handler (). */ | |
1751 | ||
1752 | void | |
1753 | __gnat_initialize () | |
1754 | { | |
1755 | __gnat_install_handler (); | |
1756 | } | |
1757 | ||
38cbfe40 RK |
1758 | #else |
1759 | ||
1760 | /* For all other versions of GNAT, the initialize routine and handler | |
1761 | installation do nothing */ | |
1762 | ||
1763 | /***************************************/ | |
fbf5a39b | 1764 | /* __gnat_initialize (Default Version) */ |
38cbfe40 RK |
1765 | /***************************************/ |
1766 | ||
1767 | void | |
1768 | __gnat_initialize () | |
1769 | { | |
1770 | } | |
1771 | ||
1772 | /********************************************/ | |
fbf5a39b | 1773 | /* __gnat_install_handler (Default Version) */ |
38cbfe40 RK |
1774 | /********************************************/ |
1775 | ||
1776 | void | |
1777 | __gnat_install_handler () | |
1778 | { | |
1779 | __gnat_handler_installed = 1; | |
1780 | } | |
1781 | ||
1782 | #endif | |
1783 | ||
38cbfe40 RK |
1784 | /*********************/ |
1785 | /* __gnat_init_float */ | |
1786 | /*********************/ | |
1787 | ||
1788 | /* This routine is called as each process thread is created, for possible | |
1789 | initialization of the FP processor. This version is used under INTERIX, | |
1790 | WIN32 and could be used under OS/2 */ | |
1791 | ||
1792 | #if defined (_WIN32) || defined (__INTERIX) || defined (__EMX__) \ | |
fbf5a39b | 1793 | || defined (__Lynx__) || defined(__NetBSD__) |
38cbfe40 RK |
1794 | |
1795 | #define HAVE_GNAT_INIT_FLOAT | |
1796 | ||
1797 | void | |
1798 | __gnat_init_float () | |
1799 | { | |
1800 | #if defined (__i386__) || defined (i386) | |
1801 | ||
1802 | /* This is used to properly initialize the FPU on an x86 for each | |
1803 | process thread. */ | |
1804 | ||
1805 | asm ("finit"); | |
1806 | ||
1807 | #endif /* Defined __i386__ */ | |
1808 | } | |
1809 | #endif | |
1810 | ||
38cbfe40 RK |
1811 | #ifndef HAVE_GNAT_INIT_FLOAT |
1812 | ||
1813 | /* All targets without a specific __gnat_init_float will use an empty one */ | |
1814 | void | |
1815 | __gnat_init_float () | |
1816 | { | |
1817 | } | |
1818 | #endif |