diff options
Diffstat (limited to 'libgfortran')
-rw-r--r-- | libgfortran/ChangeLog | 12 | ||||
-rw-r--r-- | libgfortran/libgfortran.h | 3 | ||||
-rw-r--r-- | libgfortran/runtime/backtrace.c | 12 | ||||
-rw-r--r-- | libgfortran/runtime/compile_options.c | 11 | ||||
-rw-r--r-- | libgfortran/runtime/main.c | 39 |
5 files changed, 75 insertions, 2 deletions
diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index f0e3078..9092921 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,5 +1,17 @@ 2011-05-29 Janne Blomqvist <jb@gcc.gnu.org> + PR libfortran/48931 + * libgfortran.h (find_addr2line): New prototype. + * runtime/backtrace.c (show_backtrace): Use async-signal-safe + execve and stored path of addr2line. + * runtime/compile_options.c (maybe_find_addr2line): New function. + (set_options): Call maybe_find_addr2line if backtracing is enabled. + * runtime/main.c (find_addr2line): New function. + (init): Call find_addr2line if backtracing is enabled. + (cleanup): Free addr2line_path. + +2011-05-29 Janne Blomqvist <jb@gcc.gnu.org> + PR libfortran/49214 * runtime/backtrace.c (fd_gets): Return NULL if nothing was read. diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h index e77ba10..b72b250 100644 --- a/libgfortran/libgfortran.h +++ b/libgfortran/libgfortran.h @@ -665,6 +665,9 @@ export_proto(store_exe_path); extern char * full_exe_path (void); internal_proto(full_exe_path); +extern void find_addr2line (void); +internal_proto(find_addr2line); + /* backtrace.c */ extern void show_backtrace (void); diff --git a/libgfortran/runtime/backtrace.c b/libgfortran/runtime/backtrace.c index 943332a..7d6479f 100644 --- a/libgfortran/runtime/backtrace.c +++ b/libgfortran/runtime/backtrace.c @@ -104,6 +104,9 @@ fd_gets (char *s, int size, int fd) } +extern char *addr2line_path; + + /* show_backtrace displays the backtrace, currently obtained by means of the glibc backtrace* functions. */ @@ -124,6 +127,9 @@ show_backtrace (void) #if CAN_PIPE + if (addr2line_path == NULL) + goto fallback_noerr; + /* We attempt to extract file and line information from addr2line. */ do { @@ -146,6 +152,7 @@ show_backtrace (void) /* Child process. */ #define NUM_FIXEDARGS 7 char *arg[NUM_FIXEDARGS]; + char *newenv[] = { NULL }; close (f[0]); @@ -160,14 +167,14 @@ show_backtrace (void) _exit (1); close (f[1]); - arg[0] = (char *) "addr2line"; + arg[0] = addr2line_path; arg[1] = (char *) "-e"; arg[2] = full_exe_path (); arg[3] = (char *) "-f"; arg[4] = (char *) "-s"; arg[5] = (char *) "-C"; arg[6] = NULL; - execvp (arg[0], arg); + execve (addr2line_path, arg, newenv); _exit (1); #undef NUM_FIXEDARGS } @@ -264,6 +271,7 @@ fallback: #endif /* CAN_PIPE */ +fallback_noerr: /* Fallback to the glibc backtrace. */ estr_write ("\nBacktrace for this error:\n"); backtrace_symbols_fd (trace, depth, STDERR_FILENO); diff --git a/libgfortran/runtime/compile_options.c b/libgfortran/runtime/compile_options.c index dc0da4b..c3e64de 100644 --- a/libgfortran/runtime/compile_options.c +++ b/libgfortran/runtime/compile_options.c @@ -58,6 +58,15 @@ backtrace_handler (int signum) } +/* Helper function for set_options because we need to access the + global variable options which is not seen in set_options. */ +static void +maybe_find_addr2line (void) +{ + if (options.backtrace == -1) + find_addr2line (); +} + /* Set the usual compile-time options. */ extern void set_options (int , int []); export_proto(set_options); @@ -131,6 +140,8 @@ set_options (int num, int options[]) #if defined(SIGXFSZ) signal (SIGXFSZ, backtrace_handler); #endif + + maybe_find_addr2line (); } #endif diff --git a/libgfortran/runtime/main.c b/libgfortran/runtime/main.c index 54d9e09..bc8dab4 100644 --- a/libgfortran/runtime/main.c +++ b/libgfortran/runtime/main.c @@ -139,6 +139,40 @@ full_exe_path (void) } +char *addr2line_path; + +/* Find addr2line and store the path. */ + +void +find_addr2line (void) +{ +#ifdef HAVE_ACCESS +#define A2L_LEN 10 + char *path = getenv ("PATH"); + size_t n = strlen (path); + char ap[n + 1 + A2L_LEN]; + size_t ai = 0; + for (size_t i = 0; i < n; i++) + { + if (path[i] != ':') + ap[ai++] = path[i]; + else + { + ap[ai++] = '/'; + memcpy (ap + ai, "addr2line", A2L_LEN); + if (access (ap, R_OK|X_OK) == 0) + { + addr2line_path = strdup (ap); + return; + } + else + ai = 0; + } + } +#endif +} + + /* Set the saved values of the command line arguments. */ void @@ -185,6 +219,9 @@ init (void) /* if (argc > 1 && strcmp(argv[1], "--resume") == 0) resume(); */ #endif + if (options.backtrace == 1) + find_addr2line (); + random_seed_i4 (NULL, NULL, NULL); } @@ -198,4 +235,6 @@ cleanup (void) if (please_free_exe_path_when_done) free ((char *) exe_path); + + free (addr2line_path); } |