Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libgfortran / runtime / main.c
1 /* Copyright (C) 2002-2013 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 #include <stdlib.h>
27 #include <string.h>
28 #include <limits.h>
29
30
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 /* Stupid function to be sure the constructor is always linked in, even
36    in the case of static linking.  See PR libfortran/22298 for details.  */
37 void
38 stupid_function_name_for_static_linking (void)
39 {
40   return;
41 }
42
43 /* This will be 0 for little-endian
44    machines and 1 for big-endian machines.  */
45 int big_endian = 0;
46
47
48 /* Figure out endianness for this machine.  */
49
50 static void
51 determine_endianness (void)
52 {
53   union
54   {
55     GFC_LOGICAL_8 l8;
56     GFC_LOGICAL_4 l4[2];
57   } u;
58
59   u.l8 = 1;
60   if (u.l4[0])
61     big_endian = 0;
62   else if (u.l4[1])
63     big_endian = 1;
64   else
65     runtime_error ("Unable to determine machine endianness");
66 }
67
68
69 static int argc_save;
70 static char **argv_save;
71
72 static const char *exe_path;
73 static int please_free_exe_path_when_done;
74
75 /* Save the path under which the program was called, for use in the
76    backtrace routines.  */
77 void
78 store_exe_path (const char * argv0)
79 {
80 #ifndef PATH_MAX
81 #define PATH_MAX 1024
82 #endif
83
84 #ifndef DIR_SEPARATOR   
85 #define DIR_SEPARATOR '/'
86 #endif
87
88   char buf[PATH_MAX], *path;
89   const char *cwd;
90
91   /* This can only happen if store_exe_path is called multiple times.  */
92   if (please_free_exe_path_when_done)
93     free ((char *) exe_path);
94
95   /* Reading the /proc/self/exe symlink is Linux-specific(?), but if
96      it works it gives the correct answer.  */
97 #ifdef HAVE_READLINK
98   int len;
99   if ((len = readlink ("/proc/self/exe", buf, sizeof (buf) - 1)) != -1)
100     {
101       buf[len] = '\0';
102       exe_path = strdup (buf);
103       please_free_exe_path_when_done = 1;
104       return;
105     }
106 #endif
107
108   /* If the path is absolute or on a simulator where argv is not set.  */
109 #ifdef __MINGW32__
110   if (argv0 == NULL
111       || ('A' <= argv0[0] && argv0[0] <= 'Z' && argv0[1] == ':')
112       || ('a' <= argv0[0] && argv0[0] <= 'z' && argv0[1] == ':')
113       || (argv0[0] == '/' && argv0[1] == '/')
114       || (argv0[0] == '\\' && argv0[1] == '\\'))
115 #else
116   if (argv0 == NULL || argv0[0] == DIR_SEPARATOR)
117 #endif
118     {
119       exe_path = argv0;
120       please_free_exe_path_when_done = 0;
121       return;
122     }
123
124 #ifdef HAVE_GETCWD
125   cwd = getcwd (buf, sizeof (buf));
126 #else
127   cwd = NULL;
128 #endif
129
130   if (!cwd)
131     {
132       exe_path = argv0;
133       please_free_exe_path_when_done = 0;
134       return;
135     }
136
137   /* exe_path will be cwd + "/" + argv[0] + "\0".  This will not work
138      if the executable is not in the cwd, but at this point we're out
139      of better ideas.  */
140   size_t pathlen = strlen (cwd) + 1 + strlen (argv0) + 1;
141   path = malloc (pathlen);
142   snprintf (path, pathlen, "%s%c%s", cwd, DIR_SEPARATOR, argv0);
143   exe_path = path;
144   please_free_exe_path_when_done = 1;
145 }
146
147
148 /* Return the full path of the executable.  */
149 char *
150 full_exe_path (void)
151 {
152   return (char *) exe_path;
153 }
154
155
156 char *addr2line_path;
157
158 /* Find addr2line and store the path.  */
159
160 void
161 find_addr2line (void)
162 {
163 #ifdef HAVE_ACCESS
164 #define A2L_LEN 10
165   char *path = secure_getenv ("PATH");
166   if (!path)
167     return;
168   size_t n = strlen (path);
169   char ap[n + 1 + A2L_LEN];
170   size_t ai = 0;
171   for (size_t i = 0; i < n; i++)
172     {
173       if (path[i] != ':')
174         ap[ai++] = path[i];
175       else
176         {
177           ap[ai++] = '/';
178           memcpy (ap + ai, "addr2line", A2L_LEN);
179           if (access (ap, R_OK|X_OK) == 0)
180             {
181               addr2line_path = strdup (ap);
182               return;
183             }
184           else
185             ai = 0;
186         }
187     }
188 #endif
189 }
190
191
192 /* Set the saved values of the command line arguments.  */
193
194 void
195 set_args (int argc, char **argv)
196 {
197   argc_save = argc;
198   argv_save = argv;
199   store_exe_path (argv[0]);
200 }
201 iexport(set_args);
202
203
204 /* Retrieve the saved values of the command line arguments.  */
205
206 void
207 get_args (int *argc, char ***argv)
208 {
209   *argc = argc_save;
210   *argv = argv_save;
211 }
212
213
214 /* Initialize the runtime library.  */
215
216 static void __attribute__((constructor))
217 init (void)
218 {
219   /* Figure out the machine endianness.  */
220   determine_endianness ();
221
222   /* Must be first */
223   init_variables ();
224
225   init_units ();
226   set_fpu ();
227   init_compile_options ();
228
229 #ifdef DEBUG
230   /* Check for special command lines.  */
231
232   if (argc > 1 && strcmp (argv[1], "--help") == 0)
233     show_variables ();
234
235   /* if (argc > 1 && strcmp(argv[1], "--resume") == 0) resume();  */
236 #endif
237
238   if (options.backtrace == 1)
239     find_addr2line ();
240
241   random_seed_i4 (NULL, NULL, NULL);
242 }
243
244
245 /* Cleanup the runtime library.  */
246
247 static void __attribute__((destructor))
248 cleanup (void)
249 {
250   close_units ();
251   
252   if (please_free_exe_path_when_done)
253     free ((char *) exe_path);
254
255   free (addr2line_path);
256 }