LCOV - code coverage report
Current view: top level - gcc - collect-utils.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 71.2 % 111 79
Test Date: 2026-02-28 14:20:25 Functions: 75.0 % 8 6
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Utility functions used by tools like collect2 and lto-wrapper.
       2              :    Copyright (C) 2009-2026 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            0 : notice (const char *cmsgid, ...)
      43              : {
      44            0 :   va_list ap;
      45              : 
      46            0 :   va_start (ap, cmsgid);
      47            0 :   vfprintf (stderr, _(cmsgid), ap);
      48            0 :   va_end (ap);
      49            0 : }
      50              : 
      51              : void
      52            0 : fatal_signal (int signum)
      53              : {
      54            0 :   signal (signum, SIG_DFL);
      55            0 :   utils_cleanup (true);
      56              :   /* Get the same signal again, this time not handled,
      57              :      so its normal effect occurs.  */
      58            0 :   kill (getpid (), signum);
      59            0 : }
      60              : 
      61              : /* Setup the signal handlers for the utils. */
      62              : void
      63       106007 : setup_signals (void)
      64              : {
      65              : #ifdef SIGQUIT
      66       106007 :   if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
      67       106007 :     signal (SIGQUIT, fatal_signal);
      68              : #endif
      69       106007 :   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
      70       106002 :     signal (SIGINT, fatal_signal);
      71              : #ifdef SIGALRM
      72       106007 :   if (signal (SIGALRM, SIG_IGN) != SIG_IGN)
      73       106007 :     signal (SIGALRM, fatal_signal);
      74              : #endif
      75              : #ifdef SIGHUP
      76       106007 :   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
      77         2431 :     signal (SIGHUP, fatal_signal);
      78              : #endif
      79       106007 :   if (signal (SIGSEGV, SIG_IGN) != SIG_IGN)
      80       106007 :     signal (SIGSEGV, fatal_signal);
      81       106007 :   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
      82       106007 :     signal (SIGTERM, fatal_signal);
      83              : #ifdef SIGPIPE
      84       106007 :   if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
      85       106007 :     signal (SIGPIPE, fatal_signal);
      86              : #endif
      87              : #ifdef SIGBUS
      88       106007 :   if (signal (SIGBUS, SIG_IGN) != SIG_IGN)
      89       106007 :     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       106007 :   signal (SIGCHLD, SIG_DFL);
      95              : #endif
      96       106007 : }
      97              : 
      98              : /* Wait for a process to finish, and exit if a nonzero status is found.  */
      99              : 
     100              : int
     101       122536 : collect_wait (const char *prog, struct pex_obj *pex)
     102              : {
     103       122536 :   int status;
     104              : 
     105       122536 :   if (!pex_get_status (pex, 1, &status))
     106            0 :     fatal_error (input_location, "cannot get program status: %m");
     107       122536 :   pex_free (pex);
     108              : 
     109       122536 :   if (response_file && !save_temps)
     110              :     {
     111        12253 :       unlink (response_file);
     112        12253 :       response_file = NULL;
     113              :     }
     114              : 
     115       122536 :   if (status)
     116              :     {
     117          131 :       if (WIFSIGNALED (status))
     118              :         {
     119            0 :           int sig = WTERMSIG (status);
     120            0 :           fatal_error (input_location, "%s terminated with signal %d [%s]%s",
     121              :                        prog, sig, strsignal (sig),
     122            0 :                        WCOREDUMP (status) ? ", core dumped" : "");
     123              :         }
     124              : 
     125          131 :       if (WIFEXITED (status))
     126          131 :         return WEXITSTATUS (status);
     127              :     }
     128              :   return 0;
     129              : }
     130              : 
     131              : void
     132        28731 : do_wait (const char *prog, struct pex_obj *pex)
     133              : {
     134        28731 :   int ret = collect_wait (prog, pex);
     135        28731 :   if (ret != 0)
     136            0 :     fatal_error (input_location, "%s returned %d exit status", prog, ret);
     137        28731 : }
     138              : 
     139              : 
     140              : /* Execute a program, and wait for the reply.  */
     141              : 
     142              : struct pex_obj *
     143       122536 : collect_execute (const char *prog, char **argv, const char *outname,
     144              :                  const char *errname, int flags, bool use_atfile,
     145              :                  const char *atsuffix)
     146              : {
     147       122536 :   struct pex_obj *pex;
     148       122536 :   const char *errmsg;
     149       122536 :   int err;
     150       122536 :   char *response_arg = NULL;
     151       122536 :   char *response_argv[3];
     152              : 
     153       122536 :   if (use_atfile && argv[0] != NULL)
     154              :     {
     155              :       /* If using @file arguments, create a temporary file and put the
     156              :          contents of argv into it.  Then change argv to an array corresponding
     157              :          to a single argument @FILE, where FILE is the temporary filename.  */
     158              : 
     159        12288 :       char **current_argv = argv + 1;
     160        12288 :       char *argv0 = argv[0];
     161        12288 :       int status;
     162        12288 :       FILE *f;
     163              : 
     164              :       /* Note: we assume argv contains at least one element; this is
     165              :          checked above.  */
     166              : 
     167        12288 :       if (!save_temps || !atsuffix || !dumppfx)
     168        12253 :         response_file = make_temp_file ("");
     169              :       else
     170           35 :         response_file = concat (dumppfx, atsuffix, NULL);
     171              : 
     172        12288 :       f = fopen (response_file, "w");
     173              : 
     174        12288 :       if (f == NULL)
     175            0 :         fatal_error (input_location, "could not open response file %s",
     176              :                      response_file);
     177              : 
     178        12288 :       status = writeargv (current_argv, f);
     179              : 
     180        12288 :       if (status)
     181            0 :         fatal_error (input_location, "could not write to response file %s",
     182              :                      response_file);
     183              : 
     184        12288 :       status = fclose (f);
     185              : 
     186        12288 :       if (EOF == status)
     187            0 :         fatal_error (input_location, "could not close response file %s",
     188              :                      response_file);
     189              : 
     190        12288 :       response_arg = concat ("@", response_file, NULL);
     191        12288 :       response_argv[0] = argv0;
     192        12288 :       response_argv[1] = response_arg;
     193        12288 :       response_argv[2] = NULL;
     194              : 
     195        12288 :       argv = response_argv;
     196              :     }
     197              : 
     198       122536 :   if (verbose || debug)
     199              :     {
     200            0 :       char **p_argv;
     201            0 :       const char *str;
     202              : 
     203            0 :       if (argv[0])
     204            0 :         fprintf (stderr, "%s", argv[0]);
     205              :       else
     206            0 :         notice ("[cannot find %s]", prog);
     207              : 
     208            0 :       for (p_argv = &argv[1]; (str = *p_argv) != (char *) 0; p_argv++)
     209            0 :         fprintf (stderr, " %s", str);
     210              : 
     211            0 :       fprintf (stderr, "\n");
     212              :     }
     213              : 
     214       122536 :   fflush (stdout);
     215       122536 :   fflush (stderr);
     216              : 
     217              :   /* If we cannot find a program we need, complain error.  Do this here
     218              :      since we might not end up needing something that we could not find.  */
     219              : 
     220       122536 :   if (argv[0] == 0)
     221            0 :     fatal_error (input_location, "cannot find %qs", prog);
     222              : 
     223       122536 :   pex = pex_init (0, "collect2", NULL);
     224       122536 :   if (pex == NULL)
     225              :     fatal_error (input_location, "%<pex_init%> failed: %m");
     226              : 
     227       122536 :   errmsg = pex_run (pex, flags, argv[0], argv, outname,
     228              :                     errname, &err);
     229       122536 :   if (errmsg != NULL)
     230              :     {
     231            0 :       if (err != 0)
     232              :         {
     233            0 :           errno = err;
     234            0 :           fatal_error (input_location, "%s: %m", _(errmsg));
     235              :         }
     236              :       else
     237            0 :         fatal_error (input_location, errmsg);
     238              :     }
     239              : 
     240       122536 :   free (response_arg);
     241              : 
     242       122536 :   return pex;
     243              : }
     244              : 
     245              : void
     246        16636 : fork_execute (const char *prog, char **argv, bool use_atfile,
     247              :               const char *atsuffix)
     248              : {
     249        16636 :   struct pex_obj *pex;
     250              : 
     251        16636 :   pex = collect_execute (prog, argv, NULL, NULL,
     252              :                          PEX_LAST | PEX_SEARCH, use_atfile, atsuffix);
     253        16636 :   do_wait (prog, pex);
     254        16636 : }
     255              : 
     256              : /* Delete tempfiles.  */
     257              : 
     258              : void
     259        12202 : utils_cleanup (bool from_signal)
     260              : {
     261        12202 :   static bool cleanup_done = false;
     262              : 
     263        12202 :   if (cleanup_done)
     264              :     return;
     265              : 
     266              :   /* Setting cleanup_done prevents an infinite loop if one of the
     267              :      calls to maybe_unlink fails. */
     268        12202 :   cleanup_done = true;
     269              : 
     270        12202 :   tool_cleanup (from_signal);
     271              : }
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.