init.c 81.6 KB
Newer Older
Richard Kenner committed
1 2 3 4 5 6 7 8
/****************************************************************************
 *                                                                          *
 *                         GNAT COMPILER COMPONENTS                         *
 *                                                                          *
 *                                 I N I T                                  *
 *                                                                          *
 *                          C Implementation File                           *
 *                                                                          *
9
 *          Copyright (C) 1992-2018, Free Software Foundation, Inc.         *
Richard Kenner committed
10 11 12
 *                                                                          *
 * GNAT is free software;  you can  redistribute it  and/or modify it under *
 * terms of the  GNU General Public License as published  by the Free Soft- *
Arnaud Charlet committed
13
 * ware  Foundation;  either version 3,  or (at your option) any later ver- *
Richard Kenner committed
14 15
 * sion.  GNAT is distributed in the hope that it will be useful, but WITH- *
 * OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY *
Arnaud Charlet committed
16 17 18 19 20 21 22 23 24 25
 * or FITNESS FOR A PARTICULAR PURPOSE.                                     *
 *                                                                          *
 * As a special exception under Section 7 of GPL version 3, you are granted *
 * additional permissions described in the GCC Runtime Library Exception,   *
 * version 3.1, as published by the Free Software Foundation.               *
 *                                                                          *
 * You should have received a copy of the GNU General Public License and    *
 * a copy of the GCC Runtime Library Exception along with this program;     *
 * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    *
 * <http://www.gnu.org/licenses/>.                                          *
Richard Kenner committed
26 27
 *                                                                          *
 * GNAT was originally developed  by the GNAT team at  New York University. *
28
 * Extensive contributions were provided by Ada Core Technologies Inc.      *
Richard Kenner committed
29 30 31
 *                                                                          *
 ****************************************************************************/

32 33
/*  This unit contains initialization circuits that are system dependent.
    A major part of the functionality involves stack overflow checking.
Richard Kenner committed
34 35 36
    The GCC backend generates probe instructions to test for stack overflow.
    For details on the exact approach used to generate these probes, see the
    "Using and Porting GCC" manual, in particular the "Stack Checking" section
37 38 39
    and the subsection "Specifying How Stack Checking is Done".  The handlers
    installed by this file are used to catch the resulting signals that come
    from these probes failing (i.e. touching protected pages).  */
Richard Kenner committed
40

Arnaud Charlet committed
41 42 43
/* This file should be kept synchronized with s-init.ads, s-init.adb and the
   s-init-*.adb variants. All these files implement the required functionality
   for different targets.  */
Arnaud Charlet committed
44

Richard Kenner committed
45
/* The following include is here to meet the published VxWorks requirement
46
   that the __vxworks header appear before any other include.  */
Richard Kenner committed
47 48
#ifdef __vxworks
#include "vxWorks.h"
Arnaud Charlet committed
49
#include "version.h" /* for _WRS_VXWORKS_MAJOR */
Richard Kenner committed
50 51
#endif

52
#ifdef __ANDROID__
53
#undef __linux__
54 55
#endif

Richard Kenner committed
56 57 58 59
#ifdef IN_RTS
#include "tconfig.h"
#include "tsystem.h"
#include <sys/stat.h>
60

Arnaud Charlet committed
61
/* We don't have libiberty, so use malloc.  */
62
#define xmalloc(S) malloc (S)
Richard Kenner committed
63 64 65 66 67 68 69 70
#else
#include "config.h"
#include "system.h"
#endif

#include "adaint.h"
#include "raise.h"

71 72 73 74
#ifdef __cplusplus
extern "C" {
#endif

Richard Kenner committed
75 76
extern void __gnat_raise_program_error (const char *, int);

77
/* Addresses of exception data blocks for predefined exceptions.  Tasking_Error
78 79
   is not used in this unit, and the abort signal is only used on IRIX.
   ??? Revisit this part since IRIX is no longer supported.  */
Richard Kenner committed
80 81 82 83 84
extern struct Exception_Data constraint_error;
extern struct Exception_Data numeric_error;
extern struct Exception_Data program_error;
extern struct Exception_Data storage_error;

85
/* For the Cert run time we use the regular raise exception routine because
86
   Raise_From_Signal_Handler is not available.  */
87 88 89 90 91
#ifdef CERT
#define Raise_From_Signal_Handler \
                      __gnat_raise_exception
extern void Raise_From_Signal_Handler (struct Exception_Data *, const char *);
#else
Richard Kenner committed
92 93
#define Raise_From_Signal_Handler \
                      ada__exceptions__raise_from_signal_handler
94
extern void Raise_From_Signal_Handler (struct Exception_Data *, const char *);
95
#endif
Richard Kenner committed
96

Arnaud Charlet committed
97 98 99
/* Global values computed by the binder.  Note that these variables are
   declared here, not in the binder file, to avoid having unresolved
   references in the shared libgnat.  */
100
int   __gl_main_priority                 = -1;
Arnaud Charlet committed
101
int   __gl_main_cpu                      = -1;
102 103 104 105 106 107 108 109 110 111 112
int   __gl_time_slice_val                = -1;
char  __gl_wc_encoding                   = 'n';
char  __gl_locking_policy                = ' ';
char  __gl_queuing_policy                = ' ';
char  __gl_task_dispatching_policy       = ' ';
char *__gl_priority_specific_dispatching = 0;
int   __gl_num_specific_dispatching      = 0;
char *__gl_interrupt_states              = 0;
int   __gl_num_interrupt_states          = 0;
int   __gl_unreserve_all_interrupts      = 0;
int   __gl_exception_tracebacks          = 0;
Arnaud Charlet committed
113
int   __gl_exception_tracebacks_symbolic = 0;
114 115
int   __gl_detect_blocking               = 0;
int   __gl_default_stack_size            = -1;
116
int   __gl_leap_seconds_support          = 0;
117
int   __gl_canonical_streams             = 0;
Arnaud Charlet committed
118
char *__gl_bind_env_addr                 = NULL;
Richard Kenner committed
119

Arnaud Charlet committed
120 121 122
/* This value is not used anymore, but kept for bootstrapping purpose.  */
int   __gl_zero_cost_exceptions          = 0;

123
/* Indication of whether synchronous signal handler has already been
124
   installed by a previous call to adainit.  */
Richard Kenner committed
125 126
int  __gnat_handler_installed      = 0;

127 128 129
#ifndef IN_RTS
int __gnat_inside_elab_final_code = 0;
/* ??? This variable is obsolete since 2001-08-29 but is kept to allow
130
   bootstrap from old GNAT versions (< 3.15).  */
131 132
#endif

Richard Kenner committed
133
/* HAVE_GNAT_INIT_FLOAT must be set on every targets where a __gnat_init_float
134 135
   is defined.  If this is not set then a void implementation will be defined
   at the end of this unit.  */
Richard Kenner committed
136 137
#undef HAVE_GNAT_INIT_FLOAT

138 139 140 141 142 143 144 145
/******************************/
/* __gnat_get_interrupt_state */
/******************************/

char __gnat_get_interrupt_state (int);

/* This routine is called from the runtime as needed to determine the state
   of an interrupt, as set by an Interrupt_State pragma appearing anywhere
146
   in the current partition.  The input argument is the interrupt number,
147 148 149 150 151
   and the result is one of the following:

       'n'   this interrupt not set by any Interrupt_State pragma
       'u'   Interrupt_State pragma set state to User
       'r'   Interrupt_State pragma set state to Runtime
152
       's'   Interrupt_State pragma set state to System  */
153 154

char
R. Kelley Cook committed
155
__gnat_get_interrupt_state (int intrup)
156 157 158 159 160 161 162
{
  if (intrup >= __gl_num_interrupt_states)
    return 'n';
  else
    return __gl_interrupt_states [intrup];
}

163 164 165
/***********************************/
/* __gnat_get_specific_dispatching */
/***********************************/
Richard Kenner committed
166

167
char __gnat_get_specific_dispatching (int);
Richard Kenner committed
168

169
/* This routine is called from the runtime as needed to determine the
170 171
   priority specific dispatching policy, as set by a
   Priority_Specific_Dispatching pragma appearing anywhere in the current
172 173
   partition.  The input argument is the priority number, and the result
   is the upper case first character of the policy name, e.g. 'F' for
174
   FIFO_Within_Priorities. A space ' ' is returned if no
175
   Priority_Specific_Dispatching pragma is used in the partition.  */
Arnaud Charlet committed
176

177 178
char
__gnat_get_specific_dispatching (int priority)
Richard Kenner committed
179
{
180 181 182 183 184 185 186
  if (__gl_num_specific_dispatching == 0)
    return ' ';
  else if (priority >= __gl_num_specific_dispatching)
    return 'F';
  else
    return __gl_priority_specific_dispatching [priority];
}
187

188 189 190 191 192
#ifndef IN_RTS

/**********************/
/* __gnat_set_globals */
/**********************/
193

194
/* This routine is kept for bootstrapping purposes, since the binder generated
195
   file now sets the __gl_* variables directly.  */
196

197
void
198
__gnat_set_globals (void)
199 200
{
}
201

202
#endif
Richard Kenner committed
203

204 205 206
/***************/
/* AIX Section */
/***************/
Richard Kenner committed
207 208 209

#if defined (_AIX)

210 211 212
#include <signal.h>
#include <sys/time.h>

213
/* Some versions of AIX don't define SA_NODEFER.  */
Richard Kenner committed
214

215
#ifndef SA_NODEFER
Richard Kenner committed
216
#define SA_NODEFER 0
217
#endif /* SA_NODEFER */
Richard Kenner committed
218

219
/* Versions of AIX before 4.3 don't have nanosleep but provide
220
   nsleep instead.  */
Richard Kenner committed
221

222
#ifndef _AIXVERSION_430
Richard Kenner committed
223

R. Kelley Cook committed
224
extern int nanosleep (struct timestruc_t *, struct timestruc_t *);
Richard Kenner committed
225 226

int
R. Kelley Cook committed
227
nanosleep (struct timestruc_t *Rqtp, struct timestruc_t *Rmtp)
Richard Kenner committed
228 229 230 231
{
  return nsleep (Rqtp, Rmtp);
}

232 233
#endif /* _AIXVERSION_430 */

Richard Kenner committed
234
static void
235
__gnat_error_handler (int sig,
Arnaud Charlet committed
236 237
		      siginfo_t *si ATTRIBUTE_UNUSED,
		      void *ucontext ATTRIBUTE_UNUSED)
Richard Kenner committed
238 239
{
  struct Exception_Data *exception;
Geert Bosch committed
240
  const char *msg;
Richard Kenner committed
241 242 243 244

  switch (sig)
    {
    case SIGSEGV:
245
      /* FIXME: we need to detect the case of a *real* SIGSEGV.  */
Richard Kenner committed
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
      exception = &storage_error;
      msg = "stack overflow or erroneous memory access";
      break;

    case SIGBUS:
      exception = &constraint_error;
      msg = "SIGBUS";
      break;

    case SIGFPE:
      exception = &constraint_error;
      msg = "SIGFPE";
      break;

    default:
      exception = &program_error;
      msg = "unhandled signal";
    }

  Raise_From_Signal_Handler (exception, msg);
}

void
R. Kelley Cook committed
269
__gnat_install_handler (void)
Richard Kenner committed
270 271 272 273 274
{
  struct sigaction act;

  /* Set up signal handler to map synchronous signals to appropriate
     exceptions.  Make sure that the handler isn't interrupted by another
275
     signal that might cause a scheduling event!  */
Richard Kenner committed
276

277 278
  act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
  act.sa_sigaction = __gnat_error_handler;
279 280
  sigemptyset (&act.sa_mask);

281
  /* Do not install handlers if interrupt state is "System".  */
282 283 284 285 286 287 288 289 290 291
  if (__gnat_get_interrupt_state (SIGABRT) != 's')
    sigaction (SIGABRT, &act, NULL);
  if (__gnat_get_interrupt_state (SIGFPE) != 's')
    sigaction (SIGFPE,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGILL) != 's')
    sigaction (SIGILL,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGSEGV) != 's')
    sigaction (SIGSEGV, &act, NULL);
  if (__gnat_get_interrupt_state (SIGBUS) != 's')
    sigaction (SIGBUS,  &act, NULL);
Richard Kenner committed
292 293 294 295

  __gnat_handler_installed = 1;
}

296
/*****************/
297 298
/* HP-UX section */
/*****************/
Richard Kenner committed
299

300
#elif defined (__hpux__)
Richard Kenner committed
301 302

#include <signal.h>
303
#include <sys/ucontext.h>
Richard Kenner committed
304

Arnaud Charlet committed
305 306
#if defined (IN_RTS) && defined (__ia64__)

Arnaud Charlet committed
307
#include <sys/uc_access.h>
Arnaud Charlet committed
308

Arnaud Charlet committed
309 310 311 312 313 314 315 316 317 318 319 320
#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE

void
__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
{
  ucontext_t *uc = (ucontext_t *) ucontext;
  uint64_t ip;

  /* Adjust on itanium, as GetIPInfo is not supported.  */
  __uc_get_ip (uc, &ip);
  __uc_set_ip (uc, ip + 1);
}
Arnaud Charlet committed
321
#endif /* IN_RTS && __ia64__ */
Arnaud Charlet committed
322 323 324 325

/* Tasking and Non-tasking signal handler.  Map SIGnal to Ada exception
   propagation after the required low level adjustments.  */

326
static void
Arnaud Charlet committed
327
__gnat_error_handler (int sig, siginfo_t *si ATTRIBUTE_UNUSED, void *ucontext)
Richard Kenner committed
328 329
{
  struct Exception_Data *exception;
330
  const char *msg;
Richard Kenner committed
331

Arnaud Charlet committed
332 333
  __gnat_adjust_context_for_raise (sig, ucontext);

Richard Kenner committed
334 335 336
  switch (sig)
    {
    case SIGSEGV:
337
      /* FIXME: we need to detect the case of a *real* SIGSEGV.  */
Richard Kenner committed
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
      exception = &storage_error;
      msg = "stack overflow or erroneous memory access";
      break;

    case SIGBUS:
      exception = &constraint_error;
      msg = "SIGBUS";
      break;

    case SIGFPE:
      exception = &constraint_error;
      msg = "SIGFPE";
      break;

    default:
      exception = &program_error;
      msg = "unhandled signal";
    }

  Raise_From_Signal_Handler (exception, msg);
}

360 361 362 363 364 365 366
/* This must be in keeping with System.OS_Interface.Alternate_Stack_Size.  */
#if defined (__hppa__)
char __gnat_alternate_stack[16 * 1024]; /* 2 * SIGSTKSZ */
#else
char __gnat_alternate_stack[128 * 1024]; /* MINSIGSTKSZ */
#endif

Richard Kenner committed
367
void
R. Kelley Cook committed
368
__gnat_install_handler (void)
Richard Kenner committed
369 370 371 372 373
{
  struct sigaction act;

  /* Set up signal handler to map synchronous signals to appropriate
     exceptions.  Make sure that the handler isn't interrupted by another
374
     signal that might cause a scheduling event!  Also setup an alternate
Richard Kenner committed
375 376
     stack region for the handler execution so that stack overflows can be
     handled properly, avoiding a SEGV generation from stack usage by the
377
     handler itself.  */
Richard Kenner committed
378 379

  stack_t stack;
380 381
  stack.ss_sp = __gnat_alternate_stack;
  stack.ss_size = sizeof (__gnat_alternate_stack);
Richard Kenner committed
382
  stack.ss_flags = 0;
383
  sigaltstack (&stack, NULL);
Richard Kenner committed
384

385
  act.sa_sigaction = __gnat_error_handler;
386
  act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
387 388
  sigemptyset (&act.sa_mask);

389
  /* Do not install handlers if interrupt state is "System".  */
390 391 392 393 394 395 396 397
  if (__gnat_get_interrupt_state (SIGABRT) != 's')
    sigaction (SIGABRT, &act, NULL);
  if (__gnat_get_interrupt_state (SIGFPE) != 's')
    sigaction (SIGFPE,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGILL) != 's')
    sigaction (SIGILL,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGBUS) != 's')
    sigaction (SIGBUS,  &act, NULL);
398 399 400
  act.sa_flags |= SA_ONSTACK;
  if (__gnat_get_interrupt_state (SIGSEGV) != 's')
    sigaction (SIGSEGV, &act, NULL);
Richard Kenner committed
401 402 403 404

  __gnat_handler_installed = 1;
}

405 406 407
/*********************/
/* GNU/Linux Section */
/*********************/
Richard Kenner committed
408

409
#elif defined (__linux__)
Richard Kenner committed
410 411

#include <signal.h>
412 413 414

#define __USE_GNU 1 /* required to get REG_EIP/RIP from glibc's ucontext.h */
#include <sys/ucontext.h>
Richard Kenner committed
415

416
/* GNU/Linux, which uses glibc, does not define NULL in included
417
   header files.  */
Richard Kenner committed
418 419 420 421 422

#if !defined (NULL)
#define NULL ((void *) 0)
#endif

423 424 425
#if defined (MaRTE)

/* MaRTE OS provides its own version of sigaction, sigfillset, and
426
   sigemptyset (overriding these symbol names).  We want to make sure that
427 428
   the versions provided by the underlying C library are used here (these
   versions are renamed by MaRTE to linux_sigaction, fake_linux_sigfillset,
429
   and fake_linux_sigemptyset, respectively).  The MaRTE library will not
430 431
   always be present (it will not be linked if no tasking constructs are
   used), so we use the weak symbol mechanism to point always to the symbols
432
   defined within the C library.  */
433 434 435

#pragma weak linux_sigaction
int linux_sigaction (int signum, const struct sigaction *act,
Arnaud Charlet committed
436 437
		     struct sigaction *oldact)
{
438 439 440 441 442
  return sigaction (signum, act, oldact);
}
#define sigaction(signum, act, oldact) linux_sigaction (signum, act, oldact)

#pragma weak fake_linux_sigfillset
Arnaud Charlet committed
443 444
void fake_linux_sigfillset (sigset_t *set)
{
445 446 447 448 449
  sigfillset (set);
}
#define sigfillset(set) fake_linux_sigfillset (set)

#pragma weak fake_linux_sigemptyset
Arnaud Charlet committed
450 451
void fake_linux_sigemptyset (sigset_t *set)
{
452 453 454 455 456 457
  sigemptyset (set);
}
#define sigemptyset(set) fake_linux_sigemptyset (set)

#endif

458
#if defined (__i386__) || defined (__x86_64__) || defined (__ia64__) \
Arnaud Charlet committed
459
    || defined (__ARMEL__)
460 461 462 463 464

#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE

void
__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
Richard Kenner committed
465
{
466
  mcontext_t *mcontext = &((ucontext_t *) ucontext)->uc_mcontext;
Richard Kenner committed
467

Arnaud Charlet committed
468
  /* On the i386 and x86-64 architectures, stack checking is performed by
469 470 471 472 473 474 475 476 477 478 479 480
     means of probes with moving stack pointer, that is to say the probed
     address is always the value of the stack pointer.  Upon hitting the
     guard page, the stack pointer therefore points to an inaccessible
     address and an alternate signal stack is needed to run the handler.
     But there is an additional twist: on these architectures, the EH
     return code writes the address of the handler at the target CFA's
     value on the stack before doing the jump.  As a consequence, if
     there is an active handler in the frame whose stack has overflowed,
     the stack pointer must nevertheless point to an accessible address
     by the time the EH return is executed.

     We therefore adjust the saved value of the stack pointer by the size
Arnaud Charlet committed
481 482 483 484
     of one page + a small dope of 4 words, in order to make sure that it
     points to an accessible address in case it's used as the target CFA.
     The stack checking code guarantees that this address is unused by the
     time this happens.  */
485

486
#if defined (__i386__)
Arnaud Charlet committed
487
  unsigned long *pc = (unsigned long *)mcontext->gregs[REG_EIP];
488
  /* The pattern is "orl $0x0,(%esp)" for a probe in 32-bit mode.  */
Arnaud Charlet committed
489
  if (signo == SIGSEGV && pc && *pc == 0x00240c83)
Arnaud Charlet committed
490
    mcontext->gregs[REG_ESP] += 4096 + 4 * sizeof (unsigned long);
491
#elif defined (__x86_64__)
H.J. Lu committed
492 493 494 495 496 497 498
  unsigned long long *pc = (unsigned long long *)mcontext->gregs[REG_RIP];
  if (signo == SIGSEGV && pc
      /* The pattern is "orq $0x0,(%rsp)" for a probe in 64-bit mode.  */
      && ((*pc & 0xffffffffffLL) == 0x00240c8348LL
	  /* The pattern may also be "orl $0x0,(%esp)" for a probe in
	     x32 mode.  */
	  || (*pc & 0xffffffffLL) == 0x00240c83LL))
Arnaud Charlet committed
499
    mcontext->gregs[REG_RSP] += 4096 + 4 * sizeof (unsigned long);
500
#elif defined (__ia64__)
501
  /* ??? The IA-64 unwinder doesn't compensate for signals.  */
502
  mcontext->sc_ip++;
Arnaud Charlet committed
503 504 505
#elif defined (__ARMEL__)
  /* ARM Bump has to be an even number because of odd/even architecture.  */
  mcontext->arm_pc+=2;
Arnaud Charlet committed
506
#ifdef __thumb2__
Arnaud Charlet committed
507
#define CPSR_THUMB_BIT 5
Arnaud Charlet committed
508
  /* For thumb, the return address much have the low order bit set, otherwise
Arnaud Charlet committed
509 510 511 512 513
     the unwinder will reset to "arm" mode upon return.  As long as the
     compilation unit containing the landing pad is compiled with the same
     mode (arm vs thumb) as the signaling compilation unit, this works.  */
  if (mcontext->arm_cpsr & (1<<CPSR_THUMB_BIT))
    mcontext->arm_pc+=1;
Arnaud Charlet committed
514
#endif
515 516
#endif
}
Richard Kenner committed
517

518 519
#endif

Richard Kenner committed
520
static void
Arnaud Charlet committed
521
__gnat_error_handler (int sig, siginfo_t *si ATTRIBUTE_UNUSED, void *ucontext)
Richard Kenner committed
522 523
{
  struct Exception_Data *exception;
Arnaud Charlet committed
524 525 526 527 528
  const char *msg;

  /* Adjusting is required for every fault context, so adjust for this one
     now, before we possibly trigger a recursive fault below.  */
  __gnat_adjust_context_for_raise (sig, ucontext);
Richard Kenner committed
529 530 531 532

  switch (sig)
    {
    case SIGSEGV:
Arnaud Charlet committed
533 534 535
      /* Here we would like a discrimination test to see whether the page
	 before the faulting address is accessible.  Unfortunately, Linux
	 seems to have no way of giving us the faulting address.
Richard Kenner committed
536

Arnaud Charlet committed
537 538
	 In old versions of init.c, we had a test of the page before the
	 stack pointer:
Richard Kenner committed
539

Arnaud Charlet committed
540 541
	   ((volatile char *)
	    ((long) si->esp_at_signal & - getpagesize ()))[getpagesize ()];
Richard Kenner committed
542

Arnaud Charlet committed
543 544
	 but that's wrong since it tests the stack pointer location and the
	 stack probing code may not move it until all probes succeed.
Richard Kenner committed
545

Arnaud Charlet committed
546 547 548 549
	 For now we simply do not attempt any discrimination at all. Note
	 that this is quite acceptable, since a "real" SIGSEGV can only
	 occur as the result of an erroneous program.  */
      exception = &storage_error;
Arnaud Charlet committed
550
      msg = "stack overflow or erroneous memory access";
Richard Kenner committed
551 552 553
      break;

    case SIGBUS:
Arnaud Charlet committed
554 555
      exception = &storage_error;
      msg = "SIGBUS: possible stack overflow";
Richard Kenner committed
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
      break;

    case SIGFPE:
      exception = &constraint_error;
      msg = "SIGFPE";
      break;

    default:
      exception = &program_error;
      msg = "unhandled signal";
    }

  Raise_From_Signal_Handler (exception, msg);
}

571 572 573 574 575 576 577 578
#ifndef __ia64__
#define HAVE_GNAT_ALTERNATE_STACK 1
/* This must be in keeping with System.OS_Interface.Alternate_Stack_Size.
   It must be larger than MINSIGSTKSZ and hopefully near 2 * SIGSTKSZ.  */
# if 16 * 1024 < MINSIGSTKSZ
#  error "__gnat_alternate_stack too small"
# endif
char __gnat_alternate_stack[16 * 1024];
579 580
#endif

581 582 583 584 585 586 587
#ifdef __XENO__
#include <sys/mman.h>
#include <native/task.h>

RT_TASK main_task;
#endif

Richard Kenner committed
588
void
R. Kelley Cook committed
589
__gnat_install_handler (void)
Richard Kenner committed
590 591 592
{
  struct sigaction act;

593 594 595 596 597 598 599 600 601 602 603 604 605 606
#ifdef __XENO__
  int prio;

  if (__gl_main_priority == -1)
    prio = 49;
  else
    prio = __gl_main_priority;

  /* Avoid memory swapping for this program */

  mlockall (MCL_CURRENT|MCL_FUTURE);

  /* Turn the current Linux task into a native Xenomai task */

Arnaud Charlet committed
607
  rt_task_shadow (&main_task, "environment_task", prio, T_FPU);
608 609
#endif

Richard Kenner committed
610 611
  /* Set up signal handler to map synchronous signals to appropriate
     exceptions.  Make sure that the handler isn't interrupted by another
612 613 614 615 616
     signal that might cause a scheduling event!  Also setup an alternate
     stack region for the handler execution so that stack overflows can be
     handled properly, avoiding a SEGV generation from stack usage by the
     handler itself.  */

617 618
  act.sa_sigaction = __gnat_error_handler;
  act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
619 620
  sigemptyset (&act.sa_mask);

621
  /* Do not install handlers if interrupt state is "System".  */
622 623 624 625 626 627 628 629
  if (__gnat_get_interrupt_state (SIGABRT) != 's')
    sigaction (SIGABRT, &act, NULL);
  if (__gnat_get_interrupt_state (SIGFPE) != 's')
    sigaction (SIGFPE,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGILL) != 's')
    sigaction (SIGILL,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGBUS) != 's')
    sigaction (SIGBUS,  &act, NULL);
Arnaud Charlet committed
630 631
  if (__gnat_get_interrupt_state (SIGSEGV) != 's')
    {
632
#ifdef HAVE_GNAT_ALTERNATE_STACK
Arnaud Charlet committed
633 634 635 636 637 638 639 640 641 642 643
      /* Setup an alternate stack region for the handler execution so that
	 stack overflows can be handled properly, avoiding a SEGV generation
	 from stack usage by the handler itself.  */
      stack_t stack;

      stack.ss_sp = __gnat_alternate_stack;
      stack.ss_size = sizeof (__gnat_alternate_stack);
      stack.ss_flags = 0;
      sigaltstack (&stack, NULL);

      act.sa_flags |= SA_ONSTACK;
644
#endif
Arnaud Charlet committed
645 646
      sigaction (SIGSEGV, &act, NULL);
    }
Richard Kenner committed
647 648 649 650

  __gnat_handler_installed = 1;
}

651
/*******************/
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
/* LynxOS Section */
/*******************/

#elif defined (__Lynx__)

#include <signal.h>
#include <unistd.h>

static void
__gnat_error_handler (int sig)
{
  struct Exception_Data *exception;
  const char *msg;

  switch(sig)
  {
    case SIGFPE:
      exception = &constraint_error;
      msg = "SIGFPE";
      break;
    case SIGILL:
      exception = &constraint_error;
      msg = "SIGILL";
      break;
    case SIGSEGV:
      exception = &storage_error;
      msg = "stack overflow or erroneous memory access";
      break;
    case SIGBUS:
      exception = &constraint_error;
      msg = "SIGBUS";
      break;
    default:
      exception = &program_error;
      msg = "unhandled signal";
    }

Arnaud Charlet committed
689
    Raise_From_Signal_Handler (exception, msg);
690 691 692
}

void
Arnaud Charlet committed
693
__gnat_install_handler (void)
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
{
  struct sigaction act;

  act.sa_handler = __gnat_error_handler;
  act.sa_flags = 0x0;
  sigemptyset (&act.sa_mask);

  /* Do not install handlers if interrupt state is "System".  */
  if (__gnat_get_interrupt_state (SIGFPE) != 's')
    sigaction (SIGFPE,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGILL) != 's')
    sigaction (SIGILL,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGSEGV) != 's')
    sigaction (SIGSEGV, &act, NULL);
  if (__gnat_get_interrupt_state (SIGBUS) != 's')
    sigaction (SIGBUS,  &act, NULL);

  __gnat_handler_installed = 1;
}

/*******************/
715 716
/* Solaris Section */
/*******************/
Richard Kenner committed
717

718
#elif defined (__sun__) && !defined (__vxworks)
Richard Kenner committed
719 720 721

#include <signal.h>
#include <siginfo.h>
722 723 724
#include <sys/ucontext.h>
#include <sys/regset.h>

Richard Kenner committed
725
static void
Arnaud Charlet committed
726
__gnat_error_handler (int sig, siginfo_t *si, void *ucontext ATTRIBUTE_UNUSED)
Richard Kenner committed
727 728 729
{
  struct Exception_Data *exception;
  static int recurse = 0;
730
  const char *msg;
Richard Kenner committed
731 732 733 734 735 736 737 738 739 740 741

  switch (sig)
    {
    case SIGSEGV:
      /* If the problem was permissions, this is a constraint error.
	 Likewise if the failing address isn't maximally aligned or if
	 we've recursed.

	 ??? Using a static variable here isn't task-safe, but it's
	 much too hard to do anything else and we're just determining
	 which exception to raise.  */
Arnaud Charlet committed
742 743 744
      if (si->si_code == SEGV_ACCERR
	  || (long) si->si_addr == 0
	  || (((long) si->si_addr) & 3) != 0
Richard Kenner committed
745 746 747 748 749 750 751
	  || recurse)
	{
	  exception = &constraint_error;
	  msg = "SIGSEGV";
	}
      else
	{
752
	  /* See if the page before the faulting page is accessible.  Do that
Richard Kenner committed
753 754 755 756 757
	     by trying to access it.  We'd like to simply try to access
	     4096 + the faulting address, but it's not guaranteed to be
	     the actual address, just to be on the same page.  */
	  recurse++;
	  ((volatile char *)
Arnaud Charlet committed
758
	   ((long) si->si_addr & - getpagesize ()))[getpagesize ()];
Richard Kenner committed
759
	  exception = &storage_error;
Arnaud Charlet committed
760
	  msg = "stack overflow or erroneous memory access";
Richard Kenner committed
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
	}
      break;

    case SIGBUS:
      exception = &program_error;
      msg = "SIGBUS";
      break;

    case SIGFPE:
      exception = &constraint_error;
      msg = "SIGFPE";
      break;

    default:
      exception = &program_error;
      msg = "unhandled signal";
    }

  recurse = 0;
  Raise_From_Signal_Handler (exception, msg);
}

void
R. Kelley Cook committed
784
__gnat_install_handler (void)
Richard Kenner committed
785 786 787 788 789
{
  struct sigaction act;

  /* Set up signal handler to map synchronous signals to appropriate
     exceptions.  Make sure that the handler isn't interrupted by another
790
     signal that might cause a scheduling event!  */
Richard Kenner committed
791

792
  act.sa_sigaction = __gnat_error_handler;
Richard Kenner committed
793
  act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
794 795
  sigemptyset (&act.sa_mask);

796
  /* Do not install handlers if interrupt state is "System".  */
797 798 799 800 801 802 803 804
  if (__gnat_get_interrupt_state (SIGABRT) != 's')
    sigaction (SIGABRT, &act, NULL);
  if (__gnat_get_interrupt_state (SIGFPE) != 's')
    sigaction (SIGFPE,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGSEGV) != 's')
    sigaction (SIGSEGV, &act, NULL);
  if (__gnat_get_interrupt_state (SIGBUS) != 's')
    sigaction (SIGBUS,  &act, NULL);
Richard Kenner committed
805 806 807 808

  __gnat_handler_installed = 1;
}

809 810 811
/***************/
/* VMS Section */
/***************/
Richard Kenner committed
812 813 814

#elif defined (VMS)

815
/* Routine called from binder to override default feature values. */
Arnaud Charlet committed
816
void __gnat_set_features (void);
817
int __gnat_features_set = 0;
Arnaud Charlet committed
818
void (*__gnat_ctrl_c_handler) (void) = 0;
819

Arnaud Charlet committed
820 821 822 823 824 825 826 827 828 829
#ifdef __IA64
#define lib_get_curr_invo_context LIB$I64_GET_CURR_INVO_CONTEXT
#define lib_get_prev_invo_context LIB$I64_GET_PREV_INVO_CONTEXT
#define lib_get_invo_handle LIB$I64_GET_INVO_HANDLE
#else
#define lib_get_curr_invo_context LIB$GET_CURR_INVO_CONTEXT
#define lib_get_prev_invo_context LIB$GET_PREV_INVO_CONTEXT
#define lib_get_invo_handle LIB$GET_INVO_HANDLE
#endif

Arnaud Charlet committed
830 831 832 833
/* Masks for facility identification. */
#define FAC_MASK  		0x0fff0000
#define DECADA_M_FACILITY	0x00310000

834
/* Define macro symbols for the VMS conditions that become Ada exceptions.
Arnaud Charlet committed
835
   It would be better to just include <ssdef.h> */
836

Arnaud Charlet committed
837
#define SS$_CONTINUE           1
838 839
#define SS$_ACCVIO            12
#define SS$_HPARITH         1284
Arnaud Charlet committed
840
#define SS$_INTDIV          1156
841
#define SS$_STKOVF          1364
Arnaud Charlet committed
842
#define SS$_CONTROLC        1617
843 844
#define SS$_RESIGNAL        2328

Arnaud Charlet committed
845 846 847 848
#define MTH$_FLOOVEMAT   1475268       /* Some ACVC_21 CXA tests */

/* The following codes must be resignalled, and not handled here. */

849
/* These codes are in standard message libraries.  */
Arnaud Charlet committed
850
extern int C$_SIGKILL;
Arnaud Charlet committed
851
extern int C$_SIGINT;
852 853 854 855 856
extern int SS$_DEBUG;
extern int LIB$_KEYNOTFOU;
extern int LIB$_ACTIMAGE;

/* These codes are non standard, which is to say the author is
857
   not sure if they are defined in the standard message libraries
858
   so keep them as macros for now.  */
859 860
#define RDB$_STREAM_EOF 20480426
#define FDL$_UNPRIKW 11829410
Arnaud Charlet committed
861 862
#define CMA$_EXIT_THREAD 4227492

Arnaud Charlet committed
863 864
struct cond_sigargs
{
Arnaud Charlet committed
865 866 867 868
  unsigned int sigarg;
  unsigned int sigargval;
};

Arnaud Charlet committed
869 870
struct cond_subtests
{
Arnaud Charlet committed
871 872 873
  unsigned int num;
  const struct cond_sigargs sigargs[];
};
874

Arnaud Charlet committed
875 876
struct cond_except
{
877
  unsigned int cond;
878
  const struct Exception_Data *except;
Arnaud Charlet committed
879 880
  unsigned int needs_adjust;  /* 1 = adjust PC,  0 = no adjust */
  const struct cond_subtests *subtests;
881 882
};

Arnaud Charlet committed
883 884
struct descriptor_s
{
Arnaud Charlet committed
885 886 887
  unsigned short len, mbz;
  __char_ptr32 adr;
};
888

Richard Kenner committed
889 890
/* Conditions that don't have an Ada exception counterpart must raise
   Non_Ada_Error.  Since this is defined in s-auxdec, it should only be
891 892
   referenced by user programs, not the compiler or tools.  Hence the
   #ifdef IN_RTS.  */
Richard Kenner committed
893 894

#ifdef IN_RTS
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919

#define Status_Error ada__io_exceptions__status_error
extern struct Exception_Data Status_Error;

#define Mode_Error ada__io_exceptions__mode_error
extern struct Exception_Data Mode_Error;

#define Name_Error ada__io_exceptions__name_error
extern struct Exception_Data Name_Error;

#define Use_Error ada__io_exceptions__use_error
extern struct Exception_Data Use_Error;

#define Device_Error ada__io_exceptions__device_error
extern struct Exception_Data Device_Error;

#define End_Error ada__io_exceptions__end_error
extern struct Exception_Data End_Error;

#define Data_Error ada__io_exceptions__data_error
extern struct Exception_Data Data_Error;

#define Layout_Error ada__io_exceptions__layout_error
extern struct Exception_Data Layout_Error;

Richard Kenner committed
920 921 922 923
#define Non_Ada_Error system__aux_dec__non_ada_error
extern struct Exception_Data Non_Ada_Error;

#define Coded_Exception system__vms_exception_table__coded_exception
Arnaud Charlet committed
924
extern struct Exception_Data *Coded_Exception (void *);
Arnaud Charlet committed
925 926

#define Base_Code_In system__vms_exception_table__base_code_in
Arnaud Charlet committed
927
extern void *Base_Code_In (void *);
Richard Kenner committed
928

929
/* DEC Ada exceptions are not defined in a header file, so they
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
   must be declared.  */

#define ADA$_ALREADY_OPEN	0x0031a594
#define ADA$_CONSTRAINT_ERRO	0x00318324
#define ADA$_DATA_ERROR		0x003192c4
#define ADA$_DEVICE_ERROR	0x003195e4
#define ADA$_END_ERROR		0x00319904
#define ADA$_FAC_MODE_MISMAT	0x0031a8b3
#define ADA$_IOSYSFAILED	0x0031af04
#define ADA$_KEYSIZERR		0x0031aa3c
#define ADA$_KEY_MISMATCH	0x0031a8e3
#define ADA$_LAYOUT_ERROR	0x00319c24
#define ADA$_LINEXCMRS		0x0031a8f3
#define ADA$_MAXLINEXC		0x0031a8eb
#define ADA$_MODE_ERROR		0x00319f44
#define ADA$_MRN_MISMATCH	0x0031a8db
#define ADA$_MRS_MISMATCH	0x0031a8d3
#define ADA$_NAME_ERROR		0x0031a264
#define ADA$_NOT_OPEN		0x0031a58c
#define ADA$_ORG_MISMATCH	0x0031a8bb
#define ADA$_PROGRAM_ERROR	0x00318964
#define ADA$_RAT_MISMATCH	0x0031a8cb
#define ADA$_RFM_MISMATCH	0x0031a8c3
#define ADA$_STAOVF		0x00318cac
#define ADA$_STATUS_ERROR	0x0031a584
#define ADA$_STORAGE_ERROR	0x00318c84
#define ADA$_UNSUPPORTED	0x0031a8ab
#define ADA$_USE_ERROR		0x0031a8a4
958

959
/* DEC Ada specific conditions.  */
Arnaud Charlet committed
960 961
static const struct cond_except dec_ada_cond_except_table [] =
{
Arnaud Charlet committed
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988
  {ADA$_PROGRAM_ERROR,   &program_error, 0, 0},
  {ADA$_USE_ERROR,       &Use_Error, 0, 0},
  {ADA$_KEYSIZERR,       &program_error, 0, 0},
  {ADA$_STAOVF,          &storage_error, 0, 0},
  {ADA$_CONSTRAINT_ERRO, &constraint_error, 0, 0},
  {ADA$_IOSYSFAILED,     &Device_Error, 0, 0},
  {ADA$_LAYOUT_ERROR,    &Layout_Error, 0, 0},
  {ADA$_STORAGE_ERROR,   &storage_error, 0, 0},
  {ADA$_DATA_ERROR,      &Data_Error, 0, 0},
  {ADA$_DEVICE_ERROR,    &Device_Error, 0, 0},
  {ADA$_END_ERROR,       &End_Error, 0, 0},
  {ADA$_MODE_ERROR,      &Mode_Error, 0, 0},
  {ADA$_NAME_ERROR,      &Name_Error, 0, 0},
  {ADA$_STATUS_ERROR,    &Status_Error, 0, 0},
  {ADA$_NOT_OPEN,        &Use_Error, 0, 0},
  {ADA$_ALREADY_OPEN,    &Use_Error, 0, 0},
  {ADA$_USE_ERROR,       &Use_Error, 0, 0},
  {ADA$_UNSUPPORTED,     &Use_Error, 0, 0},
  {ADA$_FAC_MODE_MISMAT, &Use_Error, 0, 0},
  {ADA$_ORG_MISMATCH,    &Use_Error, 0, 0},
  {ADA$_RFM_MISMATCH,    &Use_Error, 0, 0},
  {ADA$_RAT_MISMATCH,    &Use_Error, 0, 0},
  {ADA$_MRS_MISMATCH,    &Use_Error, 0, 0},
  {ADA$_MRN_MISMATCH,    &Use_Error, 0, 0},
  {ADA$_KEY_MISMATCH,    &Use_Error, 0, 0},
  {ADA$_MAXLINEXC,       &constraint_error, 0, 0},
  {ADA$_LINEXCMRS,       &constraint_error, 0, 0},
Richard Kenner committed
989

990 991 992
#if 0
   /* Already handled by a pragma Import_Exception
      in Aux_IO_Exceptions */
Arnaud Charlet committed
993 994 995
  {ADA$_LOCK_ERROR,      &Lock_Error, 0, 0},
  {ADA$_EXISTENCE_ERROR, &Existence_Error, 0, 0},
  {ADA$_KEY_ERROR,       &Key_Error, 0, 0},
996
#endif
Richard Kenner committed
997

Arnaud Charlet committed
998
  {0,                    0, 0, 0}
Arnaud Charlet committed
999 1000
};

1001
#endif /* IN_RTS */
Richard Kenner committed
1002

Arnaud Charlet committed
1003 1004 1005 1006 1007 1008
/* Non-DEC Ada specific conditions that map to Ada exceptions.  */

/* Subtest for ACCVIO Constraint_Error, kept for compatibility,
   in hindsight should have just made ACCVIO == Storage_Error.  */
#define ACCVIO_VIRTUAL_ADDR 3
static const struct cond_subtests accvio_c_e =
Arnaud Charlet committed
1009 1010 1011 1012 1013
{1,  /* number of subtests below */
  {
     { ACCVIO_VIRTUAL_ADDR, 0 }
   }
};
Arnaud Charlet committed
1014 1015 1016 1017 1018 1019

/* Macro flag to adjust PC which gets off by one for some conditions,
   not sure if this is reliably true, PC could be off by more for
   HPARITH for example, unless a trapb is inserted. */
#define NEEDS_ADJUST 1

Arnaud Charlet committed
1020 1021
static const struct cond_except system_cond_except_table [] =
{
Arnaud Charlet committed
1022 1023 1024 1025 1026 1027 1028
  {MTH$_FLOOVEMAT, &constraint_error, 0, 0},
  {SS$_INTDIV,     &constraint_error, 0, 0},
  {SS$_HPARITH,    &constraint_error, NEEDS_ADJUST, 0},
  {SS$_ACCVIO,     &constraint_error, NEEDS_ADJUST, &accvio_c_e},
  {SS$_ACCVIO,     &storage_error,    NEEDS_ADJUST, 0},
  {SS$_STKOVF,     &storage_error,    NEEDS_ADJUST, 0},
  {0,               0, 0, 0}
1029
};
Richard Kenner committed
1030

1031 1032 1033 1034 1035 1036
/* To deal with VMS conditions and their mapping to Ada exceptions,
   the __gnat_error_handler routine below is installed as an exception
   vector having precedence over DEC frame handlers.  Some conditions
   still need to be handled by such handlers, however, in which case
   __gnat_error_handler needs to return SS$_RESIGNAL.  Consider for
   instance the use of a third party library compiled with DECAda and
1037
   performing its own exception handling internally.
1038 1039 1040 1041 1042 1043 1044 1045

   To allow some user-level flexibility, which conditions should be
   resignaled is controlled by a predicate function, provided with the
   condition value and returning a boolean indication stating whether
   this condition should be resignaled or not.

   That predicate function is called indirectly, via a function pointer,
   by __gnat_error_handler, and changing that pointer is allowed to the
Ralf Wildenhues committed
1046
   user code by way of the __gnat_set_resignal_predicate interface.
1047 1048 1049 1050 1051 1052 1053 1054 1055

   The user level function may then implement what it likes, including
   for instance the maintenance of a dynamic data structure if the set
   of to be resignalled conditions has to change over the program's
   lifetime.

   ??? This is not a perfect solution to deal with the possible
   interactions between the GNAT and the DECAda exception handling
   models and better (more general) schemes are studied.  This is so
1056
   just provided as a convenient workaround in the meantime, and
1057 1058 1059
   should be use with caution since the implementation has been kept
   very simple.  */

Arnaud Charlet committed
1060
typedef int resignal_predicate (int code);
1061

Arnaud Charlet committed
1062 1063
static const int * const cond_resignal_table [] =
{
Arnaud Charlet committed
1064
  &C$_SIGKILL,
1065
  (int *)CMA$_EXIT_THREAD,
1066 1067 1068 1069 1070 1071 1072 1073
  &SS$_DEBUG,
  &LIB$_KEYNOTFOU,
  &LIB$_ACTIMAGE,
  (int *) RDB$_STREAM_EOF,
  (int *) FDL$_UNPRIKW,
  0
};

Arnaud Charlet committed
1074 1075
static const int facility_resignal_table [] =
{
1076 1077 1078 1079 1080
  0x1380000, /* RDB */
  0x2220000, /* SQL */
  0
};

1081 1082 1083 1084 1085
/* Default GNAT predicate for resignaling conditions.  */

static int
__gnat_default_resignal_p (int code)
{
1086 1087
  int i, iexcept;

1088
  for (i = 0; facility_resignal_table [i]; i++)
Arnaud Charlet committed
1089
    if ((code & FAC_MASK) == facility_resignal_table [i])
1090 1091
      return 1;

1092
  for (i = 0, iexcept = 0;
1093
       cond_resignal_table [i]
Arnaud Charlet committed
1094
	&& !(iexcept = LIB$MATCH_COND (&code, &cond_resignal_table [i]));
1095 1096 1097
       i++);

  return iexcept;
1098 1099 1100 1101 1102
}

/* Static pointer to predicate that the __gnat_error_handler exception
   vector invokes to determine if it should resignal a condition.  */

Arnaud Charlet committed
1103
static resignal_predicate *__gnat_resignal_p = __gnat_default_resignal_p;
1104 1105 1106 1107 1108

/* User interface to change the predicate pointer to PREDICATE. Reset to
   the default if PREDICATE is null.  */

void
Arnaud Charlet committed
1109
__gnat_set_resignal_predicate (resignal_predicate *predicate)
1110
{
Arnaud Charlet committed
1111
  if (predicate == NULL)
1112 1113 1114 1115 1116
    __gnat_resignal_p = __gnat_default_resignal_p;
  else
    __gnat_resignal_p = predicate;
}

1117
/* Should match System.Parameters.Default_Exception_Msg_Max_Length.  */
1118 1119
#define Default_Exception_Msg_Max_Length 512

1120 1121 1122
/* Action routine for SYS$PUTMSG. There may be multiple
   conditions, each with text to be appended to MESSAGE
   and separated by line termination.  */
1123
static int
Arnaud Charlet committed
1124
copy_msg (struct descriptor_s *msgdesc, char *message)
1125 1126 1127 1128
{
  int len = strlen (message);
  int copy_len;

1129
  /* Check for buffer overflow and skip.  */
1130 1131 1132 1133 1134 1135
  if (len > 0 && len <= Default_Exception_Msg_Max_Length - 3)
    {
      strcat (message, "\r\n");
      len += 2;
    }

1136
  /* Check for buffer overflow and truncate if necessary.  */
1137 1138
  copy_len = (len + msgdesc->len <= Default_Exception_Msg_Max_Length - 1 ?
	      msgdesc->len :
1139
	      Default_Exception_Msg_Max_Length - 1 - len);
1140 1141 1142 1143 1144 1145
  strncpy (&message [len], msgdesc->adr, copy_len);
  message [len + copy_len] = 0;

  return 0;
}

Arnaud Charlet committed
1146 1147 1148
/* Scan TABLE for a match for the condition contained in SIGARGS,
   and return the entry, or the empty entry if no match found.  */
static const struct cond_except *
Arnaud Charlet committed
1149
scan_conditions ( int *sigargs, const struct cond_except *table [])
Arnaud Charlet committed
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
{
  int i;
  struct cond_except entry;

  /* Scan the exception condition table for a match and fetch
     the associated GNAT exception pointer.  */
  for (i = 0; (*table) [i].cond; i++)
    {
      unsigned int match = LIB$MATCH_COND (&sigargs [1], &(*table) [i].cond);
      const struct cond_subtests *subtests  = (*table) [i].subtests;

      if (match)
	{
	  if (!subtests)
	    {
	      return &(*table) [i];
	    }
	  else
	    {
	      unsigned int ii;
	      int num = (*subtests).num;

	      /* Perform subtests to differentiate exception.  */
	      for (ii = 0; ii < num; ii++)
		{
		  unsigned int arg = (*subtests).sigargs [ii].sigarg;
		  unsigned int argval = (*subtests).sigargs [ii].sigargval;

		  if (sigargs [arg] != argval)
		    {
		      num = 0;
		      break;
		    }
		}

	      /* All subtests passed.  */
	      if (num == (*subtests).num)
	        return &(*table) [i];
	    }
	}
    }

    /* No match, return the null terminating entry.  */
    return &(*table) [i];
}

Arnaud Charlet committed
1196 1197
/* __gnat_handle_vms_condtition is both a frame based handler
   for the runtime, and an exception vector for the compiler.  */
1198
long
1199
__gnat_handle_vms_condition (int *sigargs, void *mechargs)
Richard Kenner committed
1200 1201
{
  struct Exception_Data *exception = 0;
Arnaud Charlet committed
1202
  unsigned int needs_adjust = 0;
Arnaud Charlet committed
1203
  void *base_code;
Arnaud Charlet committed
1204
  struct descriptor_s gnat_facility = {4, 0, "GNAT"};
1205
  char message [Default_Exception_Msg_Max_Length];
Arnaud Charlet committed
1206

1207
  const char *msg = "";
Richard Kenner committed
1208

1209 1210 1211 1212
  /* Check for conditions to resignal which aren't effected by pragma
     Import_Exception.  */
  if (__gnat_resignal_p (sigargs [1]))
    return SS$_RESIGNAL;
Arnaud Charlet committed
1213 1214 1215 1216 1217
#ifndef IN_RTS
  /* toplev.c handles this for compiler.  */
  if (sigargs [1] == SS$_HPARITH)
    return SS$_RESIGNAL;
#endif
Richard Kenner committed
1218 1219

#ifdef IN_RTS
1220
  /* See if it's an imported exception.  Beware that registered exceptions
Arnaud Charlet committed
1221
     are bound to their base code, with the severity bits masked off.  */
Arnaud Charlet committed
1222
  base_code = Base_Code_In ((void *) sigargs[1]);
Arnaud Charlet committed
1223
  exception = Coded_Exception (base_code);
Richard Kenner committed
1224 1225 1226
#endif

  if (exception == 0)
1227
#ifdef IN_RTS
Arnaud Charlet committed
1228 1229 1230 1231 1232 1233 1234
    {
      int i;
      struct cond_except cond;
      const struct cond_except *cond_table;
      const struct cond_except *cond_tables [] = {dec_ada_cond_except_table,
					          system_cond_except_table,
					          0};
Arnaud Charlet committed
1235
      unsigned int ctrlc = SS$_CONTROLC;
Arnaud Charlet committed
1236
      unsigned int *sigint = &C$_SIGINT;
Arnaud Charlet committed
1237
      int ctrlc_match = LIB$MATCH_COND (&sigargs [1], &ctrlc);
Arnaud Charlet committed
1238
      int sigint_match = LIB$MATCH_COND (&sigargs [1], &sigint);
Arnaud Charlet committed
1239 1240 1241 1242 1243

      extern int SYS$DCLAST (void (*astadr)(), unsigned long long astprm,
	                     unsigned int acmode);

      /* If SS$_CONTROLC has been imported as an exception, it will take
1244
	 priority over a Ctrl/C handler.  See above.  SIGINT has a
Arnaud Charlet committed
1245 1246 1247
	 different condition value due to it's DECCCRTL roots and it's
	 the condition that gets raised for a "kill -INT".  */
      if ((ctrlc_match || sigint_match) && __gnat_ctrl_c_handler)
Arnaud Charlet committed
1248 1249 1250 1251
	{
	  SYS$DCLAST (__gnat_ctrl_c_handler, 0, 0);
	  return SS$_CONTINUE;
	}
Arnaud Charlet committed
1252 1253 1254

      i = 0;
      while ((cond_table = cond_tables[i++]) && !exception)
1255
	{
Arnaud Charlet committed
1256 1257
	  cond = *scan_conditions (sigargs, &cond_table);
	  exception = (struct Exception_Data *) cond.except;
1258
	}
Arnaud Charlet committed
1259 1260 1261 1262 1263 1264 1265 1266

      if (exception)
	needs_adjust = cond.needs_adjust;
      else
	/* User programs expect Non_Ada_Error to be raised if no match,
	   reference DEC Ada test CXCONDHAN.  */
	exception = &Non_Ada_Error;
      }
Richard Kenner committed
1267
#else
Arnaud Charlet committed
1268 1269 1270 1271
    {
      /* Pretty much everything is just a program error in the compiler */
      exception = &program_error;
    }
Richard Kenner committed
1272
#endif
Arnaud Charlet committed
1273 1274 1275 1276

  message[0] = 0;
  /* Subtract PC & PSL fields as per ABI for SYS$PUTMSG.  */
  sigargs[0] -= 2;
Arnaud Charlet committed
1277

Arnaud Charlet committed
1278 1279
  extern int SYS$PUTMSG (void *, int (*)(), void *, unsigned long long);

Arnaud Charlet committed
1280 1281
  /* If it was a DEC Ada specific condtiion, make it GNAT otherwise
     keep the old facility.  */
1282
  if ((sigargs [1] & FAC_MASK) == DECADA_M_FACILITY)
Arnaud Charlet committed
1283 1284
    SYS$PUTMSG (sigargs, copy_msg, &gnat_facility,
	        (unsigned long long ) message);
Arnaud Charlet committed
1285
  else
Arnaud Charlet committed
1286 1287
    SYS$PUTMSG (sigargs, copy_msg, 0,
	        (unsigned long long ) message);
Arnaud Charlet committed
1288

Arnaud Charlet committed
1289 1290 1291 1292 1293 1294
  /* Add back PC & PSL fields as per ABI for SYS$PUTMSG.  */
  sigargs[0] += 2;
  msg = message;

  if (needs_adjust)
    __gnat_adjust_context_for_raise (sigargs [1], (void *)mechargs);
Richard Kenner committed
1295

1296
  Raise_From_Signal_Handler (exception, msg);
1297 1298
}

Arnaud Charlet committed
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
#if defined (IN_RTS) && defined (__IA64)
/* Called only from adasigio.b32.  This is a band aid to avoid going
   through the VMS signal handling code which results in a 0x8000 per
   handled exception memory leak in P2 space (see VMS source listing
   sys/lis/exception.lis) due to the allocation of working space that
   is expected to be deallocated upon return from the condition handler,
   which doesn't return in GNAT compiled code.  */
void
GNAT$STOP (int *sigargs)
{
   /* Note that there are no mechargs. We rely on the fact that condtions
Arnaud Charlet committed
1310 1311 1312 1313
      raised from DEClib I/O do not require an "adjust".  Also the count
      will be off by 2, since LIB$STOP didn't get a chance to add the
      PC and PSL fields, so we bump it so PUTMSG comes out right.  */
   sigargs [0] += 2;
Arnaud Charlet committed
1314 1315 1316 1317
   __gnat_handle_vms_condition (sigargs, 0);
}
#endif

Richard Kenner committed
1318
void
R. Kelley Cook committed
1319
__gnat_install_handler (void)
Richard Kenner committed
1320
{
1321
  long prvhnd ATTRIBUTE_UNUSED;
Richard Kenner committed
1322

1323
#if !defined (IN_RTS)
Arnaud Charlet committed
1324 1325
  extern int SYS$SETEXV (unsigned int vector, int (*addres)(),
	                 unsigned int accmode, void *(*(prvhnd)));
Arnaud Charlet committed
1326
  SYS$SETEXV (1, __gnat_handle_vms_condition, 3, &prvhnd);
1327 1328
#endif

1329
  __gnat_handler_installed = 1;
Richard Kenner committed
1330 1331
}

1332
/* __gnat_adjust_context_for_raise for Alpha - see comments along with the
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
   default version later in this file.  */

#if defined (IN_RTS) && defined (__alpha__)

#include <vms/chfctxdef.h>
#include <vms/chfdef.h>

#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE

void
__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
{
Arnaud Charlet committed
1345 1346 1347
  if (signo == SS$_HPARITH)
    {
      /* Sub one to the address of the instruction signaling the condition,
Arnaud Charlet committed
1348
	 located in the sigargs array.  */
1349

Arnaud Charlet committed
1350 1351
      CHF$MECH_ARRAY * mechargs = (CHF$MECH_ARRAY *) ucontext;
      CHF$SIGNAL_ARRAY * sigargs
Arnaud Charlet committed
1352
	= (CHF$SIGNAL_ARRAY *) mechargs->chf$q_mch_sig_addr;
1353

Arnaud Charlet committed
1354 1355
      int vcount = sigargs->chf$is_sig_args;
      int * pc_slot = & (&sigargs->chf$l_sig_name)[vcount-2];
1356

Arnaud Charlet committed
1357 1358
      (*pc_slot)--;
    }
1359 1360 1361 1362
}

#endif

1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394
/* __gnat_adjust_context_for_raise for ia64.  */

#if defined (IN_RTS) && defined (__IA64)

#include <vms/chfctxdef.h>
#include <vms/chfdef.h>

#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE

typedef unsigned long long u64;

void
__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
{
  /* Add one to the address of the instruction signaling the condition,
     located in the 64bits sigargs array.  */

  CHF$MECH_ARRAY * mechargs = (CHF$MECH_ARRAY *) ucontext;

  CHF64$SIGNAL_ARRAY *chfsig64
    = (CHF64$SIGNAL_ARRAY *) mechargs->chf$ph_mch_sig64_addr;

  u64 * post_sigarray
    = (u64 *)chfsig64 + 1 + chfsig64->chf64$l_sig_args;

  u64 * ih_pc_loc = post_sigarray - 2;

  (*ih_pc_loc) ++;
}

#endif

Arnaud Charlet committed
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
/* Easier interface for LIB$GET_LOGICAL: put the equivalence of NAME into BUF,
   always NUL terminated.  In case of error or if the result is longer than
   LEN (length of BUF) an empty string is written info BUF.  */

static void
__gnat_vms_get_logical (const char *name, char *buf, int len)
{
  struct descriptor_s name_desc, result_desc;
  int status;
  unsigned short rlen;

  /* Build the descriptor for NAME.  */
  name_desc.len = strlen (name);
  name_desc.mbz = 0;
  name_desc.adr = (char *)name;

  /* Build the descriptor for the result.  */
  result_desc.len = len;
  result_desc.mbz = 0;
  result_desc.adr = buf;

  status = LIB$GET_LOGICAL (&name_desc, &result_desc, &rlen);

  if ((status & 1) == 1 && rlen < len)
    buf[rlen] = 0;
  else
    buf[0] = 0;
}

/* Size of a page on ia64 and alpha VMS.  */
#define VMS_PAGESIZE 8192

/* User mode.  */
#define PSL__C_USER 3

/* No access.  */
#define PRT__C_NA 0

/* Descending region.  */
#define VA__M_DESCEND 1

/* Get by virtual address.  */
#define VA___REGSUM_BY_VA 1

/* Memory region summary.  */
struct regsum
{
  unsigned long long q_region_id;
  unsigned int l_flags;
  unsigned int l_region_protection;
  void *pq_start_va;
  unsigned long long q_region_size;
  void *pq_first_free_va;
};

extern int SYS$GET_REGION_INFO (unsigned int, unsigned long long *,
Arnaud Charlet committed
1451 1452
	                        void *, void *, unsigned int,
	                        void *, unsigned int *);
Arnaud Charlet committed
1453
extern int SYS$EXPREG_64 (unsigned long long *, unsigned long long,
Arnaud Charlet committed
1454 1455
	                  unsigned int, unsigned int, void **,
	                  unsigned long long *);
Arnaud Charlet committed
1456
extern int SYS$SETPRT_64 (void *, unsigned long long, unsigned int,
Arnaud Charlet committed
1457 1458
	                  unsigned int, void **, unsigned long long *,
	                  unsigned int *);
Arnaud Charlet committed
1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483

/* Add a guard page in the memory region containing ADDR at ADDR +/- SIZE.
   (The sign depends on the kind of the memory region).  */

static int
__gnat_set_stack_guard_page (void *addr, unsigned long size)
{
  int status;
  void *ret_va;
  unsigned long long ret_len;
  unsigned int ret_prot;
  void *start_va;
  unsigned long long length;
  unsigned int retlen;
  struct regsum buffer;

  /* Get the region for ADDR.  */
  status = SYS$GET_REGION_INFO
    (VA___REGSUM_BY_VA, NULL, addr, NULL, sizeof (buffer), &buffer, &retlen);

  if ((status & 1) != 1)
    return -1;

  /* Extend the region.  */
  status = SYS$EXPREG_64 (&buffer.q_region_id,
Arnaud Charlet committed
1484
	                  size, 0, 0, &start_va, &length);
Arnaud Charlet committed
1485 1486 1487 1488 1489 1490 1491 1492 1493

  if ((status & 1) != 1)
    return -1;

  /* Create a guard page.  */
  if (!(buffer.l_flags & VA__M_DESCEND))
    start_va = (void *)((unsigned long long)start_va + length - VMS_PAGESIZE);

  status = SYS$SETPRT_64 (start_va, VMS_PAGESIZE, PSL__C_USER, PRT__C_NA,
Arnaud Charlet committed
1494
	                  &ret_va, &ret_len, &ret_prot);
Arnaud Charlet committed
1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531

  if ((status & 1) != 1)
    return -1;
  return 0;
}

/* Read logicals to limit the stack(s) size.  */

static void
__gnat_set_stack_limit (void)
{
#ifdef __ia64__
  void *sp;
  unsigned long size;
  char value[16];
  char *e;

  /* The main stack.  */
  __gnat_vms_get_logical ("GNAT_STACK_SIZE", value, sizeof (value));
  size = strtoul (value, &e, 0);
  if (e > value && *e == 0)
    {
      asm ("mov %0=sp" : "=r" (sp));
      __gnat_set_stack_guard_page (sp, size * 1024);
    }

  /* The register stack.  */
  __gnat_vms_get_logical ("GNAT_RBS_SIZE", value, sizeof (value));
  size = strtoul (value, &e, 0);
  if (e > value && *e == 0)
    {
      asm ("mov %0=ar.bsp" : "=r" (sp));
      __gnat_set_stack_guard_page (sp, size * 1024);
    }
#endif
}

Arnaud Charlet committed
1532 1533 1534 1535 1536 1537 1538 1539
#ifdef IN_RTS
extern int SYS$IEEE_SET_FP_CONTROL (void *, void *, void *);
#define K_TRUE 1
#define __int64 long long
#define __NEW_STARLET
#include <vms/ieeedef.h>
#endif

Arnaud Charlet committed
1540 1541 1542 1543
/* Feature logical name and global variable address pair.
   If we ever add another feature logical to this list, the
   feature struct will need to be enhanced to take into account
   possible values for *gl_addr.  */
Arnaud Charlet committed
1544
struct feature {
Arnaud Charlet committed
1545
  const char *name;
Arnaud Charlet committed
1546 1547
  int *gl_addr;
};
1548

Arnaud Charlet committed
1549
/* Default values for GNAT features set by environment or binder.  */
Arnaud Charlet committed
1550
int __gl_heap_size = 64;
1551

Arnaud Charlet committed
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
/* Default float format is 'I' meaning IEEE.  If gnatbind detetcts that a
   VAX Float format is specified, it will set this global variable to 'V'.
   Subsequently __gnat_set_features will test the variable and if set for
   VAX Float will call a Starlet function to enable trapping for invalid
   operation, drivide by zero, and overflow. This will prevent the VMS runtime
   (specifically OTS$CHECK_FP_MODE) from complaining about inconsistent
   floating point settings in a mixed language program. Ideally the setting
   would be determined at link time based on setttings in the object files,
   however the VMS linker seems to take the setting from the first object
   in the link, e.g. pcrt0.o which is float representation neutral.  */
char __gl_float_format = 'I';

Arnaud Charlet committed
1564
/* Array feature logical names and global variable addresses.  */
Arnaud Charlet committed
1565 1566
static const struct feature features[] =
{
Arnaud Charlet committed
1567
  {"GNAT$NO_MALLOC_64", &__gl_heap_size},
1568 1569 1570
  {0, 0}
};

Arnaud Charlet committed
1571 1572
void
__gnat_set_features (void)
1573
{
Arnaud Charlet committed
1574 1575
  int i;
  char buff[16];
Arnaud Charlet committed
1576 1577 1578 1579 1580 1581
#ifdef IN_RTS
  IEEE clrmsk, setmsk, prvmsk;

  clrmsk.ieee$q_flags = 0LL;
  setmsk.ieee$q_flags = 0LL;
#endif
1582

Arnaud Charlet committed
1583
  /* Loop through features array and test name for enable/disable.  */
Arnaud Charlet committed
1584
  for (i = 0; features[i].name; i++)
1585
    {
Arnaud Charlet committed
1586 1587 1588
      __gnat_vms_get_logical (features[i].name, buff, sizeof (buff));

      if (strcmp (buff, "ENABLE") == 0
Arnaud Charlet committed
1589 1590 1591
	  || strcmp (buff, "TRUE") == 0
	  || strcmp (buff, "1") == 0)
	*features[i].gl_addr = 32;
Arnaud Charlet committed
1592
      else if (strcmp (buff, "DISABLE") == 0
Arnaud Charlet committed
1593 1594 1595
	       || strcmp (buff, "FALSE") == 0
	       || strcmp (buff, "0") == 0)
	*features[i].gl_addr = 64;
1596 1597
    }

Arnaud Charlet committed
1598 1599 1600
  /* Features to artificially limit the stack size.  */
  __gnat_set_stack_limit ();

Arnaud Charlet committed
1601 1602 1603 1604 1605 1606 1607 1608 1609 1610
#ifdef IN_RTS
  if (__gl_float_format == 'V')
    {
      setmsk.ieee$v_trap_enable_inv = K_TRUE;
      setmsk.ieee$v_trap_enable_dze = K_TRUE;
      setmsk.ieee$v_trap_enable_ovf = K_TRUE;
      SYS$IEEE_SET_FP_CONTROL (&clrmsk, &setmsk, &prvmsk);
    }
#endif

Arnaud Charlet committed
1611
  __gnat_features_set = 1;
1612 1613
}

Arnaud Charlet committed
1614 1615
/* Return true if the VMS version is 7.x.  */

Arnaud Charlet committed
1616 1617
extern unsigned int LIB$GETSYI (int *, ...);

Arnaud Charlet committed
1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631
#define SYI$_VERSION 0x1000

int
__gnat_is_vms_v7 (void)
{
  struct descriptor_s desc;
  char version[8];
  int status;
  int code = SYI$_VERSION;

  desc.len = sizeof (version);
  desc.mbz = 0;
  desc.adr = version;

Arnaud Charlet committed
1632
  status = LIB$GETSYI (&code, 0, &desc);
Arnaud Charlet committed
1633 1634 1635 1636 1637 1638
  if ((status & 1) == 1 && version[1] == '7' && version[2] == '.')
    return 1;
  else
    return 0;
}

1639 1640 1641
/*******************/
/* FreeBSD Section */
/*******************/
Arnaud Charlet committed
1642

1643
#elif defined (__FreeBSD__) || defined (__DragonFly__)
Arnaud Charlet committed
1644 1645

#include <signal.h>
1646
#include <sys/ucontext.h>
Arnaud Charlet committed
1647 1648 1649
#include <unistd.h>

static void
Arnaud Charlet committed
1650 1651 1652
__gnat_error_handler (int sig,
		      siginfo_t *si ATTRIBUTE_UNUSED,
		      void *ucontext ATTRIBUTE_UNUSED)
Arnaud Charlet committed
1653 1654
{
  struct Exception_Data *exception;
1655
  const char *msg;
Arnaud Charlet committed
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674

  switch (sig)
    {
    case SIGFPE:
      exception = &constraint_error;
      msg = "SIGFPE";
      break;

    case SIGILL:
      exception = &constraint_error;
      msg = "SIGILL";
      break;

    case SIGSEGV:
      exception = &storage_error;
      msg = "stack overflow or erroneous memory access";
      break;

    case SIGBUS:
Arnaud Charlet committed
1675 1676
      exception = &storage_error;
      msg = "SIGBUS: possible stack overflow";
Arnaud Charlet committed
1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687
      break;

    default:
      exception = &program_error;
      msg = "unhandled signal";
    }

  Raise_From_Signal_Handler (exception, msg);
}

void
1688
__gnat_install_handler (void)
Arnaud Charlet committed
1689 1690 1691 1692 1693
{
  struct sigaction act;

  /* Set up signal handler to map synchronous signals to appropriate
     exceptions.  Make sure that the handler isn't interrupted by another
1694
     signal that might cause a scheduling event!  */
Arnaud Charlet committed
1695

1696 1697
  act.sa_sigaction
    = (void (*)(int, struct __siginfo *, void*)) __gnat_error_handler;
1698
  act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
Arnaud Charlet committed
1699 1700 1701 1702 1703 1704 1705
  (void) sigemptyset (&act.sa_mask);

  (void) sigaction (SIGILL,  &act, NULL);
  (void) sigaction (SIGFPE,  &act, NULL);
  (void) sigaction (SIGSEGV, &act, NULL);
  (void) sigaction (SIGBUS,  &act, NULL);

1706
  __gnat_handler_installed = 1;
Arnaud Charlet committed
1707 1708
}

Arnaud Charlet committed
1709 1710 1711
/*************************************/
/* VxWorks Section (including Vx653) */
/*************************************/
Richard Kenner committed
1712 1713 1714 1715 1716

#elif defined(__vxworks)

#include <signal.h>
#include <taskLib.h>
Arnaud Charlet committed
1717
#if (defined (__i386__) || defined (__x86_64__)) && !defined (VTHREADS)
Arnaud Charlet committed
1718
#include <sysLib.h>
Arnaud Charlet committed
1719
#endif
1720

Arnaud Charlet committed
1721 1722
#include "sigtramp.h"

Arnaud Charlet committed
1723
#ifndef __RTP__
Richard Kenner committed
1724 1725
#include <intLib.h>
#include <iv.h>
1726
#endif
Richard Kenner committed
1727

Arnaud Charlet committed
1728 1729
#if ((defined (ARMEL) && (_WRS_VXWORKS_MAJOR == 6)) || defined (__x86_64__)) && !defined(__RTP__)
#define VXWORKS_FORCE_GUARD_PAGE 1
Arnaud Charlet committed
1730
#include <vmLib.h>
Arnaud Charlet committed
1731 1732
extern size_t vxIntStackOverflowSize;
#define INT_OVERFLOW_SIZE vxIntStackOverflowSize
Arnaud Charlet committed
1733 1734
#endif

1735 1736 1737 1738
#ifdef VTHREADS
#include "private/vThreadsP.h"
#endif

1739 1740
#ifndef __RTP__

1741
/* Directly vectored Interrupt routines are not supported when using RTPs.  */
1742

Arnaud Charlet committed
1743
extern void * __gnat_inum_to_ivec (int);
1744

1745
/* This is needed by the GNAT run time to handle Vxworks interrupts.  */
Arnaud Charlet committed
1746
void *
1747 1748
__gnat_inum_to_ivec (int num)
{
Arnaud Charlet committed
1749
  return (void *) INUM_TO_IVEC (num);
1750 1751 1752
}
#endif

Arnaud Charlet committed
1753
#if !defined(__alpha_vxworks) && ((_WRS_VXWORKS_MAJOR != 6) && (_WRS_VXWORKS_MAJOR != 7)) && !defined(__RTP__)
Richard Kenner committed
1754 1755

/* getpid is used by s-parint.adb, but is not defined by VxWorks, except
1756
   on Alpha VxWorks and VxWorks 6.x (including RTPs).  */
Richard Kenner committed
1757

R. Kelley Cook committed
1758
extern long getpid (void);
Richard Kenner committed
1759 1760

long
R. Kelley Cook committed
1761
getpid (void)
Richard Kenner committed
1762 1763 1764 1765 1766
{
  return taskIdSelf ();
}
#endif

Arnaud Charlet committed
1767 1768 1769 1770 1771 1772
/* When stack checking is performed by probing a guard page on the stack,
   sometimes this guard page is not properly reset on VxWorks. We need to
   manually reset it in this case.
   This function returns TRUE in case the guard page was hit by the
   signal. */
static int
1773
__gnat_reset_guard_page (int sig)
Arnaud Charlet committed
1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791
{
  /* On ARM VxWorks 6.x and x86_64 VxWorks 7, the guard page is left un-armed
     by the kernel after being violated, so subsequent violations aren't
     detected.
     So we retrieve the address of the guard page from the TCB and compare it
     with the page that is violated and re-arm that page if there's a match. */
#if defined (VXWORKS_FORCE_GUARD_PAGE)

  /* Ignore signals that are not stack overflow signals */
  if (sig != SIGSEGV && sig != SIGBUS && sig != SIGILL) return FALSE;

  /* If the target does not support guard pages, INT_OVERFLOW_SIZE will be 0 */
  if (INT_OVERFLOW_SIZE == 0) return FALSE;

  TASK_ID tid           = taskIdSelf ();
  WIND_TCB *pTcb        = taskTcb (tid);
  VIRT_ADDR guardPage   = (VIRT_ADDR) pTcb->pStackEnd - INT_OVERFLOW_SIZE;
  UINT stateMask        = VM_STATE_MASK_VALID;
1792
  UINT guardState       = VM_STATE_VALID_NOT;
Arnaud Charlet committed
1793

1794 1795 1796
#if (_WRS_VXWORKS_MAJOR >= 7)
  stateMask  |= MMU_ATTR_SPL_MSK;
  guardState |= MMU_ATTR_NO_BLOCK;
Arnaud Charlet committed
1797 1798
#endif

1799 1800 1801
  UINT nState;
  vmStateGet (NULL, guardPage, &nState);
  if ((nState & VM_STATE_MASK_VALID) != VM_STATE_VALID_NOT)
Arnaud Charlet committed
1802
    {
1803 1804 1805
      /* If the guard page has a valid state, we need to reset to
         invalid state here */
      vmStateSet (NULL, guardPage, INT_OVERFLOW_SIZE, stateMask, guardState);
Arnaud Charlet committed
1806 1807 1808 1809 1810 1811
      return TRUE;
    }
#endif /* VXWORKS_FORCE_GUARD_PAGE */
  return FALSE;
}

1812 1813 1814
/* VxWorks 653 vThreads expects the field excCnt to be zeroed when a signal is.
   handled. The VxWorks version of longjmp does this; GCC's builtin_longjmp
   doesn't.  */
1815 1816 1817 1818
void
__gnat_clear_exception_count (void)
{
#ifdef VTHREADS
1819 1820 1821
  WIND_TCB *currentTask = (WIND_TCB *) taskIdSelf();

  currentTask->vThreads.excCnt = 0;
1822 1823 1824
#endif
}

1825
/* Handle different SIGnal to exception mappings in different VxWorks
Arnaud Charlet committed
1826 1827
   versions.  */
void
Arnaud Charlet committed
1828 1829 1830
__gnat_map_signal (int sig,
                   siginfo_t *si ATTRIBUTE_UNUSED,
                   void *sc ATTRIBUTE_UNUSED)
Richard Kenner committed
1831 1832
{
  struct Exception_Data *exception;
1833
  const char *msg;
Richard Kenner committed
1834 1835 1836 1837 1838 1839 1840

  switch (sig)
    {
    case SIGFPE:
      exception = &constraint_error;
      msg = "SIGFPE";
      break;
1841
#ifdef VTHREADS
Arnaud Charlet committed
1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855
#ifdef __VXWORKSMILS__
    case SIGILL:
      exception = &storage_error;
      msg = "SIGILL: possible stack overflow";
      break;
    case SIGSEGV:
      exception = &storage_error;
      msg = "SIGSEGV";
      break;
    case SIGBUS:
      exception = &program_error;
      msg = "SIGBUS";
      break;
#else
Richard Kenner committed
1856 1857
    case SIGILL:
      exception = &constraint_error;
1858
      msg = "Floating point exception or SIGILL";
Richard Kenner committed
1859 1860
      break;
    case SIGSEGV:
1861
      exception = &storage_error;
Arnaud Charlet committed
1862
      msg = "SIGSEGV";
Richard Kenner committed
1863 1864
      break;
    case SIGBUS:
Arnaud Charlet committed
1865 1866
      exception = &storage_error;
      msg = "SIGBUS: possible stack overflow";
1867
      break;
Arnaud Charlet committed
1868
#endif
Arnaud Charlet committed
1869
#elif (_WRS_VXWORKS_MAJOR >= 6)
1870 1871 1872 1873
    case SIGILL:
      exception = &constraint_error;
      msg = "SIGILL";
      break;
1874 1875 1876
#ifdef __RTP__
    /* In RTP mode a SIGSEGV is most likely due to a stack overflow,
       since stack checking uses the probing mechanism.  */
1877 1878 1879 1880
    case SIGSEGV:
      exception = &storage_error;
      msg = "SIGSEGV: possible stack overflow";
      break;
1881 1882 1883 1884
    case SIGBUS:
      exception = &program_error;
      msg = "SIGBUS";
      break;
1885
#else
1886 1887
      /* VxWorks 6 kernel mode with probing. SIGBUS for guard page hit */
    case SIGSEGV:
Arnaud Charlet committed
1888
      exception = &storage_error;
1889 1890 1891 1892 1893 1894 1895 1896 1897
      msg = "SIGSEGV";
      break;
    case SIGBUS:
      exception = &storage_error;
      msg = "SIGBUS: possible stack overflow";
      break;
#endif
#else
    /* VxWorks 5: a SIGILL is most likely due to a stack overflow,
1898 1899 1900 1901 1902
       since stack checking uses the stack limit mechanism.  */
    case SIGILL:
      exception = &storage_error;
      msg = "SIGILL: possible stack overflow";
      break;
1903
    case SIGSEGV:
Arnaud Charlet committed
1904
      exception = &storage_error;
1905 1906 1907
      msg = "SIGSEGV";
      break;
    case SIGBUS:
Richard Kenner committed
1908 1909 1910
      exception = &program_error;
      msg = "SIGBUS";
      break;
1911
#endif
Richard Kenner committed
1912 1913 1914 1915 1916
    default:
      exception = &program_error;
      msg = "unhandled signal";
    }

1917
  if (__gnat_reset_guard_page (sig))
Arnaud Charlet committed
1918
    {
Arnaud Charlet committed
1919 1920 1921
      /* Set the exception message: we know for sure that we have a
         stack overflow here */
      exception = &storage_error;
Arnaud Charlet committed
1922

Arnaud Charlet committed
1923
      switch (sig)
Arnaud Charlet committed
1924
        {
Arnaud Charlet committed
1925 1926 1927 1928 1929 1930 1931 1932 1933 1934
        case SIGSEGV:
          msg = "SIGSEGV: stack overflow";
          break;
        case SIGBUS:
          msg = "SIGBUS: stack overflow";
          break;
        case SIGILL:
          msg = "SIGILL: stack overflow";
          break;
        }
Arnaud Charlet committed
1935
    }
1936
  __gnat_clear_exception_count ();
Richard Kenner committed
1937 1938 1939
  Raise_From_Signal_Handler (exception, msg);
}

1940
#if defined (ARMEL) && (_WRS_VXWORKS_MAJOR >= 7) && !defined (__aarch64__)
Arnaud Charlet committed
1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958

/* ARM-vx7 case with arm unwinding exceptions */
#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE

#include <arch/../regs.h>
#ifndef __RTP__
#include <sigLib.h>
#else
#include <signal.h>
#include <regs.h>
#include <ucontext.h>
#endif /* __RTP__ */

void
__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED,
				 void *sc ATTRIBUTE_UNUSED)
{
  /* In case of ARM exceptions, the registers context have the PC pointing
Arnaud Charlet committed
1959 1960 1961
     to the instruction that raised the signal.  However the unwinder expects
     the instruction to be in the range ]PC,PC+1].  */
  uintptr_t *pc_addr;
Arnaud Charlet committed
1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973
#ifdef __RTP__
  mcontext_t *mcontext = &((ucontext_t *) sc)->uc_mcontext;
  pc_addr = (uintptr_t*)&mcontext->regs.pc;
#else
  struct sigcontext * sctx = (struct sigcontext *) sc;
  pc_addr = (uintptr_t*)&sctx->sc_pregs->pc;
#endif
  /* ARM Bump has to be an even number because of odd/even architecture.  */
  *pc_addr += 2;
}
#endif /* ARMEL && _WRS_VXWORKS_MAJOR >= 7 */

1974 1975 1976
/* Tasking and Non-tasking signal handler.  Map SIGnal to Ada exception
   propagation after the required low level adjustments.  */

Arnaud Charlet committed
1977 1978
static void
__gnat_error_handler (int sig, siginfo_t *si, void *sc)
Arnaud Charlet committed
1979
{
Arnaud Charlet committed
1980
  sigset_t mask;
Arnaud Charlet committed
1981

Arnaud Charlet committed
1982
  /* VxWorks on e500v2 clears the SPE bit of the MSR when entering CPU
Arnaud Charlet committed
1983 1984
     exception state. To allow the handler and exception to work properly
     when they contain SPE instructions, we need to set it back before doing
Arnaud Charlet committed
1985 1986
     anything else.
     This mechanism is only need in kernel mode. */
1987
#if !(defined (__RTP__) || defined (VTHREADS)) && ((CPU == PPCE500V2) || (CPU == PPC85XX))
Arnaud Charlet committed
1988 1989 1990
  register unsigned msr;
  /* Read the MSR value */
  asm volatile ("mfmsr %0" : "=r" (msr));
1991 1992 1993 1994 1995 1996 1997
  /* Force the SPE bit if not set.  */
  if ((msr & 0x02000000) == 0)
    {
      msr |= 0x02000000;
      /* Store to MSR */
      asm volatile ("mtmsr %0" : : "r" (msr));
    }
Arnaud Charlet committed
1998 1999
#endif

Arnaud Charlet committed
2000 2001 2002 2003 2004 2005 2006
  /* VxWorks will always mask out the signal during the signal handler and
     will reenable it on a longjmp.  GNAT does not generate a longjmp to
     return from a signal handler so the signal will still be masked unless
     we unmask it.  */
  sigprocmask (SIG_SETMASK, NULL, &mask);
  sigdelset (&mask, sig);
  sigprocmask (SIG_SETMASK, &mask, NULL);
Arnaud Charlet committed
2007

2008
#if defined (__ARMEL__) || defined (__PPC__) || defined (__i386__) || defined (__x86_64__) || defined (__aarch64__)
Arnaud Charlet committed
2009
  /* On certain targets, kernel mode, we process signals through a Call Frame
Arnaud Charlet committed
2010
     Info trampoline, voiding the need for myriads of fallback_frame_state
Arnaud Charlet committed
2011 2012 2013 2014
     variants in the ZCX runtime.  We have no simple way to distinguish ZCX
     from SJLJ here, so we do this for SJLJ as well even though this is not
     necessary.  This only incurs a few extra instructions and a tiny
     amount of extra stack usage.  */
Arnaud Charlet committed
2015

Arnaud Charlet committed
2016 2017 2018
#ifdef HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE
  /* We need to sometimes to adjust the PC in case of signals so that it
     doesn't reference the exception that actually raised the signal but the
Arnaud Charlet committed
2019
     instruction before it.  */
Arnaud Charlet committed
2020 2021 2022
  __gnat_adjust_context_for_raise (sig, sc);
#endif

Arnaud Charlet committed
2023
  __gnat_sigtramp (sig, (void *)si, (void *)sc,
Arnaud Charlet committed
2024
                   (__sigtramphandler_t *)&__gnat_map_signal);
Arnaud Charlet committed
2025 2026 2027 2028

#else
  __gnat_map_signal (sig, si, sc);
#endif
Arnaud Charlet committed
2029 2030
}

Arnaud Charlet committed
2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049
#if defined(__leon__) && defined(_WRS_KERNEL)
/* For LEON VxWorks we need to install a trap handler for stack overflow */

extern void excEnt (void);
/* VxWorks exception handler entry */

struct trap_entry {
   unsigned long inst_first;
   unsigned long inst_second;
   unsigned long inst_third;
   unsigned long inst_fourth;
};
/* Four instructions representing entries in the trap table */

struct trap_entry *trap_0_entry;
/* We will set the location of the entry for software trap 0 in the trap
   table. */
#endif

Richard Kenner committed
2050
void
R. Kelley Cook committed
2051
__gnat_install_handler (void)
Richard Kenner committed
2052 2053 2054 2055 2056
{
  struct sigaction act;

  /* Setup signal handler to map synchronous signals to appropriate
     exceptions.  Make sure that the handler isn't interrupted by another
Arnaud Charlet committed
2057
     signal that might cause a scheduling event!  */
Richard Kenner committed
2058

Arnaud Charlet committed
2059
  act.sa_sigaction = __gnat_error_handler;
Richard Kenner committed
2060
  act.sa_flags = SA_SIGINFO | SA_ONSTACK;
Arnaud Charlet committed
2061
  sigemptyset (&act.sa_mask);
Richard Kenner committed
2062

Arnaud Charlet committed
2063 2064
  /* For VxWorks, install all signal handlers, since pragma Interrupt_State
     applies to vectored hardware interrupts, not signals.  */
2065 2066 2067 2068
  sigaction (SIGFPE,  &act, NULL);
  sigaction (SIGILL,  &act, NULL);
  sigaction (SIGSEGV, &act, NULL);
  sigaction (SIGBUS,  &act, NULL);
Richard Kenner committed
2069

Arnaud Charlet committed
2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103
#if defined(__leon__) && defined(_WRS_KERNEL)
  /* Specific to the LEON VxWorks kernel run-time library */

  /* For stack checking the compiler triggers a software trap 0 (ta 0) in
     case of overflow (we use the stack limit mechanism). We need to install
     the trap handler here for this software trap (the OS does not handle
     it) as if it were a data_access_exception (trap 9). We do the same as
     if we put in the trap table a VXSPARC_BAD_TRAP(9). Software trap 0 is
     located at vector 0x80, and each entry takes 4 words. */

  trap_0_entry = (struct trap_entry *)(intVecBaseGet () + 0x80 * 4);

  /* mov 0x9, %l7 */

  trap_0_entry->inst_first = 0xae102000 + 9;

  /* sethi %hi(excEnt), %l6 */

  /* The 22 most significant bits of excEnt are obtained shifting 10 times
     to the right.  */

  trap_0_entry->inst_second = 0x2d000000 + ((unsigned long)excEnt >> 10);

  /* jmp %l6+%lo(excEnt) */

  /* The 10 least significant bits of excEnt are obtained by masking */

  trap_0_entry->inst_third = 0x81c5a000 + ((unsigned long)excEnt & 0x3ff);

  /* rd %psr, %l0 */

  trap_0_entry->inst_fourth = 0xa1480000;
#endif

Arnaud Charlet committed
2104
#ifdef __HANDLE_VXSIM_SC
Arnaud Charlet committed
2105 2106
  /*  By experiment, found that sysModel () returns the following string
      prefix for vxsim when running on Linux and Windows.  */
Arnaud Charlet committed
2107 2108 2109 2110 2111
  {
    char *model = sysModel ();
    if ((strncmp (model, "Linux", 5) == 0)
        || (strncmp (model, "Windows", 7) == 0)
        || (strncmp (model, "SIMLINUX", 8) == 0) /* vx7 */
Arnaud Charlet committed
2112
        || (strncmp (model, "SIMNT", 5) == 0)) /* ditto */
Arnaud Charlet committed
2113 2114
      __gnat_set_is_vxsim (TRUE);
  }
Arnaud Charlet committed
2115 2116
#endif

Richard Kenner committed
2117 2118 2119 2120 2121 2122
  __gnat_handler_installed = 1;
}

#define HAVE_GNAT_INIT_FLOAT

void
R. Kelley Cook committed
2123
__gnat_init_float (void)
Richard Kenner committed
2124
{
2125
  /* Disable overflow/underflow exceptions on the PPC processor, needed
2126 2127
     to get correct Ada semantics.  Note that for AE653 vThreads, the HW
     overflow settings are an OS configuration issue.  The instructions
2128
     below have no effect.  */
Arnaud Charlet committed
2129
#if defined (_ARCH_PPC) && !defined (_SOFT_FLOAT) && (!defined (VTHREADS) || defined (__VXWORKSMILS__))
Arnaud Charlet committed
2130
#if defined (__SPE__)
Arnaud Charlet committed
2131
  {
Arnaud Charlet committed
2132 2133
    /* For e500v2, do nothing and leave the responsibility to install the
       handler and enable the exceptions to the BSP.  */
Arnaud Charlet committed
2134 2135
  }
#else
Richard Kenner committed
2136 2137 2138
  asm ("mtfsb0 25");
  asm ("mtfsb0 26");
#endif
Arnaud Charlet committed
2139
#endif
2140

Arnaud Charlet committed
2141
#if (defined (__i386__) || defined (__x86_64__)) && !defined (VTHREADS)
2142
  /* This is used to properly initialize the FPU on an x86 for each
Arnaud Charlet committed
2143
     process thread. */
2144 2145 2146
  asm ("finit");
#endif

2147
  /* Similarly for SPARC64.  Achieved by masking bits in the Trap Enable Mask
2148
     field of the Floating-point Status Register (see the SPARC Architecture
2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164
     Manual Version 9, p 48).  */
#if defined (sparc64)

#define FSR_TEM_NVM (1 << 27)  /* Invalid operand  */
#define FSR_TEM_OFM (1 << 26)  /* Overflow  */
#define FSR_TEM_UFM (1 << 25)  /* Underflow  */
#define FSR_TEM_DZM (1 << 24)  /* Division by Zero  */
#define FSR_TEM_NXM (1 << 23)  /* Inexact result  */
  {
    unsigned int fsr;

    __asm__("st %%fsr, %0" : "=m" (fsr));
    fsr &= ~(FSR_TEM_OFM | FSR_TEM_UFM);
    __asm__("ld %0, %%fsr" : : "m" (fsr));
  }
#endif
Richard Kenner committed
2165 2166
}

2167 2168 2169 2170 2171 2172 2173
/* This subprogram is called by System.Task_Primitives.Operations.Enter_Task
   (if not null) when a new task is created.  It is initialized by
   System.Stack_Checking.Operations.Initialize_Stack_Limit.
   The use of a hook avoids to drag stack checking subprograms if stack
   checking is not used.  */
void (*__gnat_set_stack_limit_hook)(void) = (void (*)(void))0;

2174 2175 2176
/******************/
/* NetBSD Section */
/******************/
2177 2178 2179 2180 2181 2182 2183

#elif defined(__NetBSD__)

#include <signal.h>
#include <unistd.h>

static void
R. Kelley Cook committed
2184
__gnat_error_handler (int sig)
2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210
{
  struct Exception_Data *exception;
  const char *msg;

  switch(sig)
  {
    case SIGFPE:
      exception = &constraint_error;
      msg = "SIGFPE";
      break;
    case SIGILL:
      exception = &constraint_error;
      msg = "SIGILL";
      break;
    case SIGSEGV:
      exception = &storage_error;
      msg = "stack overflow or erroneous memory access";
      break;
    case SIGBUS:
      exception = &constraint_error;
      msg = "SIGBUS";
      break;
    default:
      exception = &program_error;
      msg = "unhandled signal";
    }
Richard Kenner committed
2211

Arnaud Charlet committed
2212
    Raise_From_Signal_Handler (exception, msg);
2213 2214 2215
}

void
Arnaud Charlet committed
2216
__gnat_install_handler (void)
2217 2218
{
  struct sigaction act;
Richard Kenner committed
2219

2220 2221 2222 2223
  act.sa_handler = __gnat_error_handler;
  act.sa_flags = SA_NODEFER | SA_RESTART;
  sigemptyset (&act.sa_mask);

2224
  /* Do not install handlers if interrupt state is "System".  */
2225 2226 2227 2228 2229 2230 2231 2232
  if (__gnat_get_interrupt_state (SIGFPE) != 's')
    sigaction (SIGFPE,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGILL) != 's')
    sigaction (SIGILL,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGSEGV) != 's')
    sigaction (SIGSEGV, &act, NULL);
  if (__gnat_get_interrupt_state (SIGBUS) != 's')
    sigaction (SIGBUS,  &act, NULL);
Arnaud Charlet committed
2233 2234

  __gnat_handler_installed = 1;
2235
}
Richard Kenner committed
2236

2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274
/*******************/
/* OpenBSD Section */
/*******************/

#elif defined(__OpenBSD__)

#include <signal.h>
#include <unistd.h>

static void
__gnat_error_handler (int sig)
{
  struct Exception_Data *exception;
  const char *msg;

  switch(sig)
  {
    case SIGFPE:
      exception = &constraint_error;
      msg = "SIGFPE";
      break;
    case SIGILL:
      exception = &constraint_error;
      msg = "SIGILL";
      break;
    case SIGSEGV:
      exception = &storage_error;
      msg = "stack overflow or erroneous memory access";
      break;
    case SIGBUS:
      exception = &constraint_error;
      msg = "SIGBUS";
      break;
    default:
      exception = &program_error;
      msg = "unhandled signal";
    }

Arnaud Charlet committed
2275
    Raise_From_Signal_Handler (exception, msg);
2276 2277 2278
}

void
Arnaud Charlet committed
2279
__gnat_install_handler (void)
2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299
{
  struct sigaction act;

  act.sa_handler = __gnat_error_handler;
  act.sa_flags = SA_NODEFER | SA_RESTART;
  sigemptyset (&act.sa_mask);

  /* Do not install handlers if interrupt state is "System" */
  if (__gnat_get_interrupt_state (SIGFPE) != 's')
    sigaction (SIGFPE,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGILL) != 's')
    sigaction (SIGILL,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGSEGV) != 's')
    sigaction (SIGSEGV, &act, NULL);
  if (__gnat_get_interrupt_state (SIGBUS) != 's')
    sigaction (SIGBUS,  &act, NULL);

  __gnat_handler_installed = 1;
}

2300 2301 2302 2303 2304 2305
/******************/
/* Darwin Section */
/******************/

#elif defined(__APPLE__)

2306
#include <TargetConditionals.h>
2307
#include <signal.h>
2308
#include <stdlib.h>
Arnaud Charlet committed
2309
#include <sys/syscall.h>
2310
#include <sys/sysctl.h>
2311

Arnaud Charlet committed
2312
/* This must be in keeping with System.OS_Interface.Alternate_Stack_Size.  */
Arnaud Charlet committed
2313
char __gnat_alternate_stack[32 * 1024]; /* 1 * MINSIGSTKSZ */
Arnaud Charlet committed
2314

Arnaud Charlet committed
2315 2316
/* Defined in xnu unix_signal.c.
   Tell the kernel to re-use alt stack when delivering a signal.  */
Arnaud Charlet committed
2317 2318
#define	UC_RESET_ALT_STACK	0x80000000

2319
#if !(defined (__arm__) || defined (__arm64__) || TARGET_IPHONE_SIMULATOR)
Arnaud Charlet committed
2320 2321 2322 2323 2324
#include <mach/mach_vm.h>
#include <mach/mach_init.h>
#include <mach/vm_statistics.h>
#endif

Arnaud Charlet committed
2325 2326
#ifdef __arm64__
#include <sys/ucontext.h>
Arnaud Charlet committed
2327
#include "sigtramp.h"
Arnaud Charlet committed
2328 2329
#endif

Arnaud Charlet committed
2330 2331 2332 2333
/* Return true if ADDR is within a stack guard area.  */
static int
__gnat_is_stack_guard (mach_vm_address_t addr)
{
2334
#if !(defined (__arm__) || defined (__arm64__) || TARGET_IPHONE_SIMULATOR)
Arnaud Charlet committed
2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353
  kern_return_t kret;
  vm_region_submap_info_data_64_t info;
  mach_vm_address_t start;
  mach_vm_size_t size;
  natural_t depth;
  mach_msg_type_number_t count;

  count = VM_REGION_SUBMAP_INFO_COUNT_64;
  start = addr;
  size = -1;
  depth = 9999;
  kret = mach_vm_region_recurse (mach_task_self (), &start, &size, &depth,
				 (vm_region_recurse_info_t) &info, &count);
  if (kret == KERN_SUCCESS
      && addr >= start && addr < (start + size)
      && info.protection == VM_PROT_NONE
      && info.user_tag == VM_MEMORY_STACK)
    return 1;
  return 0;
Arnaud Charlet committed
2354 2355
#else
  /* Pagezero for arm.  */
Arnaud Charlet committed
2356
  return addr >= 4096;
Arnaud Charlet committed
2357
#endif
Arnaud Charlet committed
2358 2359
}

2360 2361
#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE

2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390
#if defined (__x86_64__)
static int
__darwin_major_version (void)
{
  static int cache = -1;
  if (cache < 0)
    {
      int mib[2] = {CTL_KERN, KERN_OSRELEASE};
      size_t len;

      /* Find out how big the buffer needs to be (and set cache to 0
         on failure).  */
      if (sysctl (mib, 2, NULL, &len, NULL, 0) == 0)
        {
          char release[len];
          sysctl (mib, 2, release, &len, NULL, 0);
          /* Darwin releases are of the form L.M.N where L is the major
             version, so strtol will return L.  */
          cache = (int) strtol (release, NULL, 10);
        }
      else
        {
          cache = 0;
        }
    }
  return cache;
}
#endif

2391 2392 2393
void
__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED,
				 void *ucontext ATTRIBUTE_UNUSED)
2394
{
2395
#if defined (__x86_64__)
2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407
  if (__darwin_major_version () < 12)
    {
      /* Work around radar #10302855, where the unwinders (libunwind or
	 libgcc_s depending on the system revision) and the DWARF unwind
	 data for sigtramp have different ideas about register numbering,
	 causing rbx and rdx to be transposed.  */
      ucontext_t *uc = (ucontext_t *)ucontext;
      unsigned long t = uc->uc_mcontext->__ss.__rbx;

      uc->uc_mcontext->__ss.__rbx = uc->uc_mcontext->__ss.__rdx;
      uc->uc_mcontext->__ss.__rdx = t;
    }
Arnaud Charlet committed
2408
#elif defined(__arm64__)
Arnaud Charlet committed
2409
  /* Even though the CFI is marked as a signal frame, we need this.  */
Arnaud Charlet committed
2410 2411
  ucontext_t *uc = (ucontext_t *)ucontext;
  uc->uc_mcontext->__ss.__pc++;
2412
#endif
2413 2414 2415
}

static void
Arnaud Charlet committed
2416
__gnat_map_signal (int sig, siginfo_t *si, void *mcontext ATTRIBUTE_UNUSED)
2417 2418 2419 2420
{
  struct Exception_Data *exception;
  const char *msg;

2421 2422 2423
  switch (sig)
    {
    case SIGSEGV:
2424
    case SIGBUS:
Arnaud Charlet committed
2425
      if (__gnat_is_stack_guard ((unsigned long)si->si_addr))
Arnaud Charlet committed
2426
	{
Arnaud Charlet committed
2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437
#ifdef __arm64__
	  /* ??? This is a kludge to make stack checking work.  The problem is
	     that the trampoline doesn't restore LR and, consequently, doesn't
	     make it possible to unwind past an interrupted frame which hasn"t
	     saved LR on the stack yet.  Therefore, for probes in the prologue
	     (32-bit probes as opposed to standard 64-bit probes), we make the
	     unwinder skip the not-yet-established frame altogether.  */
	  mcontext_t mc = (mcontext_t)mcontext;
	  if (!(*(unsigned int *)(mc->__ss.__pc-1) & ((unsigned int)1 << 30)))
	    mc->__ss.__pc = mc->__ss.__lr;
#endif
Arnaud Charlet committed
2438 2439 2440 2441 2442 2443 2444 2445
	  exception = &storage_error;
	  msg = "stack overflow";
	}
      else
	{
	  exception = &constraint_error;
	  msg = "erroneous memory access";
	}
Arnaud Charlet committed
2446

Arnaud Charlet committed
2447
      /* Reset the use of alt stack, so that the alt stack will be used
Arnaud Charlet committed
2448
	 for the next signal delivery.
Arnaud Charlet committed
2449
	 The stack can't be used in case of stack checking.  */
Arnaud Charlet committed
2450
      syscall (SYS_sigreturn, NULL, UC_RESET_ALT_STACK);
2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465
      break;

    case SIGFPE:
      exception = &constraint_error;
      msg = "SIGFPE";
      break;

    default:
      exception = &program_error;
      msg = "unhandled signal";
    }

  Raise_From_Signal_Handler (exception, msg);
}

Arnaud Charlet committed
2466 2467 2468 2469 2470
static void
__gnat_error_handler (int sig, siginfo_t *si, void *ucontext)
{
  __gnat_adjust_context_for_raise (sig, ucontext);

Arnaud Charlet committed
2471
  /* The Darwin libc comes with a signal trampoline, except for ARM64.  */
Arnaud Charlet committed
2472 2473 2474 2475 2476 2477 2478 2479
#ifdef __arm64__
  __gnat_sigtramp (sig, (void *)si, ucontext,
		   (__sigtramphandler_t *)&__gnat_map_signal);
#else
  __gnat_map_signal (sig, si, ucontext);
#endif
}

2480 2481 2482 2483 2484 2485 2486
void
__gnat_install_handler (void)
{
  struct sigaction act;

  /* Set up signal handler to map synchronous signals to appropriate
     exceptions.  Make sure that the handler isn't interrupted by another
Arnaud Charlet committed
2487 2488 2489 2490 2491 2492 2493 2494 2495 2496
     signal that might cause a scheduling event!  Also setup an alternate
     stack region for the handler execution so that stack overflows can be
     handled properly, avoiding a SEGV generation from stack usage by the
     handler itself (and it is required by Darwin).  */

  stack_t stack;
  stack.ss_sp = __gnat_alternate_stack;
  stack.ss_size = sizeof (__gnat_alternate_stack);
  stack.ss_flags = 0;
  sigaltstack (&stack, NULL);
2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509

  act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
  act.sa_sigaction = __gnat_error_handler;
  sigemptyset (&act.sa_mask);

  /* Do not install handlers if interrupt state is "System".  */
  if (__gnat_get_interrupt_state (SIGABRT) != 's')
    sigaction (SIGABRT, &act, NULL);
  if (__gnat_get_interrupt_state (SIGFPE) != 's')
    sigaction (SIGFPE,  &act, NULL);
  if (__gnat_get_interrupt_state (SIGILL) != 's')
    sigaction (SIGILL,  &act, NULL);

Arnaud Charlet committed
2510 2511 2512
  act.sa_flags |= SA_ONSTACK;
  if (__gnat_get_interrupt_state (SIGSEGV) != 's')
    sigaction (SIGSEGV, &act, NULL);
2513 2514
  if (__gnat_get_interrupt_state (SIGBUS) != 's')
    sigaction (SIGBUS,  &act, NULL);
Arnaud Charlet committed
2515

2516 2517 2518
  __gnat_handler_installed = 1;
}

2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570
#elif defined(__QNX__)

/***************/
/* QNX Section */
/***************/

#include <signal.h>
#include <unistd.h>
#include <string.h>
#include "sigtramp.h"

void
__gnat_map_signal (int sig,
		   siginfo_t *si ATTRIBUTE_UNUSED,
		   void *mcontext ATTRIBUTE_UNUSED)
{
  struct Exception_Data *exception;
  const char *msg;

  switch(sig)
  {
    case SIGFPE:
      exception = &constraint_error;
      msg = "SIGFPE";
      break;
    case SIGILL:
      exception = &constraint_error;
      msg = "SIGILL";
      break;
    case SIGSEGV:
      exception = &storage_error;
      msg = "stack overflow or erroneous memory access";
      break;
    case SIGBUS:
      exception = &constraint_error;
      msg = "SIGBUS";
      break;
    default:
      exception = &program_error;
      msg = "unhandled signal";
    }

    Raise_From_Signal_Handler (exception, msg);
}

static void
__gnat_error_handler (int sig, siginfo_t *si, void *ucontext)
{
  __gnat_sigtramp (sig, (void *) si, (void *) ucontext,
		   (__sigtramphandler_t *)&__gnat_map_signal);
}

2571 2572 2573 2574
/* This must be in keeping with System.OS_Interface.Alternate_Stack_Size.  */
/* sigaltstack is currently not supported by QNX7 */
char __gnat_alternate_stack[0];

2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620
void
__gnat_install_handler (void)
{
  struct sigaction act;
  int err;

  act.sa_handler = __gnat_error_handler;
  act.sa_flags = SA_NODEFER | SA_SIGINFO;
  sigemptyset (&act.sa_mask);

  /* Do not install handlers if interrupt state is "System" */
  if (__gnat_get_interrupt_state (SIGFPE) != 's') {
    err = sigaction (SIGFPE,  &act, NULL);
    if (err == -1) {
      err = errno;
      perror ("error while attaching SIGFPE");
      perror (strerror (err));
    }
  }
  if (__gnat_get_interrupt_state (SIGILL) != 's') {
    sigaction (SIGILL,  &act, NULL);
    if (err == -1) {
      err = errno;
      perror ("error while attaching SIGFPE");
      perror (strerror (err));
    }
  }
  if (__gnat_get_interrupt_state (SIGSEGV) != 's') {
    sigaction (SIGSEGV, &act, NULL);
    if (err == -1) {
      err = errno;
      perror ("error while attaching SIGFPE");
      perror (strerror (err));
    }
  }
  if (__gnat_get_interrupt_state (SIGBUS) != 's') {
    sigaction (SIGBUS,  &act, NULL);
    if (err == -1) {
      err = errno;
      perror ("error while attaching SIGFPE");
      perror (strerror (err));
    }
  }
  __gnat_handler_installed = 1;
}

2621 2622 2623 2624 2625 2626 2627 2628
#elif defined (__DJGPP__)

void
__gnat_install_handler ()
{
  __gnat_handler_installed = 1;
}

Arnaud Charlet committed
2629 2630 2631 2632 2633 2634 2635
#elif defined(__ANDROID__)

/*******************/
/* Android Section */
/*******************/

#include <signal.h>
Arnaud Charlet committed
2636
#include <sys/ucontext.h>
Arnaud Charlet committed
2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648
#include "sigtramp.h"

#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE

void
__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, void *ucontext)
{
  mcontext_t *mcontext = &((ucontext_t *) ucontext)->uc_mcontext;

  /* ARM Bump has to be an even number because of odd/even architecture.  */
  ((mcontext_t *) mcontext)->arm_pc += 2;
}
Arnaud Charlet committed
2649 2650

static void
Arnaud Charlet committed
2651 2652
__gnat_map_signal (int sig,
		   siginfo_t *si ATTRIBUTE_UNUSED,
Arnaud Charlet committed
2653
		   void *mcontext ATTRIBUTE_UNUSED)
Arnaud Charlet committed
2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682
{
  struct Exception_Data *exception;
  const char *msg;

  switch (sig)
    {
    case SIGSEGV:
      exception = &storage_error;
      msg = "stack overflow or erroneous memory access";
      break;

    case SIGBUS:
      exception = &constraint_error;
      msg = "SIGBUS";
      break;

    case SIGFPE:
      exception = &constraint_error;
      msg = "SIGFPE";
      break;

    default:
      exception = &program_error;
      msg = "unhandled signal";
    }

  Raise_From_Signal_Handler (exception, msg);
}

Arnaud Charlet committed
2683
static void
Arnaud Charlet committed
2684
__gnat_error_handler (int sig, siginfo_t *si, void *ucontext)
Arnaud Charlet committed
2685 2686 2687 2688 2689 2690 2691
{
  __gnat_adjust_context_for_raise (sig, ucontext);

  __gnat_sigtramp (sig, (void *) si, (void *) ucontext,
		   (__sigtramphandler_t *)&__gnat_map_signal);
}

Arnaud Charlet committed
2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726
/* This must be in keeping with System.OS_Interface.Alternate_Stack_Size.  */
char __gnat_alternate_stack[16 * 1024];

void
__gnat_install_handler (void)
{
  struct sigaction act;

  /* Set up signal handler to map synchronous signals to appropriate
     exceptions.  Make sure that the handler isn't interrupted by another
     signal that might cause a scheduling event!  Also setup an alternate
     stack region for the handler execution so that stack overflows can be
     handled properly, avoiding a SEGV generation from stack usage by the
     handler itself.  */

  stack_t stack;
  stack.ss_sp = __gnat_alternate_stack;
  stack.ss_size = sizeof (__gnat_alternate_stack);
  stack.ss_flags = 0;
  sigaltstack (&stack, NULL);

  act.sa_sigaction = __gnat_error_handler;
  act.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO;
  sigemptyset (&act.sa_mask);

  sigaction (SIGABRT, &act, NULL);
  sigaction (SIGFPE,  &act, NULL);
  sigaction (SIGILL,  &act, NULL);
  sigaction (SIGBUS,  &act, NULL);
  act.sa_flags |= SA_ONSTACK;
  sigaction (SIGSEGV, &act, NULL);

  __gnat_handler_installed = 1;
}

Richard Kenner committed
2727 2728
#else

2729
/* For all other versions of GNAT, the handler does nothing.  */
Richard Kenner committed
2730

2731 2732 2733
/*******************/
/* Default Section */
/*******************/
Richard Kenner committed
2734 2735

void
R. Kelley Cook committed
2736
__gnat_install_handler (void)
Richard Kenner committed
2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747
{
  __gnat_handler_installed = 1;
}

#endif

/*********************/
/* __gnat_init_float */
/*********************/

/* This routine is called as each process thread is created, for possible
Arnaud Charlet committed
2748 2749
   initialization of the FP processor.  This version is used under INTERIX
   and WIN32.  */
Richard Kenner committed
2750

Arnaud Charlet committed
2751
#if defined (_WIN32) || defined (__INTERIX) \
2752
  || defined (__Lynx__) || defined(__NetBSD__) || defined(__FreeBSD__) \
2753
  || defined (__OpenBSD__) || defined (__DragonFly__) || defined(__QNX__)
Richard Kenner committed
2754 2755 2756 2757

#define HAVE_GNAT_INIT_FLOAT

void
R. Kelley Cook committed
2758
__gnat_init_float (void)
Richard Kenner committed
2759
{
2760
#if defined (__i386__) || defined (__x86_64__)
Richard Kenner committed
2761 2762

  /* This is used to properly initialize the FPU on an x86 for each
2763
     process thread.  */
Richard Kenner committed
2764 2765 2766 2767 2768 2769 2770 2771 2772

  asm ("finit");

#endif  /* Defined __i386__ */
}
#endif

#ifndef HAVE_GNAT_INIT_FLOAT

2773
/* All targets without a specific __gnat_init_float will use an empty one.  */
Richard Kenner committed
2774
void
R. Kelley Cook committed
2775
__gnat_init_float (void)
Richard Kenner committed
2776 2777 2778
{
}
#endif
2779 2780 2781 2782 2783 2784 2785

/***********************************/
/* __gnat_adjust_context_for_raise */
/***********************************/

#ifndef HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE

2786
/* All targets without a specific version will use an empty one.  */
2787

2788 2789 2790 2791
/* Given UCONTEXT a pointer to a context structure received by a signal
   handler for SIGNO, perform the necessary adjustments to let the handler
   raise an exception.  Calls to this routine are not conditioned by the
   propagation scheme in use.  */
2792 2793 2794 2795 2796

void
__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED,
				 void *ucontext ATTRIBUTE_UNUSED)
{
2797
  /* We used to compensate here for the raised from call vs raised from signal
Arnaud Charlet committed
2798
     exception discrepancy with the GCC ZCX scheme, but this now can be dealt
2799 2800 2801 2802
     with generically in the unwinder (see GCC PR other/26208).  This however
     requires the use of the _Unwind_GetIPInfo routine in raise-gcc.c, which
     is predicated on the definition of HAVE_GETIPINFO at compile time.  Only
     the VMS ports still do the compensation described in the few lines below.
2803

2804
     *** Call vs signal exception discrepancy with GCC ZCX scheme ***
2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828

     The GCC unwinder expects to be dealing with call return addresses, since
     this is the "nominal" case of what we retrieve while unwinding a regular
     call chain.

     To evaluate if a handler applies at some point identified by a return
     address, the propagation engine needs to determine what region the
     corresponding call instruction pertains to.  Because the return address
     may not be attached to the same region as the call, the unwinder always
     subtracts "some" amount from a return address to search the region
     tables, amount chosen to ensure that the resulting address is inside the
     call instruction.

     When we raise an exception from a signal handler, e.g. to transform a
     SIGSEGV into Storage_Error, things need to appear as if the signal
     handler had been "called" by the instruction which triggered the signal,
     so that exception handlers that apply there are considered.  What the
     unwinder will retrieve as the return address from the signal handler is
     what it will find as the faulting instruction address in the signal
     context pushed by the kernel.  Leaving this address untouched looses, if
     the triggering instruction happens to be the very first of a region, as
     the later adjustments performed by the unwinder would yield an address
     outside that region.  We need to compensate for the unwinder adjustments
     at some point, and this is what this routine is expected to do.
2829 2830 2831

     signo is passed because on some targets for some signals the PC in
     context points to the instruction after the faulting one, in which case
2832
     the unwinder adjustment is still desired.  */
2833 2834 2835
}

#endif
2836 2837 2838 2839

#ifdef __cplusplus
}
#endif