xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/runtime/minimal.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1 /* Copyright (C) 2002-2020 Free Software Foundation, Inc.
2    Contributed by Andy Vaught and Paul Brook <paul@nowt.org>
3 
4 This file is part of the GNU Fortran runtime library (libgfortran).
5 
6 Libgfortran is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10 
11 Libgfortran is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
19 
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 <http://www.gnu.org/licenses/>.  */
24 
25 #include "libgfortran.h"
26 
27 #include <string.h>
28 
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 
33 
34 #if __nvptx__
35 /* Map "exit" to "abort"; see PR85463 '[nvptx] "exit" in offloaded region
36    doesn't terminate process'.  */
37 # undef exit
38 # define exit(status) do { (void) (status); abort (); } while (0)
39 #endif
40 
41 
42 #if __nvptx__
43 /* 'printf' is all we have.  */
44 # undef estr_vprintf
45 # define estr_vprintf vprintf
46 #else
47 # error TODO
48 #endif
49 
50 
51 /* runtime/environ.c */
52 
53 options_t options;
54 
55 
56 /* runtime/main.c */
57 
58 /* Stupid function to be sure the constructor is always linked in, even
59    in the case of static linking.  See PR libfortran/22298 for details.  */
60 void
stupid_function_name_for_static_linking(void)61 stupid_function_name_for_static_linking (void)
62 {
63   return;
64 }
65 
66 
67 static int argc_save;
68 static char **argv_save;
69 
70 
71 /* Set the saved values of the command line arguments.  */
72 
73 void
set_args(int argc,char ** argv)74 set_args (int argc, char **argv)
75 {
76   argc_save = argc;
77   argv_save = argv;
78 }
79 iexport(set_args);
80 
81 
82 /* Retrieve the saved values of the command line arguments.  */
83 
84 void
get_args(int * argc,char *** argv)85 get_args (int *argc, char ***argv)
86 {
87   *argc = argc_save;
88   *argv = argv_save;
89 }
90 
91 
92 /* runtime/error.c */
93 
94 /* Write a null-terminated C string to standard error. This function
95    is async-signal-safe.  */
96 
97 ssize_t
estr_write(const char * str)98 estr_write (const char *str)
99 {
100   return write (STDERR_FILENO, str, strlen (str));
101 }
102 
103 
104 /* printf() like function for for printing to stderr.  Uses a stack
105    allocated buffer and doesn't lock stderr, so it should be safe to
106    use from within a signal handler.  */
107 
108 int
st_printf(const char * format,...)109 st_printf (const char * format, ...)
110 {
111   int written;
112   va_list ap;
113   va_start (ap, format);
114   written = estr_vprintf (format, ap);
115   va_end (ap);
116   return written;
117 }
118 
119 
120 /* sys_abort()-- Terminate the program showing backtrace and dumping
121    core.  */
122 
123 void
sys_abort(void)124 sys_abort (void)
125 {
126   /* If backtracing is enabled, print backtrace and disable signal
127      handler for ABRT.  */
128   if (options.backtrace == 1
129       || (options.backtrace == -1 && compile_options.backtrace == 1))
130     {
131       estr_write ("\nProgram aborted.\n");
132     }
133 
134   abort();
135 }
136 
137 
138 /* Exit in case of error termination. If backtracing is enabled, print
139    backtrace, then exit.  */
140 
141 void
exit_error(int status)142 exit_error (int status)
143 {
144   if (options.backtrace == 1
145       || (options.backtrace == -1 && compile_options.backtrace == 1))
146     {
147       estr_write ("\nError termination.\n");
148     }
149   exit (status);
150 }
151 
152 
153 /* show_locus()-- Print a line number and filename describing where
154  * something went wrong */
155 
156 void
show_locus(st_parameter_common * cmp)157 show_locus (st_parameter_common *cmp)
158 {
159   char *filename;
160 
161   if (!options.locus || cmp == NULL || cmp->filename == NULL)
162     return;
163 
164   if (cmp->unit > 0)
165     {
166       filename = /* TODO filename_from_unit (cmp->unit) */ NULL;
167 
168       if (filename != NULL)
169 	{
170 	  st_printf ("At line %d of file %s (unit = %d, file = '%s')\n",
171 		   (int) cmp->line, cmp->filename, (int) cmp->unit, filename);
172 	  free (filename);
173 	}
174       else
175 	{
176 	  st_printf ("At line %d of file %s (unit = %d)\n",
177 		   (int) cmp->line, cmp->filename, (int) cmp->unit);
178 	}
179       return;
180     }
181 
182   st_printf ("At line %d of file %s\n", (int) cmp->line, cmp->filename);
183 }
184 
185 
186 /* recursion_check()-- It's possible for additional errors to occur
187  * during fatal error processing.  We detect this condition here and
188  * exit with code 4 immediately. */
189 
190 #define MAGIC 0x20DE8101
191 
192 static void
recursion_check(void)193 recursion_check (void)
194 {
195   static int magic = 0;
196 
197   /* Don't even try to print something at this point */
198   if (magic == MAGIC)
199     sys_abort ();
200 
201   magic = MAGIC;
202 }
203 
204 
205 /* os_error()-- Operating system error.  We get a message from the
206  * operating system, show it and leave.  Some operating system errors
207  * are caught and processed by the library.  If not, we come here. */
208 
209 void
os_error(const char * message)210 os_error (const char *message)
211 {
212   recursion_check ();
213   estr_write ("Operating system error: ");
214   estr_write (message);
215   estr_write ("\n");
216   exit_error (1);
217 }
218 iexport(os_error); /* TODO, DEPRECATED, ABI: Should not be exported
219 		      anymore when bumping so version.  */
220 
221 
222 /* Improved version of os_error with a printf style format string and
223    a locus.  */
224 
225 void
os_error_at(const char * where,const char * message,...)226 os_error_at (const char *where, const char *message, ...)
227 {
228   va_list ap;
229 
230   recursion_check ();
231   estr_write (where);
232   estr_write (": ");
233   va_start (ap, message);
234   estr_vprintf (message, ap);
235   va_end (ap);
236   estr_write ("\n");
237   exit_error (1);
238 }
239 iexport(os_error_at);
240 
241 
242 /* void runtime_error()-- These are errors associated with an
243  * invalid fortran program. */
244 
245 void
runtime_error(const char * message,...)246 runtime_error (const char *message, ...)
247 {
248   va_list ap;
249 
250   recursion_check ();
251   estr_write ("Fortran runtime error: ");
252   va_start (ap, message);
253   estr_vprintf (message, ap);
254   va_end (ap);
255   estr_write ("\n");
256   exit_error (2);
257 }
258 iexport(runtime_error);
259 
260 /* void runtime_error_at()-- These are errors associated with a
261  * run time error generated by the front end compiler.  */
262 
263 void
runtime_error_at(const char * where,const char * message,...)264 runtime_error_at (const char *where, const char *message, ...)
265 {
266   va_list ap;
267 
268   recursion_check ();
269   estr_write (where);
270   estr_write ("\nFortran runtime error: ");
271   va_start (ap, message);
272   estr_vprintf (message, ap);
273   va_end (ap);
274   estr_write ("\n");
275   exit_error (2);
276 }
277 iexport(runtime_error_at);
278 
279 
280 void
runtime_warning_at(const char * where,const char * message,...)281 runtime_warning_at (const char *where, const char *message, ...)
282 {
283   va_list ap;
284 
285   estr_write (where);
286   estr_write ("\nFortran runtime warning: ");
287   va_start (ap, message);
288   estr_vprintf (message, ap);
289   va_end (ap);
290   estr_write ("\n");
291 }
292 iexport(runtime_warning_at);
293 
294 
295 /* void internal_error()-- These are this-can't-happen errors
296  * that indicate something deeply wrong. */
297 
298 void
internal_error(st_parameter_common * cmp,const char * message)299 internal_error (st_parameter_common *cmp, const char *message)
300 {
301   recursion_check ();
302   show_locus (cmp);
303   estr_write ("Internal Error: ");
304   estr_write (message);
305   estr_write ("\n");
306 
307   /* This function call is here to get the main.o object file included
308      when linking statically. This works because error.o is supposed to
309      be always linked in (and the function call is in internal_error
310      because hopefully it doesn't happen too often).  */
311   stupid_function_name_for_static_linking();
312 
313   exit_error (3);
314 }
315 
316 
317 /* runtime/stop.c */
318 
319 #undef report_exception
320 #define report_exception() do {} while (0)
321 
322 
323 /* A numeric STOP statement.  */
324 
325 extern _Noreturn void stop_numeric (int, bool);
326 export_proto(stop_numeric);
327 
328 void
stop_numeric(int code,bool quiet)329 stop_numeric (int code, bool quiet)
330 {
331   if (!quiet)
332     {
333       report_exception ();
334       st_printf ("STOP %d\n", code);
335     }
336   exit (code);
337 }
338 
339 
340 /* A character string or blank STOP statement.  */
341 
342 void
stop_string(const char * string,size_t len,bool quiet)343 stop_string (const char *string, size_t len, bool quiet)
344 {
345   if (!quiet)
346     {
347       report_exception ();
348       if (string)
349 	{
350 	  estr_write ("STOP ");
351 	  (void) write (STDERR_FILENO, string, len);
352 	  estr_write ("\n");
353 	}
354     }
355   exit (0);
356 }
357 
358 
359 /* Per Fortran 2008, section 8.4:  "Execution of a STOP statement initiates
360    normal termination of execution. Execution of an ERROR STOP statement
361    initiates error termination of execution."  Thus, error_stop_string returns
362    a nonzero exit status code.  */
363 
364 extern _Noreturn void error_stop_string (const char *, size_t, bool);
365 export_proto(error_stop_string);
366 
367 void
error_stop_string(const char * string,size_t len,bool quiet)368 error_stop_string (const char *string, size_t len, bool quiet)
369 {
370   if (!quiet)
371     {
372       report_exception ();
373       estr_write ("ERROR STOP ");
374       (void) write (STDERR_FILENO, string, len);
375       estr_write ("\n");
376     }
377   exit_error (1);
378 }
379 
380 
381 /* A numeric ERROR STOP statement.  */
382 
383 extern _Noreturn void error_stop_numeric (int, bool);
384 export_proto(error_stop_numeric);
385 
386 void
error_stop_numeric(int code,bool quiet)387 error_stop_numeric (int code, bool quiet)
388 {
389   if (!quiet)
390     {
391       report_exception ();
392       st_printf ("ERROR STOP %d\n", code);
393     }
394   exit_error (code);
395 }
396