Home | History | Annotate | Line # | Download | only in gcc
collect-utils.cc revision 1.1.1.1
      1 /* Utility functions used by tools like collect2 and lto-wrapper.
      2    Copyright (C) 2009-2022 Free Software Foundation, Inc.
      3 
      4 This file is part of GCC.
      5 
      6 GCC is free software; you can redistribute it and/or modify it under
      7 the terms of the GNU General Public License as published by the Free
      8 Software Foundation; either version 3, or (at your option) any later
      9 version.
     10 
     11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14 for more details.
     15 
     16 You should have received a copy of the GNU General Public License
     17 along with GCC; see the file COPYING3.  If not see
     18 <http://www.gnu.org/licenses/>.  */
     19 
     20 #include "config.h"
     21 #include "system.h"
     22 #include "coretypes.h"
     23 #include "intl.h"
     24 #include "diagnostic.h"
     25 #include "obstack.h"
     26 #include "opts.h"
     27 #include "options.h"
     28 #include "simple-object.h"
     29 #include "lto-section-names.h"
     30 #include "collect-utils.h"
     31 
     32 static char *response_file;
     33 
     34 bool debug;
     35 bool verbose;
     36 bool save_temps;
     37 const char *dumppfx;
     38 
     39 
     40 /* Notify user of a non-error.  */
     41 void
     42 notice (const char *cmsgid, ...)
     43 {
     44   va_list ap;
     45 
     46   va_start (ap, cmsgid);
     47   vfprintf (stderr, _(cmsgid), ap);
     48   va_end (ap);
     49 }
     50 
     51 void
     52 fatal_signal (int signum)
     53 {
     54   signal (signum, SIG_DFL);
     55   utils_cleanup (true);
     56   /* Get the same signal again, this time not handled,
     57      so its normal effect occurs.  */
     58   kill (getpid (), signum);
     59 }
     60 
     61 /* Setup the signal handlers for the utils. */
     62 void
     63 setup_signals (void)
     64 {
     65 #ifdef SIGQUIT
     66   if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
     67     signal (SIGQUIT, fatal_signal);
     68 #endif
     69   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
     70     signal (SIGINT, fatal_signal);
     71 #ifdef SIGALRM
     72   if (signal (SIGALRM, SIG_IGN) != SIG_IGN)
     73     signal (SIGALRM, fatal_signal);
     74 #endif
     75 #ifdef SIGHUP
     76   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
     77     signal (SIGHUP, fatal_signal);
     78 #endif
     79   if (signal (SIGSEGV, SIG_IGN) != SIG_IGN)
     80     signal (SIGSEGV, fatal_signal);
     81   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
     82     signal (SIGTERM, fatal_signal);
     83 #ifdef SIGPIPE
     84   if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
     85     signal (SIGPIPE, fatal_signal);
     86 #endif
     87 #ifdef SIGBUS
     88   if (signal (SIGBUS, SIG_IGN) != SIG_IGN)
     89     signal (SIGBUS, fatal_signal);
     90 #endif
     91 #ifdef SIGCHLD
     92   /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
     93      receive the signal.  A different setting is inheritable */
     94   signal (SIGCHLD, SIG_DFL);
     95 #endif
     96 }
     97 
     98 /* Wait for a process to finish, and exit if a nonzero status is found.  */
    100 
    101 int
    102 collect_wait (const char *prog, struct pex_obj *pex)
    103 {
    104   int status;
    105 
    106   if (!pex_get_status (pex, 1, &status))
    107     fatal_error (input_location, "cannot get program status: %m");
    108   pex_free (pex);
    109 
    110   if (response_file && !save_temps)
    111     {
    112       unlink (response_file);
    113       response_file = NULL;
    114     }
    115 
    116   if (status)
    117     {
    118       if (WIFSIGNALED (status))
    119 	{
    120 	  int sig = WTERMSIG (status);
    121 	  fatal_error (input_location, "%s terminated with signal %d [%s]%s",
    122 		       prog, sig, strsignal (sig),
    123 		       WCOREDUMP (status) ? ", core dumped" : "");
    124 	}
    125 
    126       if (WIFEXITED (status))
    127 	return WEXITSTATUS (status);
    128     }
    129   return 0;
    130 }
    131 
    132 void
    133 do_wait (const char *prog, struct pex_obj *pex)
    134 {
    135   int ret = collect_wait (prog, pex);
    136   if (ret != 0)
    137     fatal_error (input_location, "%s returned %d exit status", prog, ret);
    138 }
    139 
    140 
    141 /* Execute a program, and wait for the reply.  */
    143 
    144 struct pex_obj *
    145 collect_execute (const char *prog, char **argv, const char *outname,
    146 		 const char *errname, int flags, bool use_atfile,
    147 		 const char *atsuffix)
    148 {
    149   struct pex_obj *pex;
    150   const char *errmsg;
    151   int err;
    152   char *response_arg = NULL;
    153   char *response_argv[3];
    154 
    155   if (use_atfile && argv[0] != NULL)
    156     {
    157       /* If using @file arguments, create a temporary file and put the
    158          contents of argv into it.  Then change argv to an array corresponding
    159          to a single argument @FILE, where FILE is the temporary filename.  */
    160 
    161       char **current_argv = argv + 1;
    162       char *argv0 = argv[0];
    163       int status;
    164       FILE *f;
    165 
    166       /* Note: we assume argv contains at least one element; this is
    167          checked above.  */
    168 
    169       if (!save_temps || !atsuffix || !dumppfx)
    170 	response_file = make_temp_file ("");
    171       else
    172 	response_file = concat (dumppfx, atsuffix, NULL);
    173 
    174       f = fopen (response_file, "w");
    175 
    176       if (f == NULL)
    177         fatal_error (input_location, "could not open response file %s",
    178 		     response_file);
    179 
    180       status = writeargv (current_argv, f);
    181 
    182       if (status)
    183         fatal_error (input_location, "could not write to response file %s",
    184 		     response_file);
    185 
    186       status = fclose (f);
    187 
    188       if (EOF == status)
    189         fatal_error (input_location, "could not close response file %s",
    190 		     response_file);
    191 
    192       response_arg = concat ("@", response_file, NULL);
    193       response_argv[0] = argv0;
    194       response_argv[1] = response_arg;
    195       response_argv[2] = NULL;
    196 
    197       argv = response_argv;
    198     }
    199 
    200   if (verbose || debug)
    201     {
    202       char **p_argv;
    203       const char *str;
    204 
    205       if (argv[0])
    206 	fprintf (stderr, "%s", argv[0]);
    207       else
    208 	notice ("[cannot find %s]", prog);
    209 
    210       for (p_argv = &argv[1]; (str = *p_argv) != (char *) 0; p_argv++)
    211 	fprintf (stderr, " %s", str);
    212 
    213       fprintf (stderr, "\n");
    214     }
    215 
    216   fflush (stdout);
    217   fflush (stderr);
    218 
    219   /* If we cannot find a program we need, complain error.  Do this here
    220      since we might not end up needing something that we could not find.  */
    221 
    222   if (argv[0] == 0)
    223     fatal_error (input_location, "cannot find %qs", prog);
    224 
    225   pex = pex_init (0, "collect2", NULL);
    226   if (pex == NULL)
    227     fatal_error (input_location, "%<pex_init%> failed: %m");
    228 
    229   errmsg = pex_run (pex, flags, argv[0], argv, outname,
    230 		    errname, &err);
    231   if (errmsg != NULL)
    232     {
    233       if (err != 0)
    234 	{
    235 	  errno = err;
    236 	  fatal_error (input_location, "%s: %m", _(errmsg));
    237 	}
    238       else
    239 	fatal_error (input_location, errmsg);
    240     }
    241 
    242   free (response_arg);
    243 
    244   return pex;
    245 }
    246 
    247 void
    248 fork_execute (const char *prog, char **argv, bool use_atfile,
    249 	      const char *atsuffix)
    250 {
    251   struct pex_obj *pex;
    252 
    253   pex = collect_execute (prog, argv, NULL, NULL,
    254 			 PEX_LAST | PEX_SEARCH, use_atfile, atsuffix);
    255   do_wait (prog, pex);
    256 }
    257 
    258 /* Delete tempfiles.  */
    259 
    260 void
    261 utils_cleanup (bool from_signal)
    262 {
    263   static bool cleanup_done = false;
    264 
    265   if (cleanup_done)
    266     return;
    267 
    268   /* Setting cleanup_done prevents an infinite loop if one of the
    269      calls to maybe_unlink fails. */
    270   cleanup_done = true;
    271 
    272   tool_cleanup (from_signal);
    273 }
    274