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 */
38void
39collect::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