LCOV - code coverage report
Current view: top level - gcc - collect-utils.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 72.9 % 118 86
Test Date: 2026-06-20 15:32:29 Functions: 77.8 % 9 7
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       110671 : setup_signals (void)
      64              : {
      65              : #ifdef SIGQUIT
      66       110671 :   if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
      67       110671 :     signal (SIGQUIT, fatal_signal);
      68              : #endif
      69       110671 :   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
      70       110666 :     signal (SIGINT, fatal_signal);
      71              : #ifdef SIGALRM
      72       110671 :   if (signal (SIGALRM, SIG_IGN) != SIG_IGN)
      73       110671 :     signal (SIGALRM, fatal_signal);
      74              : #endif
      75              : #ifdef SIGHUP
      76       110671 :   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
      77         2421 :     signal (SIGHUP, fatal_signal);
      78              : #endif
      79       110671 :   if (signal (SIGSEGV, SIG_IGN) != SIG_IGN)
      80       110671 :     signal (SIGSEGV, fatal_signal);
      81       110671 :   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
      82       110671 :     signal (SIGTERM, fatal_signal);
      83              : #ifdef SIGPIPE
      84       110671 :   if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
      85       110671 :     signal (SIGPIPE, fatal_signal);
      86              : #endif
      87              : #ifdef SIGBUS
      88       110671 :   if (signal (SIGBUS, SIG_IGN) != SIG_IGN)
      89       110671 :     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       110671 :   signal (SIGCHLD, SIG_DFL);
      95              : #endif
      96       110671 : }
      97              : 
      98              : /* Wait for a process to finish, and exit if a nonzero status is found.  */
      99              : 
     100              : int
     101       128713 : collect_wait (const char *prog, struct pex_obj *pex)
     102              : {
     103       128713 :   int status;
     104              : 
     105       128713 :   if (!pex_get_status (pex, 1, &status))
     106            0 :     fatal_error (input_location, "cannot get program status: %m");
     107       128713 :   pex_free (pex);
     108              : 
     109       128713 :   if (response_file && !save_temps)
     110              :     {
     111        13718 :       unlink (response_file);
     112        13718 :       response_file = NULL;
     113              :     }
     114              : 
     115       128713 :   if (status)
     116              :     {
     117          132 :       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          132 :       if (WIFEXITED (status))
     126          132 :         return WEXITSTATUS (status);
     127              :     }
     128              :   return 0;
     129              : }
     130              : 
     131              : void
     132        31709 : do_wait (const char *prog, struct pex_obj *pex)
     133              : {
     134        31709 :   int ret = collect_wait (prog, pex);
     135        31709 :   if (ret != 0)
     136            0 :     fatal_error (input_location, "%s returned %d exit status", prog, ret);
     137        31709 : }
     138              : 
     139              : 
     140              : /* Execute a program, and wait for the reply.  */
     141              : 
     142              : struct pex_obj *
     143       128713 : 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       128713 :   struct pex_obj *pex;
     148       128713 :   const char *errmsg;
     149       128713 :   int err;
     150       128713 :   char *response_arg = NULL;
     151       128713 :   char *response_argv[3];
     152              : 
     153       128713 :   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        13753 :       char **current_argv = argv + 1;
     160        13753 :       char *argv0 = argv[0];
     161        13753 :       int status;
     162        13753 :       FILE *f;
     163              : 
     164              :       /* Note: we assume argv contains at least one element; this is
     165              :          checked above.  */
     166              : 
     167        13753 :       if (!save_temps || !atsuffix || !dumppfx)
     168        13718 :         response_file = make_temp_file ("");
     169              :       else
     170           35 :         response_file = concat (dumppfx, atsuffix, NULL);
     171              : 
     172        13753 :       f = fopen (response_file, "w");
     173              : 
     174        13753 :       if (f == NULL)
     175            0 :         fatal_error (input_location, "could not open response file %s",
     176              :                      response_file);
     177              : 
     178        13753 :       status = writeargv (current_argv, f);
     179              : 
     180        13753 :       if (status)
     181            0 :         fatal_error (input_location, "could not write to response file %s",
     182              :                      response_file);
     183              : 
     184        13753 :       status = fclose (f);
     185              : 
     186        13753 :       if (EOF == status)
     187            0 :         fatal_error (input_location, "could not close response file %s",
     188              :                      response_file);
     189              : 
     190        13753 :       response_arg = concat ("@", response_file, NULL);
     191        13753 :       response_argv[0] = argv0;
     192        13753 :       response_argv[1] = response_arg;
     193        13753 :       response_argv[2] = NULL;
     194              : 
     195        13753 :       argv = response_argv;
     196              :     }
     197              : 
     198       128713 :   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       128713 :   fflush (stdout);
     215       128713 :   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       128713 :   if (argv[0] == 0)
     221            0 :     fatal_error (input_location, "cannot find %qs", prog);
     222              : 
     223       128713 :   pex = pex_init (0, "collect2", NULL);
     224       128713 :   if (pex == NULL)
     225              :     fatal_error (input_location, "%<pex_init%> failed: %m");
     226              : 
     227       128713 :   errmsg = pex_run (pex, flags, argv[0], argv, outname,
     228              :                     errname, &err);
     229       128713 :   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       128713 :   free (response_arg);
     241              : 
     242       128713 :   return pex;
     243              : }
     244              : 
     245              : void
     246        18148 : fork_execute (const char *prog, char **argv, bool use_atfile,
     247              :               const char *atsuffix)
     248              : {
     249        18148 :   struct pex_obj *pex;
     250              : 
     251        18148 :   pex = collect_execute (prog, argv, NULL, NULL,
     252              :                          PEX_LAST | PEX_SEARCH, use_atfile, atsuffix);
     253        18148 :   do_wait (prog, pex);
     254        18148 : }
     255              : 
     256              : /* Delete tempfiles.  */
     257              : 
     258              : void
     259        13667 : utils_cleanup (bool from_signal)
     260              : {
     261        13667 :   static bool cleanup_done = false;
     262              : 
     263        13667 :   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        13667 :   cleanup_done = true;
     269              : 
     270        13667 :   tool_cleanup (from_signal);
     271              : }
     272              : 
     273              : /* Return COLLECT_GCC_OPTIONS, expanding an @file reference if present.
     274              :    Returns nullptr if unset.  Result is owned by an internal cache.  */
     275              : 
     276              : const char *
     277       207675 : read_collect_gcc_options (void)
     278              : {
     279       207675 :   static char *cached;
     280              : 
     281       207675 :   if (cached)
     282              :     return cached;
     283              : 
     284       110671 :   const char *raw = getenv ("COLLECT_GCC_OPTIONS");
     285       110671 :   if (raw == nullptr)
     286              :     return nullptr;
     287              : 
     288       110671 :   cached = expandargstr (tool_name, raw);
     289       110671 :   return cached;
     290              : }
        

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.