| /* Handling of compile-time options that influence the library. |
| Copyright (C) 2005-2019 Free Software Foundation, Inc. |
| |
| This file is part of the GNU Fortran runtime library (libgfortran). |
| |
| Libgfortran is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| Libgfortran is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| 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/>. */ |
| |
| #include "libgfortran.h" |
| #include <signal.h> |
| |
| |
| /* Useful compile-time options will be stored in here. */ |
| compile_options_t compile_options; |
| |
| #ifndef LIBGFOR_MINIMAL |
| static volatile sig_atomic_t fatal_error_in_progress = 0; |
| |
| |
| /* Helper function for backtrace_handler to write information about the |
| received signal to stderr before actually giving the backtrace. */ |
| static void |
| show_signal (int signum) |
| { |
| const char * name = NULL, * desc = NULL; |
| |
| switch (signum) |
| { |
| #if defined(SIGQUIT) |
| case SIGQUIT: |
| name = "SIGQUIT"; |
| desc = "Terminal quit signal"; |
| break; |
| #endif |
| |
| /* The following 4 signals are defined by C89. */ |
| case SIGILL: |
| name = "SIGILL"; |
| desc = "Illegal instruction"; |
| break; |
| |
| case SIGABRT: |
| name = "SIGABRT"; |
| desc = "Process abort signal"; |
| break; |
| |
| case SIGFPE: |
| name = "SIGFPE"; |
| desc = "Floating-point exception - erroneous arithmetic operation"; |
| break; |
| |
| case SIGSEGV: |
| name = "SIGSEGV"; |
| desc = "Segmentation fault - invalid memory reference"; |
| break; |
| |
| #if defined(SIGBUS) |
| case SIGBUS: |
| name = "SIGBUS"; |
| desc = "Access to an undefined portion of a memory object"; |
| break; |
| #endif |
| |
| #if defined(SIGSYS) |
| case SIGSYS: |
| name = "SIGSYS"; |
| desc = "Bad system call"; |
| break; |
| #endif |
| |
| #if defined(SIGTRAP) |
| case SIGTRAP: |
| name = "SIGTRAP"; |
| desc = "Trace/breakpoint trap"; |
| break; |
| #endif |
| |
| #if defined(SIGXCPU) |
| case SIGXCPU: |
| name = "SIGXCPU"; |
| desc = "CPU time limit exceeded"; |
| break; |
| #endif |
| |
| #if defined(SIGXFSZ) |
| case SIGXFSZ: |
| name = "SIGXFSZ"; |
| desc = "File size limit exceeded"; |
| break; |
| #endif |
| } |
| |
| if (name) |
| st_printf ("\nProgram received signal %s: %s.\n", name, desc); |
| else |
| st_printf ("\nProgram received signal %d.\n", signum); |
| } |
| |
| |
| /* A signal handler to allow us to output a backtrace. */ |
| void |
| backtrace_handler (int signum) |
| { |
| /* Since this handler is established for more than one kind of signal, |
| it might still get invoked recursively by delivery of some other kind |
| of signal. Use a static variable to keep track of that. */ |
| if (fatal_error_in_progress) |
| raise (signum); |
| fatal_error_in_progress = 1; |
| |
| show_signal (signum); |
| estr_write ("\nBacktrace for this error:\n"); |
| show_backtrace (true); |
| |
| /* Now reraise the signal. We reactivate the signal's |
| default handling, which is to terminate the process. |
| We could just call exit or abort, |
| but reraising the signal sets the return status |
| from the process correctly. */ |
| signal (signum, SIG_DFL); |
| raise (signum); |
| } |
| #endif |
| |
| /* Set the usual compile-time options. */ |
| extern void set_options (int , int []); |
| export_proto(set_options); |
| |
| void |
| set_options (int num, int options[]) |
| { |
| if (num >= 1) |
| compile_options.warn_std = options[0]; |
| if (num >= 2) |
| compile_options.allow_std = options[1]; |
| if (num >= 3) |
| compile_options.pedantic = options[2]; |
| if (num >= 4) |
| compile_options.backtrace = options[3]; |
| if (num >= 5) |
| compile_options.sign_zero = options[4]; |
| if (num >= 6) |
| compile_options.bounds_check = options[5]; |
| if (num >= 7) |
| compile_options.fpe_summary = options[6]; |
| |
| #ifndef LIBGFOR_MINIMAL |
| /* If backtrace is required, we set signal handlers on the POSIX |
| 2001 signals with core action. */ |
| if (compile_options.backtrace) |
| { |
| #if defined(SIGQUIT) |
| signal (SIGQUIT, backtrace_handler); |
| #endif |
| |
| /* The following 4 signals are defined by C89. */ |
| signal (SIGILL, backtrace_handler); |
| signal (SIGABRT, backtrace_handler); |
| signal (SIGFPE, backtrace_handler); |
| signal (SIGSEGV, backtrace_handler); |
| |
| #if defined(SIGBUS) |
| signal (SIGBUS, backtrace_handler); |
| #endif |
| |
| #if defined(SIGSYS) |
| signal (SIGSYS, backtrace_handler); |
| #endif |
| |
| #if defined(SIGTRAP) |
| signal (SIGTRAP, backtrace_handler); |
| #endif |
| |
| #if defined(SIGXCPU) |
| signal (SIGXCPU, backtrace_handler); |
| #endif |
| |
| #if defined(SIGXFSZ) |
| signal (SIGXFSZ, backtrace_handler); |
| #endif |
| } |
| #endif |
| } |
| |
| |
| /* Default values for the compile-time options. Keep in sync with |
| gcc/fortran/options.c (gfc_init_options). */ |
| void |
| init_compile_options (void) |
| { |
| compile_options.warn_std = GFC_STD_F95_DEL | GFC_STD_LEGACY; |
| compile_options.allow_std = GFC_STD_F95_OBS | GFC_STD_F95_DEL |
| | GFC_STD_F2003 | GFC_STD_F2008 | GFC_STD_F95 | GFC_STD_F77 |
| | GFC_STD_F2008_OBS | GFC_STD_GNU | GFC_STD_LEGACY; |
| compile_options.pedantic = 0; |
| compile_options.backtrace = 0; |
| compile_options.sign_zero = 1; |
| compile_options.fpe_summary = 0; |
| } |
| |
| /* Function called by the front-end to tell us the |
| default for unformatted data conversion. */ |
| |
| extern void set_convert (int); |
| export_proto (set_convert); |
| |
| void |
| set_convert (int conv) |
| { |
| compile_options.convert = conv; |
| } |
| |
| extern void set_record_marker (int); |
| export_proto (set_record_marker); |
| |
| |
| void |
| set_record_marker (int val) |
| { |
| |
| switch(val) |
| { |
| case 4: |
| compile_options.record_marker = sizeof (GFC_INTEGER_4); |
| break; |
| |
| case 8: |
| compile_options.record_marker = sizeof (GFC_INTEGER_8); |
| break; |
| |
| default: |
| runtime_error ("Invalid value for record marker"); |
| break; |
| } |
| } |
| |
| extern void set_max_subrecord_length (int); |
| export_proto (set_max_subrecord_length); |
| |
| void set_max_subrecord_length(int val) |
| { |
| if (val > GFC_MAX_SUBRECORD_LENGTH || val < 1) |
| { |
| runtime_error ("Invalid value for maximum subrecord length"); |
| return; |
| } |
| |
| compile_options.max_subrecord_length = val; |
| } |