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 <stdarg.h>
25#include <stdlib.h>
26#include <strings.h>
27#include <string.h>
28#include <sys/types.h>
29#include <sys/param.h>
30#include <sys/wait.h>
31#include <sys/utsname.h>
32#include <fcntl.h>
33#include <signal.h>
34#include <time.h>
35#include <errno.h>
36#include <sys/ptrace.h>
37
38#include "gp-defs.h"
39#include "cpu_frequency.h"
40#include "util.h"
41#include "collctrl.h"
42#include "hwcdrv.h"
43#include "gp-experiment.h"
44#include "collect.h"
45#include "StringBuilder.h"
46
47#define SP_COLLECTOR_FOUNDER "SP_COLLECTOR_FOUNDER"
48
49extern char **environ;
50
51static volatile int interrupt = 0;
52static int saved_stdout = -1;
53static int  saved_stderr = -1;
54static int no_short_usage = 0;
55static int usage_fd = 2;
56static collect *collect_obj = NULL;
57extern "C" void sigint_handler (int sig, siginfo_t *info, void *context);
58static char *outredirect = NULL;
59static int precheck;
60static int nprocesses;
61static Process **processes;
62
63int
64main (int argc, char *argv[])
65{
66  // disable any alarm that might be pending
67  int r = alarm (0);
68  if (r != 0)
69    dbe_write (2, GTXT ("collect has alarm(%d) pending\n"), r);
70  collect_obj = new collect (argc, argv, environ);
71  collect_obj->start (argc, argv);
72  delete collect_obj;
73  return 0;
74}
75
76extern "C" void
77sigint_handler (int, siginfo_t *, void *)
78{
79  interrupt = 1;
80  if (collect_obj->cc != NULL)
81    collect_obj->cc->interrupt ();
82  return;
83}
84
85extern "C" void
86sigalrm_handler (int, siginfo_t *, void *)
87{
88  dbe_write (2, GTXT ("collect: unexpected alarm clock signal received\n"));
89  return;
90}
91
92extern "C" void
93sigterm_handler (int, siginfo_t *, void *)
94{
95  for (int i = 0; i < nprocesses; i++)
96    {
97      Process *proc = processes[i];
98      if (proc != NULL)
99	kill (proc->pid, SIGTERM);
100    }
101}
102
103collect::collect (int argc, char *argv[], char **envp)
104: Application (argc, argv)
105{
106  verbose = 0;
107  disabled = 0;
108  cc = NULL;
109  collect_warnings = NULL;
110  collect_warnings_idx = 0;
111  int ii;
112  for (ii = 0; ii < MAX_LD_PRELOAD_TYPES; ii++)
113    sp_preload_list[ii] = NULL;
114  for (ii = 0; ii < MAX_LD_PRELOAD_TYPES; ii++)
115    sp_libpath_list[ii] = NULL;
116  java_path = NULL;
117  java_how = NULL;
118  jseen_global = 0;
119  nlabels = 0;
120  origargc = argc;
121  origargv = argv;
122  origenvp = envp;
123  mem_so_me = false;
124}
125
126collect::~collect ()
127{
128  delete cc;
129}
130
131struct sigaction old_sigint_handler;
132struct sigaction old_sigalrm_handler;
133
134void
135collect::start (int argc, char *argv[])
136{
137  char *ccret;
138  char *extype;
139  /* create a collector control structure, disabling aggressive warning */
140  cc = new Coll_Ctrl (0, false, false);
141  if (prog_name)
142    {
143      char *s = strrchr (prog_name, '/');
144      if (s && (s - prog_name) > 5) // Remove /bin/
145	{
146	  s = dbe_sprintf (NTXT ("%.*s"), (int) (s - prog_name - 4), prog_name);
147	  cc->set_project_home (s);
148	  free (s);
149	}
150    }
151  char * errenable = cc->enable_expt ();
152  if (errenable)
153    {
154      writeStr (2, errenable);
155      free (errenable);
156    }
157
158  /* install a handler for SIGALRM */
159  struct sigaction act;
160  memset (&act, 0, sizeof (struct sigaction));
161  sigemptyset (&act.sa_mask);
162  act.sa_handler = (SignalHandler) sigalrm_handler;
163  act.sa_flags = SA_RESTART | SA_SIGINFO;
164  if (sigaction (SIGALRM, &act, &old_sigalrm_handler) == -1)
165    {
166      writeStr (2, GTXT ("Unable to install SIGALRM handler\n"));
167      exit (-1);
168    }
169
170  /* install a handler for SIGINT */
171  sigemptyset (&act.sa_mask);
172  act.sa_handler = (SignalHandler) sigint_handler;
173  act.sa_flags = SA_RESTART | SA_SIGINFO;
174  if (sigaction (SIGINT, &act, &old_sigint_handler) == -1)
175    {
176      writeStr (2, GTXT ("Unable to install SIGINT handler\n"));
177      exit (-1);
178    }
179
180  /* install a handler for SIGTERM */
181  sigemptyset (&act.sa_mask);
182  act.sa_sigaction = sigterm_handler;
183  act.sa_flags = SA_RESTART | SA_SIGINFO;
184  if (sigaction (SIGTERM, &act, NULL) == -1)
185    {
186      writeStr (2, GTXT ("Unable to install SIGTERM handler\n"));
187      exit (-1);
188    }
189  if (argc > 1 && strncmp (argv[1], NTXT ("--whoami="), 9) == 0)
190    {
191      whoami = argv[1] + 9;
192      argc--;
193      argv++;
194    }
195
196  /* check for no arguments -- usage message */
197  if (argc == 1)
198    {
199      verbose = 1;
200      usage_fd = 1;
201      validate_config (0);
202      usage ();
203      exit (0);
204    }
205  else if (argc == 2 && strcmp (argv[1], NTXT ("-h")) == 0)
206    {
207      /* only one argument, -h */
208      verbose = 1;
209      validate_config (0);
210      /* now print the HWC usage message */
211      show_hwc_usage ();
212      exit (0);
213    }
214  else if (argc == 2 && (strcmp (argv[1], NTXT ("-help")) == 0 ||
215			 strcmp (argv[1], NTXT ("--help")) == 0))
216    {
217      /* only one argument, -help or --help */
218      verbose = 1;
219      usage_fd = 1;
220      validate_config (0);
221      usage ();
222      exit (0);
223    }
224// Ruud
225  else if ((argc == 2) &&
226	   (strcmp (argv[1], NTXT ("--version")) == 0))
227    {
228      /* only one argument, --version */
229
230      /* print the version info */
231      Application::print_version_info ();
232      exit (0);
233    }
234
235  /* precheck the arguments -- scan for -O, -M flagS */
236  precheck = 1;
237  targ_index = check_args (argc, argv);
238  if (targ_index < 0)
239    {
240      /* message has already been written */
241      usage_fd = 2;
242      short_usage ();
243      exit (1);
244    }
245  /* crack the arguments */
246  precheck = 0;
247  targ_index = check_args (argc, argv);
248  if (targ_index <= 0)
249    {
250      /* message has already been written */
251      usage_fd = 2;
252      short_usage ();
253      exit (1);
254    }
255  if (targ_index != 0)
256    check_target (argc, argv);
257  if (disabled != 0 && cc->get_count () == 0)
258    {
259      // show collection parameters; count data
260      ccret = cc->show (0);
261      writeStr (1, ccret);
262    }
263
264  // see if Java version should be checked
265  if (cc->get_java_default () == 0 && java_path != NULL)
266    validate_java (java_path, java_how, verbose);
267
268  /* if count data is requested, exec bit to do the real work */
269  /* even for a dryrun */
270  if (cc->get_count () != 0)
271    get_count_data ();
272
273  /* if a dry run, just exit */
274  if (disabled != 0)
275    {
276      writeStr (1, cc->show_expt ());
277      StringBuilder sb;
278      sb.append (GTXT ("Exec argv[] = "));
279      for (int i = 0; i < nargs; i++)
280	sb.appendf (NTXT ("%s "), arglist[i]);
281      sb.append (NTXT ("\n"));
282      char *s = sb.toString ();
283      writeStr (1, s);
284      free (s);
285      exit (0);
286    }
287
288  // If the mem_so_me flag is set, preload mem.so
289  //	and launch the process
290  if (mem_so_me)
291    {
292      /* set env vars for mem.so */
293      if (putenv_memso () != 0)
294	exit (1); /* message has already been written */
295      /* ensure original outputs restored for target */
296      reset_output ();
297
298      /* now exec the target ... */
299      if (cc->get_debug_mode () == 1)
300	{
301	  traceme (arglist[0], arglist);
302	  extype = NTXT ("traceme");
303	}
304      else
305	{
306	  execvp (arglist[0], arglist);
307	  extype = NTXT ("exevcp");
308	}
309      /* oops, exec of the target failed */
310      char *em = strerror (errno);
311      set_output ();    /* restore output for collector */
312      if (em == NULL)
313	dbe_write (2, GTXT ("memso %s of %s failed: errno = %d\n"), extype, argv[targ_index], errno);
314      else
315	dbe_write (2, GTXT ("memso %s of %s failed: %s\n"), extype, argv[targ_index], em);
316      exit (1);
317    }
318
319  /* normal path, setting up an experiment and launching the target */
320  /* set up the experiment */
321  ccret = cc->setup_experiment ();
322  if (ccret != NULL)
323    {
324      dbe_write (2, NTXT ("%s\n"), ccret);
325      free (ccret);
326      exit (1);
327    }
328  /* Beyond this point, the experiment is created */
329  if (collect_warnings != NULL)
330    {
331      warn_open ();
332      for (int i = 0; i < collect_warnings_idx; i++)
333	warn_comment (SP_JCMD_CWARN, COL_WARN_APP_NOT_READY, collect_warnings[i], (int) strlen (collect_warnings[i]));
334      warn_close ();
335    }
336  /* check cpu frequency variation for intel*/
337  unsigned char mode = COL_CPUFREQ_NONE;
338  int max_freq = get_cpu_frequency (&mode);
339  char freq_scaling[256];
340  char turbo_mode[256];
341  *freq_scaling = 0;
342  *turbo_mode = 0;
343  if (mode & COL_CPUFREQ_SCALING)
344    snprintf (freq_scaling, sizeof (freq_scaling), NTXT (" frequency_scaling=\"enabled\""));
345  if (mode & COL_CPUFREQ_TURBO)
346    snprintf (turbo_mode, sizeof (turbo_mode), NTXT (" turbo_mode=\"enabled\""));
347  if (mode != COL_CPUFREQ_NONE)
348    {
349      warn_open ();
350      if (warn_file != NULL)
351	{
352	  warn_write ("<powerm>\n<frequency clk=\"%d\"%s%s/>\n</powerm>\n",
353		      max_freq, freq_scaling, turbo_mode);
354	  warn_close ();
355	}
356    }
357
358  /* check for labels to write to notes file */
359  if (nlabels != 0)
360    {
361      char *nbuf;
362      char nbuf2[MAXPATHLEN];
363      // fetch the experiment name and CWD
364      char *exp = cc->get_experiment ();
365      char *ev = getcwd (nbuf2, sizeof (nbuf2));
366
367      // format the environment variable for the experiment directory name
368      if (ev != NULL && exp[0] != '/')
369	// cwd succeeded, and experiment is a relative path
370	nbuf = dbe_sprintf (NTXT ("%s/%s/%s"), nbuf2, exp, SP_NOTES_FILE);
371      else
372	// getcwd failed or experiment is a fullpath
373	nbuf = dbe_sprintf (NTXT ("%s/%s"), exp, SP_NOTES_FILE);
374
375      FILE *f = fopen (nbuf, NTXT ("w"));
376      free (nbuf);
377      if (f != NULL)
378	{
379	  for (int i = 0; i < nlabels; i++)
380	    fprintf (f, NTXT ("%s\n"), label[i]);
381	  fclose (f);
382	}
383    }
384  /* check for user interrupt */
385  if (interrupt == 1)
386    {
387      cc->delete_expt ();
388      writeStr (2, GTXT ("User interrupt\n"));
389      exit (0);
390    }
391
392  /* print data-collection parameters */
393  if (verbose)
394    {
395      ccret = cc->show (0);
396      if (ccret != NULL)
397	writeStr (2, ccret);
398    }
399  ccret = cc->show_expt ();
400  if (ccret != NULL)
401    writeStr (1, ccret);    /* write this to stdout */
402
403  pid_t pid = (pid_t) cc->get_attach_pid ();
404  if (pid == (pid_t) 0)
405    {
406      /* No attach */
407      /* Set the environment for libcollector */
408      if (putenv_libcollector () != 0)
409	{
410	  /* message has already been written */
411	  cc->delete_expt ();
412	  exit (1);
413	}
414      /* ensure original output fds restored for target */
415      reset_output ();
416
417      /* now exec the target ... */
418      if (cc->get_debug_mode () == 1)
419	{
420	  traceme (arglist[0], arglist);
421	  extype = NTXT ("traceme");
422	}
423      else
424	{
425	  execvp (arglist[0], arglist);
426	  extype = NTXT ("execvp");
427	}
428
429      /* we reach this point only if the target launch failed */
430      char *em = strerror (errno);
431
432      /* restore output for collector */
433      set_output ();
434
435      /* exec failed; delete experiment */
436      cc->delete_expt ();
437
438      /* print a message and exit */
439      if (em == NULL)
440	dbe_write (2, GTXT ("%s of %s failed: errno = %d\n"), extype, argv[targ_index], errno);
441      else
442	dbe_write (2, GTXT ("%s of %s failed: %s\n"), extype, argv[targ_index], em);
443      exit (1);
444    }
445  else
446    abort ();
447}
448
449/**
450 * Prepare a warning message and pass it to warn_write()
451 * @Parameters:
452 * kind Type of comment
453 * num ID
454 * s Comment sting
455 * len Length of the string
456 * @Return: none.
457 */
458void
459collect::warn_comment (const char *kind, int num, char *s, int len)
460{
461  if (len != 0)
462    warn_write (NTXT ("<event kind=\"%s\" id=\"%d\">%.*s</event>\n"),
463		kind, num, len, s);
464  else if (s == NULL)
465    warn_write (NTXT ("<event kind=\"%s\" id=\"%d\"/>\n"), kind, num);
466  else
467    warn_write (NTXT ("<event kind=\"%s\" id=\"%d\">%s</event>\n"), kind, num, s);
468}
469
470/**
471 * Open the warnings file in Append mode ("aw")
472 */
473void
474collect::warn_open ()
475{
476  // open the warnings file
477  warnfilename = dbe_sprintf (NTXT ("%s/%s"), cc->get_experiment (), SP_WARN_FILE);
478  int fd = open (warnfilename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
479  warn_file = fdopen (fd, NTXT ("aw"));
480}
481
482/**
483 * Close the warnings file
484 */
485void
486collect::warn_close ()
487{
488  (void) fclose (warn_file);
489}
490
491/**
492 * Format the warning message and write it to the warnings file
493 */
494void
495collect::warn_write (const char *format, ...)
496{
497  char buf[4096];
498  // format the input arguments into a string
499  va_list va;
500  va_start (va, format);
501  vsnprintf (buf, sizeof (buf), format, va);
502  va_end (va);
503  // write it to the warnings file (warnings.xml)
504  fwrite (buf, 1, strlen (buf), warn_file);
505  fflush (warn_file);
506}
507
508/* process the args, setting expt. params,
509 *	and finding offset for a.out name
510 */
511int
512collect::check_args (int argc, char *argv[])
513{
514  int hseen = 0;
515  int hoffseen = 0;
516  int lseen = 0;
517  int tseen = 0;
518  int pseen = 0;
519  int sseen = 0;
520  int yseen = 0;
521  int Fseen = 0;
522  int Aseen = 0;
523  int Sseen = 0;
524  int Hseen = 0;
525  int iseen = 0;
526  int Jseen = 0;
527  int ofseen = 0;
528  char *expName = NULL;
529  bool overwriteExp = false;
530  char *ccret;
531  char *ccwarn;
532  for (targ_index = 1; targ_index < argc; targ_index++)
533    {
534      if (argv[targ_index] == NULL)
535	break;
536      if (dbe_strcmp (argv[targ_index], "--") == 0)
537	{
538	  targ_index++;
539	  break;
540	}
541      if (argv[targ_index][0] != '-')
542	break;
543      int param;
544      switch (argv[targ_index][1])
545	{
546	case 'y':
547	  {
548	    if (precheck == 1)
549	      {
550		targ_index++;
551		if (argv[targ_index] == NULL)
552		  return 0;
553		break;
554	      }
555	    char *ptr;
556	    int resume = 1;
557	    if (checkflagterm (argv[targ_index]) == -1) return -1;
558	    if (yseen != 0)
559	      {
560		dupflagseen ('y');
561		return -1;
562	      }
563	    yseen++;
564	    targ_index++;
565	    if (argv[targ_index] == NULL)
566	      {
567		writeStr (2, GTXT ("-y requires a signal argument\n"));
568		return -1;
569	      }
570	    if ((ptr = strrchr (argv[targ_index], ',')) != NULL)
571	      {
572		if ((*(ptr + 1) != 'r') || (*(ptr + 2) != 0))
573		  {
574		    /* not the right trailer */
575		    dbe_write (2, GTXT ("Invalid delay signal %s\n"), argv[targ_index]);
576		    return -1;
577		  }
578		resume = 0;
579		*ptr = 0;
580	      }
581	    param = cc->find_sig (argv[targ_index]);
582	    if (param < 0)
583	      {
584		/* invalid signal */
585		dbe_write (2, GTXT ("Invalid delay signal %s\n"), argv[targ_index]);
586		return -1;
587	      }
588	    ccret = cc->set_pauseresume_signal (param, resume);
589	    if (ccret != NULL)
590	      {
591		/* invalid signal; write message */
592		writeStr (2, ccret);
593		return -1;
594	      }
595	    break;
596	  }
597	case 'l':
598	  if (precheck == 1)
599	    {
600	      targ_index++;
601	      if (argv[targ_index] == NULL)
602		return 0;
603	      break;
604	    }
605	  if (checkflagterm (argv[targ_index]) == -1) return -1;
606	  if (lseen != 0)
607	    {
608	      dupflagseen ('l');
609	      return -1;
610	    }
611	  lseen++;
612	  targ_index++;
613	  if (argv[targ_index] == NULL)
614	    {
615	      writeStr (2, GTXT ("-l requires a signal argument\n"));
616	      return -1;
617	    }
618	  param = cc->find_sig (argv[targ_index]);
619	  if (param < 0)
620	    {
621	      /* invalid signal */
622	      dbe_write (2, GTXT ("Invalid sample signal %s\n"), argv[targ_index]);
623	      return -1;
624	    }
625	  ccret = cc->set_sample_signal (param);
626	  if (ccret != NULL)
627	    {
628	      /* invalid signal; write message */
629	      writeStr (2, ccret);
630	      free (ccret);
631	      return -1;
632	    }
633	  break;
634
635#ifdef GPROFNG_DOES_NOT_SUPPORT
636	case 'P':
637	  if (precheck == 1)
638	    {
639	      targ_index++;
640	      if (argv[targ_index] == NULL)
641		return 0;
642	      break;
643	    }
644	  if (checkflagterm (argv[targ_index]) == -1)
645	    return -1;
646	  if (Pseen != 0)
647	    {
648	      dupflagseen ('P');
649	      return -1;
650	    }
651	  Pseen++;
652	  targ_index++;
653	  if (argv[targ_index] == NULL)
654	    {
655	      writeStr (2, GTXT ("-P requires a process pid argument\n"));
656	      return -1;
657	    }
658	  ccret = cc->set_attach_pid (argv[targ_index]);
659	  if (ccret != NULL)
660	    {
661	      /* error; write message */
662	      writeStr (2, ccret);
663	      free (ccret);
664	      return -1;
665	    }
666	  break;
667#endif
668	case 't':
669	  if (precheck == 1)
670	    {
671	      targ_index++;
672	      if (argv[targ_index] == NULL)
673		return 0;
674	      break;
675	    }
676
677	  if (checkflagterm (argv[targ_index]) == -1) return -1;
678	  if (tseen != 0)
679	    {
680	      dupflagseen ('t');
681	      return -1;
682	    }
683	  tseen++;
684	  targ_index++;
685	  if (argv[targ_index] == NULL)
686	    {
687	      writeStr (2, GTXT ("-t requires a run-duration argument\n"));
688	      return -1;
689	    }
690	  ccret = cc->set_time_run (argv[targ_index]);
691	  if (ccret != NULL)
692	    {
693	      /* error; write message */
694	      writeStr (2, ccret);
695	      free (ccret);
696	      return -1;
697	    }
698	  break;
699	case 'p':
700	  {
701	    char *warnmsg;
702	    if (precheck == 1)
703	      {
704		targ_index++;
705		if (argv[targ_index] == NULL)
706		  return 0;
707		break;
708	      }
709	    if (checkflagterm (argv[targ_index]) == -1) return -1;
710	    if (pseen != 0)
711	      {
712		dupflagseen ('p');
713		return -1;
714	      }
715	    pseen++;
716	    targ_index++;
717	    if (argv[targ_index] == NULL)
718	      {
719		writeStr (2, GTXT ("-p requires a clock-profiling argument\n"));
720		return -1;
721	      }
722	    ccret = cc->set_clkprof (argv[targ_index], &warnmsg);
723	    if (ccret != NULL)
724	      {
725		writeStr (2, ccret);
726		free (ccret);
727		return -1;
728	      }
729	    if (warnmsg != NULL)
730	      {
731		writeStr (2, warnmsg);
732		free (warnmsg);
733	      }
734	    break;
735	  }
736	case 's':
737	  if (precheck == 1)
738	    {
739	      targ_index++;
740	      if (argv[targ_index] == NULL)
741		return 0;
742	      break;
743	    }
744	  if (checkflagterm (argv[targ_index]) == -1) return -1;
745	  if (sseen != 0)
746	    {
747	      dupflagseen ('s');
748	      return -1;
749	    }
750	  sseen++;
751	  targ_index++;
752	  if (argv[targ_index] == NULL)
753	    {
754	      writeStr (2, GTXT ("-s requires a synchronization-tracing argument\n"));
755	      return -1;
756	    }
757	  ccret = cc->set_synctrace (argv[targ_index]);
758	  if (ccret != NULL)
759	    {
760	      writeStr (2, ccret);
761	      free (ccret);
762	      return -1;
763	    }
764	  break;
765	case 'h':
766	  {
767	    if (precheck == 1)
768	      {
769		targ_index++;
770		if (argv[targ_index] == NULL)
771		  return 0;
772		break;
773	      }
774	    if (checkflagterm (argv[targ_index]) == -1)
775	      return -1;
776	    targ_index++;
777	    if ((argv[targ_index] == NULL) || (strlen (argv[targ_index]) == 0))
778	      {
779		writeStr (2, GTXT ("-h requires a HW-counter-profiling argument\n"));
780		return -1;
781	      }
782	    // Check for some special cases
783	    char * string = argv[targ_index];
784	    if (strcmp (argv[targ_index], NTXT ("off")) == 0)
785	      {
786		if (hseen != 0)
787		  {
788		    no_short_usage = 1;
789		    writeStr (2, GTXT ("-h off cannot be used with any other -h arguments\n"));
790		    return -1;
791		  }
792		hoffseen = 1;
793		hseen = 1;
794		cc->disable_hwc ();
795		break;
796	      }
797	    // Check to see if we can use HWC
798	    unsigned hwc_maxregs = hwc_get_max_concurrent (false);
799	    if (hwc_maxregs == 0)
800	      {
801		char buf[1024];
802		char *pch = hwcfuncs_errmsg_get (buf, sizeof (buf), 0);
803		if (*pch)
804		  dbe_write (2, GTXT ("HW counter profiling is not supported on this system: %s%s"),
805			     pch, pch[strlen (pch) - 1] == '\n' ? "" : "\n");
806		else
807		  dbe_write (2, GTXT ("HW counter profiling is not supported on this system\n"));
808		no_short_usage = 1;
809		return -1;
810	      }
811	    // Make sure there's no other -h after -h off
812	    if (hoffseen != 0)
813	      {
814		no_short_usage = 1;
815		writeStr (2, GTXT ("No -h arguments can be used after -h off\n"));
816		return -1;
817	      }
818	    // set up to process HW counters (to know about default counters)
819	    cc->setup_hwc ();
820	    hseen++;
821	    char *warnmsg;
822	    if (strcmp (argv[targ_index], NTXT ("on")) == 0)
823	      ccret = cc->add_default_hwcstring ("on", &warnmsg, true);
824	    else if (strcmp (argv[targ_index], NTXT ("hi")) == 0 ||
825		     strcmp (argv[targ_index], NTXT ("high")) == 0)
826	      ccret = cc->add_default_hwcstring ("hi", &warnmsg, true);
827	    else if (strcmp (argv[targ_index], NTXT ("lo")) == 0 ||
828		     strcmp (argv[targ_index], NTXT ("low")) == 0)
829	      ccret = cc->add_default_hwcstring ("lo", &warnmsg, true);
830	    else if (strcmp (argv[targ_index], NTXT ("auto")) == 0)
831	      ccret = cc->add_default_hwcstring ("auto", &warnmsg, true);
832	    else
833	      ccret = cc->add_hwcstring (string, &warnmsg);
834	    if (ccret != NULL)
835	      {
836		/* set global flag to suppress the short_usage message for any subsequent HWC errors */
837		no_short_usage = 1;
838		writeStr (2, ccret);
839		free (ccret);
840		return -1;
841	      }
842	    if (warnmsg != NULL)
843	      {
844		writeStr (2, warnmsg);
845		free (warnmsg);
846	      }
847	    break;
848	  }
849	case 'O':
850	  overwriteExp = true;
851	  ATTRIBUTE_FALLTHROUGH
852	case 'o':
853	  if (precheck == 1)
854	    {
855	      targ_index++;
856	      if (argv[targ_index] == NULL)
857		return 0;
858	      break;
859	    }
860	  if (checkflagterm (argv[targ_index]) == -1)
861	    return -1;
862	  if (argv[targ_index + 1] == NULL)
863	    {
864	      dbe_write (2, GTXT ("Argument %s must be followed by a file name\n"),
865			 argv[targ_index]);
866	      return -1;
867	    }
868	  if (expName != NULL)
869	    {
870	      dbe_write (2, GTXT ("Only one -o or -O argument may be used\n"));
871	      dupflagseen ('o');
872	      return -1;
873	    }
874	  expName = argv[targ_index + 1];
875	  targ_index++;
876	  break;
877	case 'S':
878	  if (precheck == 1)
879	    {
880	      targ_index++;
881	      if (argv[targ_index] == NULL)
882		return 0;
883	      break;
884	    }
885	  if (checkflagterm (argv[targ_index]) == -1) return -1;
886	  if (argv[targ_index + 1] == NULL)
887	    {
888	      dbe_write (2, GTXT ("Argument %s must be followed by a sample interval name\n"),
889			 argv[targ_index]);
890	      return -1;
891	    }
892	  if (Sseen != 0)
893	    {
894	      dupflagseen ('S');
895	      return -1;
896	    }
897	  Sseen++;
898	  ccret = cc->set_sample_period (argv[targ_index + 1]);
899	  if (ccret != NULL)
900	    {
901	      writeStr (2, ccret);
902	      free (ccret);
903	      return -1;
904	    }
905	  targ_index++;
906	  break;
907	case 'H':
908	  if (precheck == 1)
909	    {
910	      targ_index++;
911	      if (argv[targ_index] == NULL)
912		return 0;
913	      break;
914	    }
915	  if (checkflagterm (argv[targ_index]) == -1)
916	    return -1;
917	  if (argv[targ_index + 1] == NULL)
918	    {
919	      dbe_write (2, GTXT ("Argument %s requires a heap-tracing argument\n"),
920			 argv[targ_index]);
921	      return -1;
922	    }
923	  if (Hseen != 0)
924	    {
925	      dupflagseen ('H');
926	      return -1;
927	    }
928	  Hseen++;
929	  ccret = cc->set_heaptrace (argv[targ_index + 1]);
930	  if (ccret != NULL)
931	    {
932	      writeStr (2, ccret);
933	      free (ccret);
934	      return -1;
935	    }
936	  if (cc->get_java_default () == 1)
937	    cc->set_java_mode (NTXT ("off"));
938	  targ_index++;
939	  break;
940	case 'i':
941	  if (precheck == 1)
942	    {
943	      targ_index++;
944	      if (argv[targ_index] == NULL)
945		return 0;
946	      break;
947	    }
948	  if (checkflagterm (argv[targ_index]) == -1)
949	    return -1;
950	  if (argv[targ_index + 1] == NULL)
951	    {
952	      fprintf (stderr, GTXT ("Argument %s requires an I/O-tracing argument\n"),
953		       argv[targ_index]);
954	      return -1;
955	    }
956	  if (iseen != 0)
957	    {
958	      dupflagseen ('i');
959	      return -1;
960	    }
961	  iseen++;
962	  ccret = cc->set_iotrace (argv[targ_index + 1]);
963	  if (ccret != NULL)
964	    {
965	      writeStr (2, ccret);
966	      free (ccret);
967	      return -1;
968	    }
969	  targ_index++;
970	  break;
971	case 'j':
972	  if (precheck == 1)
973	    {
974	      targ_index++;
975	      if (argv[targ_index] == NULL)
976		return 0;
977	      break;
978	    }
979	  if (checkflagterm (argv[targ_index]) == -1) return -1;
980	  if (argv[targ_index + 1] == NULL)
981	    {
982	      dbe_write (2, GTXT ("Argument %s requires a java-profiling argument\n"),
983			 argv[targ_index]);
984	      return -1;
985	    }
986	  if (jseen_global != 0)
987	    {
988	      dupflagseen ('j');
989	      return -1;
990	    }
991	  jseen_global++;
992	  ccret = cc->set_java_mode (argv[targ_index + 1]);
993	  if (ccret != NULL)
994	    {
995	      writeStr (2, ccret);
996	      free (ccret);
997	      return -1;
998	    }
999	  targ_index++;
1000	  break;
1001	case 'J':
1002	  if (precheck == 1)
1003	    {
1004	      targ_index++;
1005	      if (argv[targ_index] == NULL)
1006		return 0;
1007	      break;
1008	    }
1009	  if (checkflagterm (argv[targ_index]) == -1) return -1;
1010	  if (argv[targ_index + 1] == NULL)
1011	    {
1012	      dbe_write (2, GTXT ("Argument %s requires a java argument\n"),
1013			 argv[targ_index]);
1014	      return -1;
1015	    }
1016	  if (Jseen != 0)
1017	    {
1018	      dupflagseen ('J');
1019	      return -1;
1020	    }
1021	  Jseen++;
1022	  ccret = cc->set_java_args (argv[targ_index + 1]);
1023	  if (ccret != NULL)
1024	    {
1025	      writeStr (2, ccret);
1026	      free (ccret);
1027	      return -1;
1028	    }
1029	  targ_index++;
1030	  break;
1031	case 'F':
1032	  if (precheck == 1)
1033	    {
1034	      targ_index++;
1035	      if (argv[targ_index] == NULL)
1036		return 0;
1037	      break;
1038	    }
1039	  if (checkflagterm (argv[targ_index]) == -1)
1040	    return -1;
1041	  if (argv[targ_index + 1] == NULL)
1042	    {
1043	      dbe_write (2, GTXT ("Argument %s requires a descendant-following argument\n"),
1044			 argv[targ_index]);
1045	      return -1;
1046	    }
1047	  if (Fseen != 0)
1048	    {
1049	      dupflagseen ('F');
1050	      return -1;
1051	    }
1052	  Fseen++;
1053	  ccret = cc->set_follow_mode (argv[targ_index + 1]);
1054	  if (ccret != NULL)
1055	    {
1056	      writeStr (2, ccret);
1057	      free (ccret);
1058	      return -1;
1059	    }
1060	  targ_index++;
1061	  break;
1062	case 'a':
1063	  if (precheck == 1)
1064	    {
1065	      targ_index++;
1066	      if (argv[targ_index] == NULL)
1067		return 0;
1068	      break;
1069	    }
1070	  if (checkflagterm (argv[targ_index]) == -1)
1071	    return -1;
1072	  if (argv[targ_index + 1] == NULL)
1073	    {
1074	      dbe_write (2, GTXT ("Argument %s requires a load-object archiving argument\n"),
1075			 argv[targ_index]);
1076	      return -1;
1077	    }
1078	  if (Aseen != 0)
1079	    {
1080	      dupflagseen ('a');
1081	      return -1;
1082	    }
1083	  Aseen++;
1084	  ccret = cc->set_archive_mode (argv[targ_index + 1]);
1085	  if (ccret != NULL)
1086	    {
1087	      writeStr (2, ccret);
1088	      free (ccret);
1089	      return -1;
1090	    }
1091	  targ_index++;
1092	  break;
1093	case 'C':
1094	  if (precheck == 1)
1095	    {
1096	      targ_index++;
1097	      if (argv[targ_index] == NULL)
1098		return 0;
1099	      break;
1100	    }
1101	  if (checkflagterm (argv[targ_index]) == -1)
1102	    return -1;
1103	  if (argv[targ_index + 1] == NULL)
1104	    {
1105	      dbe_write (2, GTXT ("Argument %s must be followed by a comment\n"),
1106			 argv[targ_index]);
1107	      return -1;
1108	    }
1109	  if (nlabels == MAXLABELS)
1110	    {
1111	      dbe_write (2, GTXT ("No more than %d comments may be specified\n"),
1112			 MAXLABELS);
1113	      return -1;
1114	    }
1115	  label[nlabels] = argv[targ_index + 1];
1116	  nlabels++;
1117	  targ_index++;
1118	  break;
1119	case 'n':
1120	case 'v':
1121	case 'V':
1122	  if (precheck == 1)
1123	    break;
1124	  do_flag (&argv[targ_index][1]);
1125	  break;
1126	case 'Z':
1127	  // special undocumented argument for debug builds only to allow analyzer to
1128	  // LD_PRELOAD mem.so for the target it spawns
1129	  mem_so_me = true;
1130	  break;
1131	case '-':
1132	  if (strcmp (argv[targ_index], NTXT ("--verbose")) == 0)
1133	    do_flag ("v");
1134	  else if (strcmp (argv[targ_index], "--outfile") == 0)
1135	    {
1136	      if (precheck == 0)
1137		{
1138		  targ_index++;
1139		  if (argv[targ_index] == NULL)
1140		    return 0;
1141		  break;
1142		}
1143	      // process this argument now
1144	      if (argv[targ_index + 1] == NULL)
1145		{
1146		  dbe_write (2, GTXT ("Argument %s requires a file argument\n"),
1147			     argv[targ_index]);
1148		  return -1;
1149		}
1150	      if (ofseen != 0)
1151		{
1152		  dupflagseen (argv[targ_index]);
1153		  return -1;
1154		}
1155	      ofseen++;
1156	      if (outredirect == NULL)
1157		{
1158		  outredirect = argv[targ_index + 1];
1159		  set_output ();
1160		} // else already redirected; ignore with no message
1161	      targ_index++;
1162	    }
1163	  else
1164	    {
1165	      dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), argv[targ_index]);
1166	      return -1;
1167	    }
1168	  break;
1169	default:
1170	  dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), argv[targ_index]);
1171	  return -1;
1172	}
1173    }
1174  if (targ_index >= argc)
1175    return -1;
1176  if (argv[targ_index] == NULL)
1177    {
1178      if (precheck == 1)
1179	return 0;
1180      if (cc->get_attach_pid () != 0)  /* no target is OK, if we're attaching */
1181	return 0;
1182      writeStr (2, GTXT ("Name of target must be specified\n"));
1183      return -1;
1184    }
1185  if (expName)
1186    {
1187      ccwarn = NULL;
1188      ccret = cc->set_expt (expName, &ccwarn, overwriteExp);
1189      if (ccwarn)
1190	{
1191	  writeStr (2, ccwarn);
1192	  free (ccwarn);
1193	}
1194      if (ccret)
1195	{
1196	  writeStr (2, ccret);
1197	  return -1;
1198	}
1199    }
1200  if (cc->get_attach_pid () != 0)
1201    {
1202      writeStr (2, GTXT ("Name of target must not be specified when -P is used\n"));
1203      return -1;
1204    }
1205  return targ_index;
1206}
1207
1208int
1209collect::checkflagterm (const char *c)
1210{
1211  if (c[2] != 0)
1212    {
1213      dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), c);
1214      return -1;
1215    }
1216  return 0;
1217}
1218
1219int
1220collect::do_flag (const char *flags)
1221{
1222  char *s;
1223  for (int i = 0;; i++)
1224    {
1225      switch (flags[i])
1226	{
1227	case 0: // end of string
1228	  return 0;
1229	case 'n':
1230	  disabled = 1;
1231	  if (verbose != 1)
1232	    {
1233// Ruud
1234	      Application::print_version_info ();
1235/*
1236	      dbe_write (2, NTXT ("GNU %s version %s\n"),
1237			 get_basename (prog_name), VERSION);
1238*/
1239	      verbose = 1;
1240	    }
1241	  break;
1242	case 'x':
1243	  s = cc->set_debug_mode (1);
1244	  if (s)
1245	    {
1246	      writeStr (2, s);
1247	      free (s);
1248	    }
1249	  break;
1250	case 'v':
1251	  if (verbose != 1)
1252	    {
1253// Ruud
1254	      Application::print_version_info ();
1255/*
1256	      dbe_write (2, NTXT ("GNU %s version %s\n"),
1257			 get_basename (prog_name), VERSION);
1258*/
1259	      verbose = 1;
1260	    }
1261	  break;
1262	case 'V':
1263// Ruud
1264	  Application::print_version_info ();
1265/*
1266	  dbe_write (2, NTXT ("GNU %s version %s\n"),
1267		     get_basename (prog_name), VERSION);
1268*/
1269	  /* no further processing.... */
1270	  exit (0);
1271	}
1272    }
1273}
1274
1275/*
1276 * traceme - cause the caller to stop at the end of the next exec()
1277 *	 so that a debugger can attach to the new program
1278 *
1279 * Takes same arguments as execvp()
1280 */
1281int
1282collect::traceme (const char *execvp_file, char *const execvp_argv[])
1283{
1284  int ret = -1;
1285  pid_t pid = fork ();
1286  if (pid == 0)
1287    { // child
1288      // child will set up itself to be PTRACE'd, and then exec the target executable
1289      /* reset the SP_COLLECTOR_FOUNDER value to the new pid */
1290      pid_t mypid = getpid ();
1291      char *ev = dbe_sprintf (NTXT ("%s=%d"), SP_COLLECTOR_FOUNDER, mypid);
1292      if (putenv (ev) != 0)
1293	{
1294	  dbe_write (2, GTXT ("fork-child: Can't putenv of \"%s\": run aborted\n"), ev);
1295	  return 1;
1296	}
1297      ptrace (PTRACE_TRACEME, 0, NULL, NULL); // initiate trace
1298      ret = execvp (execvp_file, execvp_argv); // execvp user command
1299      return ret; // execvp failed
1300    }
1301  else if (pid > 0)
1302    { // parent
1303      int status;
1304      if (waitpid (pid, &status, 0) != pid)
1305	{ // wait for execvp to cause signal
1306	  writeStr (2, GTXT ("parent waitpid() failed\n"));
1307	  return -2;
1308	}
1309      if (!WIFSTOPPED (status))
1310	writeStr (2, GTXT ("WIFSTOPPED(status) failed\n"));
1311
1312      // originally, PTRACE_DETACH would send SIGTSTP, but now we do it here:
1313      if (kill (pid, SIGTSTP) != 0)
1314	writeStr (2, GTXT ("kill(pid, SIGTSTP) failed\n"));
1315      if (ptrace (PTRACE_DETACH, pid, NULL, 0) != 0)
1316	{ // detach trace
1317	  writeStr (2, GTXT ("ptrace(PTRACE_DETACH) failed\n"));
1318	  return -4;
1319	}
1320      dbe_write (2, GTXT ("Waiting for attach from debugger: pid=%d\n"), (int) pid);
1321
1322      // wait for an external debugger to attach
1323      if (waitpid (pid, &status, 0) != pid)
1324	{ // keep parent alive until child quits
1325	  writeStr (2, GTXT ("parent final waitpid() failed\n"));
1326	  return -5;
1327	}
1328    }
1329  else
1330    return -1; // fork failed
1331  exit (0);
1332}
1333
1334void
1335collect::dupflagseen (char c)
1336{
1337  dbe_write (2, GTXT ("Only one -%c argument may be used\n"), c);
1338}
1339
1340void
1341collect::dupflagseen (const char *s)
1342{
1343  dbe_write (2, GTXT ("Only one %s argument may be used\n"), s);
1344}
1345
1346int
1347collect::set_output ()
1348{
1349  static int initial = 1;
1350  if (outredirect)
1351    {
1352      int fd = open (outredirect, O_WRONLY | O_CREAT | O_APPEND,
1353		     S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1354      if (fd == -1)
1355	{
1356	  dbe_write (2, GTXT ("Warning: Can't open collector output `%s': %s\n"),
1357		     outredirect, strerror (errno));
1358	}
1359      else
1360	{
1361	  if ((saved_stdout = dup (1)) == -1 || dup2 (fd, 1) == -1)
1362	    dbe_write (2, GTXT ("Warning: Can't divert collector %s: %s\n"),
1363		       NTXT ("stdout"), strerror (errno));
1364	  if ((saved_stderr = dup (2)) == -1 || dup2 (fd, 2) == -1)
1365	    dbe_write (2, GTXT ("Warning: Can't divert collector %s: %s\n"),
1366		       NTXT ("stderr"), strerror (errno));
1367	  close (fd);
1368	  if ((saved_stdout != -1) && (saved_stderr != -1))
1369	    {
1370	      if (initial)
1371		{
1372		  struct timeval tp;
1373		  gettimeofday (&tp, NULL);
1374		  writeStr (2, ctime (&tp.tv_sec));
1375		  initial = 0;
1376		}
1377	      return 1; // diversion in place
1378	    }
1379	}
1380    }
1381  return 0; // no diversion
1382}
1383
1384void
1385collect::reset_output ()
1386{
1387  if (saved_stdout != -1 &&
1388      (dup2 (saved_stdout, 1) == -1 || close (saved_stdout)))
1389    dbe_write (2, GTXT ("Warning: Can't restore collector stdout: %s\n"),
1390	       strerror (errno));
1391  if (saved_stderr != -1 &&
1392      (dup2 (saved_stderr, 2) == -1 || close (saved_stderr)))
1393    dbe_write (2, GTXT ("Warning: Can't restore collector stderr: %s\n"),
1394	       strerror (errno));
1395}
1396
1397void
1398collect::usage ()
1399{
1400
1401/*
1402  Ruud - Isolate this line because it has an argument.  Otherwise it would be at the
1403  end of this long list.
1404*/
1405  printf ( GTXT (
1406    "Usage: gprofng collect app [OPTION(S)] TARGET [TARGET_ARGUMENTS]\n")),
1407
1408/*
1409-------------------------------------------------------------------------------
1410  For a reason I don't understand, the continuation line(s) need to start at
1411  column 26 in order for help2man to do the righ thing. Ruud
1412-------------------------------------------------------------------------------
1413*/
1414  printf ( GTXT (
1415    "\n"
1416    "Collect performance data on the target program. In addition to Program\n"
1417    "Counter PC) sampling, hardware event counters and various tracing options\n"
1418    "are supported.\n"
1419    "\n"
1420    "Options:\n"
1421    "\n"
1422    " --version           print the version number and exit.\n"
1423    " --help              print usage information and exit.\n"
1424    " --verbose {on|off}  enable (on) or disable (off) verbose mode; the default is \"off\".\n"
1425    "\n"
1426    " -p {off|on|lo|hi|<value>}  disable (off) or enable (on) clock-profiling using a default\n"
1427    "                    sampling granularity, or enable clock-profiling implicitly by\n"
1428    "                    setting the sampling granularity (lo, hi, or a specific value\n"
1429    "                    in ms); by default clock profiling is enabled.\n"
1430    "\n"
1431    " -h {<ctr_def>...,<ctr_n_def>}  enable hardware event counter profiling and select\n"
1432    "                    the counter(s); to see the supported counters on this system use\n"
1433    "                    the -h option without other arguments.\n"
1434    "\n"
1435    " -o <exp_name>     specify the name for (and path to) the experiment directory; the\n"
1436    "                    the default path is the current directory.\n"
1437    "\n"
1438    " -O <exp_name>     the same as -o, but unlike the -o option, silently overwrite an\n"
1439    "                    existing experiment directory with the same name.\n"
1440    "\n"
1441    " -C <label>        add up to 10 comment labels to the experiment; comments appear in\n"
1442    "                    the notes section of the header.\n"
1443    "\n"
1444    " -j {on|off|<path>} enable (on), or disable (off) Java profiling when the target\n"
1445    "                     program is a JVM; optionally set the <path> to a non-default JVM;\n"
1446    "                     the default is \"-j on\".\n"
1447    "\n"
1448    " -J <java-args>    specify arguments to the JVM.\n"
1449    "\n"
1450    " -t <duration>[m|s]  specify the duration over which to record data; the default unit\n"
1451    "                      is seconds (s), but can be set to minutes (m).\n"
1452    "\n"
1453    " -n                  dry run; display several run-time settings, but do not run the\n"
1454    "                      target, or collect performance data.\n"
1455    "\n"
1456    " -y <signal>[,r]     specify delayed initialization and a pause/resume signal; by default\n"
1457    "                      the target starts in paused mode; if the optional r keyword is\n"
1458    "                      provided, start in resumed mode.\n"
1459    "\n"
1460    " -F {off|on|=<regex>}  control to follow descendant processes; disable (off), enable (on),\n"
1461    "                        or collect data on all descendant processes whose name matches the\n"
1462    "                        specified regular expression; the default is \"-F on\".\n"
1463    "\n"
1464    " -a {off|on|ldobjects|src|usedldobjects|usedsrc}  specify archiving of binaries and other files;\n"
1465    "                    in addition to disable this feature (off), or enable archiving off all\n"
1466    "                    loadobjects and sources (on), the other options support a more\n"
1467    "                    refined selection. All of these options enable archiving, but the\n"
1468    "                    keyword controls what exactly is selected: all load objects (ldobjects),\n"
1469    "                    all source files (src), the loadobjects asscoiated with a program counter\n"
1470    "                    (usedldobjects), or the source files associated with a program counter\n"
1471    "                    (usedsrc); the default is \"-a ldobjects\".\n"
1472    "\n"
1473    " -S {off|on|<seconds>}  disable (off) or enable (on) periodic sampling of process-wide resource\n"
1474    "                         utilization; by default sampling occurs every second; use the <seconds>\n"
1475    "                         option to change this; the default is \"-S on\".\n"
1476    "\n"
1477    " -l <signal>       specify a signal that will trigger a sample of process-wide resource utilization.\n"
1478    "\n"
1479    " -s <option>[,<API>]  enable synchronization wait tracing; <option> is used to define the specifics\n"
1480    "                       of the tracing (on, off, <threshold>, or all); <API> is used to select the API:\n"
1481    "                       \"n\" selects native/Pthreads, \"j\" selects Java, and \"nj\" selects both;\n"
1482    "                       the default is \"-s off\".\n"
1483    "\n"
1484    " -H {off|on}        disable (off), or enable (on) heap tracing; the default is \"-H off\".\n"
1485    "\n"
1486    " -i {off|on}        disable (off), or enable (on) I/O tracing; the default is \"-i off\".\n"
1487    "\n"
1488    "Documentation:\n"
1489    "\n"
1490    "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
1491    "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
1492    "should give you access to this document.\n"
1493    "\n"
1494    "See also:\n"
1495    "\n"
1496    "gprofng(1), gp-archive(1), gp-display-html(1), gp-display-src(1), gp-display-text(1)\n"));
1497/*
1498  char *s = dbe_sprintf (GTXT ("Usage:  %s <args> target <target-args>\n"),
1499			 whoami);
1500  writeStr (usage_fd, s);
1501  free (s);
1502  writeStr (usage_fd, GTXT ("  -p {lo|on|hi|off|<value>}\tspecify clock-profiling\n"));
1503  writeStr (usage_fd, GTXT ("\t`lo'    per-thread rate of ~10 samples/second\n"));
1504  writeStr (usage_fd, GTXT ("\t`on'    per-thread rate of ~100 samples/second (default)\n"));
1505  writeStr (usage_fd, GTXT ("\t`hi'    per-thread rate of ~1000 samples/second\n"));
1506  writeStr (usage_fd, GTXT ("\t`off'   disable clock profiling\n"));
1507  writeStr (usage_fd, GTXT ("\t<value> specify profile timer period in millisec.\n"));
1508  s = dbe_sprintf (GTXT ("\t\t\tRange on this system is from %.3f to %.3f millisec.\n\t\t\tResolution is %.3f millisec.\n"),
1509		   (double) cc->get_clk_min () / 1000.,
1510		   (double) cc->get_clk_max () / 1000.,
1511		   (double) cc->get_clk_res () / 1000.);
1512  writeStr (usage_fd, s);
1513  free (s);
1514  writeStr (usage_fd, GTXT ("  -h <ctr_def>...[,<ctr_n_def>]\tspecify HW counter profiling\n"));
1515  s = dbe_sprintf (GTXT ("\tto see the supported HW counters on this machine, run \"%s -h\" with no other arguments\n"),
1516		   whoami);
1517  writeStr (usage_fd, s);
1518  free (s);
1519  writeStr (usage_fd, GTXT ("  -s <threshold>[,<scope>]\tspecify synchronization wait tracing\n"));
1520  writeStr (usage_fd, GTXT ("\t<scope> is \"j\" for tracing Java-APIs, \"n\" for tracing native-APIs, or \"nj\" for tracing both\n"));
1521  writeStr (usage_fd, GTXT ("  -H {on|off}\tspecify heap tracing\n"));
1522  writeStr (usage_fd, GTXT ("  -i {on|off}\tspecify I/O tracing\n"));
1523  writeStr (usage_fd, GTXT ("  -N <lib>\tspecify library to exclude count from instrumentation (requires -c also)\n"));
1524  writeStr (usage_fd, GTXT ("          \tmultiple -N arguments can be provided\n"));
1525  writeStr (usage_fd, GTXT ("  -j {on|off|path}\tspecify Java profiling\n"));
1526  writeStr (usage_fd, GTXT ("  -J <java-args>\tspecify arguments to Java for Java profiling\n"));
1527  writeStr (usage_fd, GTXT ("  -t <duration>\tspecify time over which to record data\n"));
1528  writeStr (usage_fd, GTXT ("  -n\tdry run -- don't run target or collect performance data\n"));
1529  writeStr (usage_fd, GTXT ("  -y <signal>[,r]\tspecify delayed initialization and pause/resume signal\n"));
1530  writeStr (usage_fd, GTXT ("\tWhen set, the target starts in paused mode;\n\t  if the optional r is provided, it starts in resumed mode\n"));
1531  writeStr (usage_fd, GTXT ("  -F {on|off|=<regex>}\tspecify following descendant processes\n"));
1532  writeStr (usage_fd, GTXT ("  -a {on|ldobjects|src|usedldobjects|usedsrc|off}\tspecify archiving of binaries and other files;\n"));
1533  writeStr (usage_fd, GTXT ("  -S {on|off|<seconds>}\t Set the interval for periodic sampling of process-wide resource utilization\n"));
1534  writeStr (usage_fd, GTXT ("  -l <signal>\tspecify signal that will trigger a sample of process-wide resource utilization\n"));
1535  writeStr (usage_fd, GTXT ("  -o <expt>\tspecify experiment name\n"));
1536  writeStr (usage_fd, GTXT ("  --verbose\tprint expanded log of processing\n"));
1537  writeStr (usage_fd, GTXT ("  -C <label>\tspecify comment label (up to 10 may appear)\n"));
1538  writeStr (usage_fd, GTXT ("  -V|--version\tprint version number and exit\n"));
1539*/
1540  /* don't document this feature */
1541  //	writeStr (usage_fd, GTXT("  -Z\tPreload mem.so, and launch target [no experiment]\n") );
1542/*
1543  writeStr (usage_fd, GTXT ("\n See the gp-collect(1) man page for more information\n"));
1544*/
1545
1546#if 0
1547  /* print an extended usage message */
1548  /* find a Java for Java profiling, set Java on to check Java */
1549  find_java ();
1550  cc->set_java_mode (NTXT ("on"));
1551
1552  /* check for variable-clock rate */
1553  unsigned char mode = COL_CPUFREQ_NONE;
1554  get_cpu_frequency (&mode);
1555  if (mode != COL_CPUFREQ_NONE)
1556    writeStr (usage_fd, GTXT ("NOTE: system has variable clock frequency, which may cause variable program run times.\n"));
1557
1558  /* show the experiment that would be run */
1559  writeStr (usage_fd, GTXT ("\n Default experiment:\n"));
1560  char *ccret = cc->setup_experiment ();
1561  if (ccret != NULL)
1562    {
1563      writeStr (usage_fd, ccret);
1564      free (ccret);
1565      exit (1);
1566    }
1567  cc->delete_expt ();
1568  ccret = cc->show (1);
1569  if (ccret != NULL)
1570    {
1571      writeStr (usage_fd, ccret);
1572      free (ccret);
1573    }
1574#endif
1575}
1576
1577void
1578collect::short_usage ()
1579{
1580  if (no_short_usage == 0)
1581    dbe_write (usage_fd, GTXT ("Run \"%s --help\" for a usage message.\n"), whoami);
1582}
1583
1584void
1585collect::show_hwc_usage ()
1586{
1587  usage_fd = 1;
1588  short_usage ();
1589  cc->setup_hwc ();
1590  hwc_usage (false, whoami, NULL);
1591}
1592
1593void
1594collect::writeStr (int f, const char *buf)
1595{
1596  if (buf != NULL)
1597    write (f, buf, strlen (buf));
1598}
1599