xref: /netbsd-src/external/gpl3/binutils.old/dist/gprofng/src/count.cc (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2    Contributed by Oracle.
3 
4    This file is part of GNU Binutils.
5 
6    This program 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    This program 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    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 #include "config.h"
22 #include <ctype.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <strings.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <errno.h>
31 #include <i18n.h>
32 #include <Elf.h>
33 #include <collctrl.h>
34 #include <StringBuilder.h>
35 #include "collect.h"
36 
37 /* get_count_data -- format exec of bit to do the real work */
38 void
get_count_data()39 collect::get_count_data ()
40 {
41   char command[8192];
42   char *s;
43   struct stat statbuf;
44 
45   // reserve space for original args, plus 30 arguments to bit
46   nargs = origargc + 30;
47   char **narglist = (char **) calloc (nargs, sizeof (char *));
48   arglist = narglist;
49 
50   // construct the command for bit
51   snprintf (command, sizeof (command), NTXT ("%s"), run_dir);
52   s = strstr_r (command, NTXT ("/bin"));
53   if (s != NULL)
54     {
55       // build command line for launching it
56       snprintf (s, sizeof (command) - (s - command), NTXT ("/lib/compilers/bit"));
57       if (stat (command, &statbuf) == -1)
58 	{
59 	  // if bit command does not exist there
60 	  char *first_look = strdup (command);
61 	  snprintf (command, sizeof (command), NTXT ("%s"), run_dir);
62 	  s = strstr (command, NTXT ("/bin"));
63 	  snprintf (s, sizeof (command) - (s - command), NTXT ("/prod/bin/bit"));
64 	  if (stat (command, &statbuf) == -1)
65 	    {
66 	      // if bit command does not exist
67 	      dbe_write (2, GTXT ("bit is not installed as `%s' or `%s'\nNo experiment is possible\n"), first_look, command);
68 	      exit (2);
69 	    }
70 	  free (first_look);
71 	}
72       *arglist++ = strdup (command);
73     }
74   else
75     {
76       dbe_write (2, GTXT ("collect can't find install bin directory\n"));
77       exit (1);
78     }
79 
80   // Tell it to collect data
81   *arglist++ = NTXT ("collect");
82 
83   // add the flag for real-data vs. static data
84   switch (cc->get_count ())
85     {
86     case -1:
87       *arglist++ = NTXT ("-i");
88       *arglist++ = NTXT ("static");
89       *arglist++ = NTXT ("-M");
90       break;
91     case 1:
92       *arglist++ = NTXT ("-M");
93       *arglist++ = NTXT ("-u");
94       break;
95     default:
96       abort ();
97     }
98 
99   // tell bit to produce an experiment
100   *arglist++ = NTXT ("-e");
101 
102   // now copy an edited list of collect options to the arglist
103   char **oargv = origargv;
104 
105   // skip the "collect"
106   oargv++;
107   int argc = 1;
108   while (argc != targ_index)
109     {
110       char *p = *oargv;
111       switch (p[1])
112 	{
113 	  // pass these arguments along, with parameter
114 	case 'o':
115 	case 'd':
116 	case 'g':
117 	case 'A':
118 	case 'C':
119 	case 'O':
120 	case 'N':
121 	  *arglist++ = *oargv++;
122 	  *arglist++ = *oargv++;
123 	  argc = argc + 2;
124 	  break;
125 	case 'I':
126 	  *arglist++ = *oargv++; // set the -I flag
127 	  *arglist++ = *oargv; // and the directory name
128 	  *arglist++ = NTXT ("-d"); // and the -d flag
129 	  *arglist++ = *oargv++; // to the same directory name
130 	  argc = argc + 2;
131 	  break;
132 	case 'n':
133 	case 'v':
134 	  // pass these arguments along as is
135 	  *arglist++ = *oargv++;
136 	  argc = argc + 1;
137 	  break;
138 	case 'x':
139 	  // skip one argument
140 	  oargv++;
141 	  argc++;
142 	  break;
143 	case 'c':
144 	case 'L':
145 	case 'y':
146 	case 'l':
147 	case 'F':
148 	case 'j':
149 	case 'J':
150 	case 'p':
151 	case 's':
152 	case 'h':
153 	case 'S':
154 	case 'm':
155 	case 'M':
156 	case 'H':
157 	case 'r':
158 	case 'i':
159 	  // skip two arguments
160 	  oargv++;
161 	  oargv++;
162 	  argc = argc + 2;
163 	  break;
164 	case 'R':
165 	case 'Z':
166 	default:
167 	  // these should never get this far
168 	  dbe_write (2, GTXT ("unexpected argument %s\n"), p);
169 	  abort ();
170 	}
171     }
172 
173   // now copy the target and its arguments
174   if (access (prog_name, X_OK) != 0)    // not found
175     *arglist++ = *oargv++;
176   else
177     {
178       oargv++;
179       *arglist++ = prog_name;
180     }
181   while (*oargv != NULL)
182     *arglist++ = *oargv++;
183 
184   /* now we have the full argument list composed; if verbose, print it */
185   if ((verbose == 1) || (disabled))
186     {
187       /* describe the experiment */
188       char *ccret = cc->show (0);
189       if (ccret != NULL)
190 	{
191 	  writeStr (2, ccret);
192 	  free (ccret);
193 	}
194       ccret = cc->show_expt ();
195       if (ccret != NULL)
196 	{
197 	  /* write this to stdout */
198 	  writeStr (1, ccret);
199 	  free (ccret);
200 	}
201       /* print the arguments to bit */
202       arglist = narglist;
203       StringBuilder sb;
204       sb.append (NTXT ("Exec argv[] = "));
205       for (int ret = 0; ret < nargs; ret++)
206 	{
207 	  if (narglist[ret] == NULL)
208 	    break;
209 	  if (ret > 0)
210 	    sb.append (NTXT (" "));
211 	  sb.append (narglist[ret]);
212 	}
213       sb.append (NTXT ("\n\n"));
214       write (2, sb.toString (), sb.length ());
215     }
216 
217   /* check for dry run */
218   if (disabled)
219     exit (0);
220 
221   /* ensure original outputs restored for target */
222   reset_output ();
223 
224   /* now exec the bit to instrument and run the target ... */
225   // (void) execve( *narglist, narglist, origenvp);
226   (void) execvp (*narglist, narglist);
227 
228   /* exec failed; no experiment to delete */
229   /* restore output for collector */
230   set_output ();
231   char *em = strerror (errno);
232   if (em == NULL)
233     dbe_write (2, GTXT ("execve of %s failed: errno = %d\n"), narglist[0], errno);
234   else
235     dbe_write (2, GTXT ("execve of %s failed: %s\n"), narglist[0], em);
236   exit (1);
237 }
238