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 <unistd.h>     // isatty
23 
24 #include "gp-print.h"
25 #include "ipcio.h"
26 #include "Command.h"
27 #include "Dbe.h"
28 #include "DbeApplication.h"
29 #include "DbeSession.h"
30 #include "Experiment.h"
31 #include "Emsg.h"
32 #include "DbeView.h"
33 #include "DataObject.h"
34 #include "Function.h"
35 #include "Hist_data.h"
36 #include "PathTree.h"
37 #include "LoadObject.h"
38 #include "Function.h"
39 #include "FilterSet.h"
40 #include "Filter.h"
41 #include "MetricList.h"
42 #include "MemorySpace.h"
43 #include "Module.h"
44 #include "util.h"
45 #include "i18n.h"
46 #include "StringBuilder.h"
47 #include "debug.h"
48 #include "UserLabel.h"
49 
50 static char *exe_name;
51 static char **new_argv;
52 
53 void
reexec()54 reexec ()
55 {
56   if (dbeSession != NULL)
57     dbeSession->unlink_tmp_files ();
58   execv (exe_name, new_argv);
59 }
60 
61 /**
62  * Run application under enhance if the following requirements are satisfied:
63  * 1. Environment variable GPROFNG_ENHANCE is not set to "no"
64  * 2. Standard input is terminal
65  * 3. Standard output is terminal
66  * 4. /bin/enhance exists and can work on this system
67  */
68 static void
reexec_enhance(int argc,char * argv[])69 reexec_enhance (int argc, char *argv[])
70 {
71   char *gp_enhance = getenv ("GPROFNG_ENHANCE");
72   if (NULL != gp_enhance && 0 == strcasecmp (gp_enhance, "no"))
73     return; // Do not enhance
74   // Verify that input and output are tty
75   if (!isatty (fileno (stdin)))     // stdin is not a terminal
76     return; // Do not enhance
77   if (!isatty (fileno (stdout)))    // stdout is not a terminal
78     return; // Do not enhance
79   char *enhance_name = NTXT ("/bin/enhance");
80   struct stat sbuf;
81   int res = stat (enhance_name, &sbuf); // Check if enhance exists
82   if (res == 0)
83     res = system (NTXT ("/bin/enhance /bin/true")); // Check if enhance can work
84   if (res != 0)
85     {
86       fflush (stdout);
87       printf (GTXT ("Warning: History and command editing is not supported on this system.\n"));
88       fflush (stdout);
89       return;
90     }
91   else
92     {
93       printf (GTXT ("Note: History and command editing is supported on this system.\n"));
94       fflush (stdout);
95     }
96   char **nargv = new char*[argc + 2];
97   for (int i = 0; i < argc; i++)
98     nargv[i + 1] = argv[i];
99   nargv[0] = enhance_name;
100   nargv[argc + 1] = NULL;
101   putenv (NTXT ("GPROFNG_ENHANCE=no")); // prevent recursion
102   execv (enhance_name, nargv);
103   // execv failed. Continue to run the program
104   delete[] nargv;
105 }
106 
107 int
main(int argc,char * argv[])108 main (int argc, char *argv[])
109 {
110   er_print *erprint;
111   int ind = 1;
112   if (argc > ind && *argv[ind] == '-')
113     {
114       int arg_count, cparam;
115       if (Command::get_command (argv[ind] + 1, arg_count, cparam) == WHOAMI)
116 	ind = ind + 1 + arg_count;
117     }
118   if (argc > ind && argv[ind] != NULL && *argv[ind] != '-')
119     reexec_enhance (argc, argv);
120 
121   // Save argv for reexec())
122   exe_name = argv[0];
123   new_argv = argv;
124 
125   if (argc > ind && argv[ind] != NULL && strcmp (argv[ind], "-IPC") == 0)
126     {
127       putenv (NTXT ("LC_NUMERIC=C")); // Use non-localized numeric data in IPC packets
128       erprint = new er_print (argc, argv);
129       theDbeApplication->rdtMode = false;
130       ipc_mainLoop (argc, argv);
131     }
132   else
133     {
134       erprint = new er_print (argc, argv);
135       erprint->start (argc, argv);
136     }
137 
138   dbeSession->unlink_tmp_files ();
139   if (DUMP_CALL_STACK)
140     {
141       extern long total_calls_add_stack, total_stacks, total_nodes, call_stack_size[201];
142       fprintf (stderr, NTXT ("total_calls_add_stack=%lld\ntotal_stacks=%lld\ntotal_nodes=%lld\n"),
143 	       (long long) total_calls_add_stack, (long long) total_stacks, (long long) total_nodes);
144       for (int i = 0; i < 201; i++)
145 	if (call_stack_size[i] != 0)
146 	    fprintf (stderr, NTXT ("   call_stack_size[%d] = %6lld\n"), i,
147 		     (long long) call_stack_size[i]);
148     }
149 #if defined(DEBUG)
150   delete erprint;
151 #endif
152   return 0;
153 }
154 
er_print(int argc,char * argv[])155 er_print::er_print (int argc, char *argv[])
156 : DbeApplication (argc, argv)
157 {
158   out_fname = GTXT ("<stdout>");
159   inp_file = stdin;
160   out_file = stdout;
161   dis_file = stdout;
162   cov_string = NULL;
163   limit = 0;
164   cstack = new Vector<Histable*>();
165   was_QQUIT = false;
166 }
167 
~er_print()168 er_print::~er_print ()
169 {
170   free (cov_string);
171   delete cstack;
172   if (inp_file != stdin)
173     fclose (inp_file);
174 }
175 
176 void
start(int argc,char * argv[])177 er_print::start (int argc, char *argv[])
178 {
179   Vector<String> *res = theDbeApplication->initApplication (NULL, NULL, NULL);
180   res->destroy ();
181   delete res;
182 
183   // Create a view on the session
184   dbevindex = dbeSession->createView (0, -1);
185   dbev = dbeSession->getView (dbevindex);
186   limit = dbev->get_limit ();
187   (void) check_args (argc, argv);
188   int ngood = dbeSession->ngoodexps ();
189   if (ngood == 0)
190     {
191       fprintf (stderr, GTXT ("No valid experiments loaded; exiting\n"));
192       return;
193     }
194   dbeDetectLoadMachineModel (dbevindex);
195   run (argc, argv);
196 }
197 
198 bool
free_memory_before_exit()199 er_print::free_memory_before_exit ()
200 {
201   return was_QQUIT;
202 }
203 
204 void
usage()205 er_print::usage ()
206 {
207 
208 /*
209   Ruud - Isolate this line because it has an argument.  Otherwise it would be at the
210   end of the long option list.
211 */
212   printf ( GTXT (
213     "Usage: gprofng display text [OPTION(S)] [COMMAND(S)] [-script <script_file>] EXPERIMENT(S)\n"));
214 
215   printf ( GTXT (
216     "\n"
217     "Print a plain text version of the various displays supported by gprofng.\n"
218     "\n"
219     "Options:\n"
220     "\n"
221     " --version           print the version number and exit.\n"
222     " --help              print usage information and exit.\n"
223     " --verbose {on|off}  enable (on) or disable (off) verbose mode; the default is \"off\".\n"
224     "\n"
225     " -script <script-file>  execute the commands stored in the script file;\n"
226     "                        this feature may be combined with commands specified\n"
227     "                        at the command line.\n"
228     "\n"
229     "Commands:\n"
230     "\n"
231     "This tool supports a rich set of commands to control the display of the\n"
232     "data; instead of, or in addition to, including these commands in a script\n"
233     "file, it is also allowed to include such commands at the command line;\n"
234     "in this case, the commands need to be prepended with the \"-\" symbol; the\n"
235     "commands are processed and interpreted left from right, so the order matters;\n"
236     "The gprofng manual documents the commands that are supported.\n"
237     "\n"
238     "If this tool is invoked without options, commands, or a script file, it starts\n"
239     "in interpreter mode. The user can then issue the commands interactively; the\n"
240     "session is terminated with the \"exit\" command in the interpreter.\n"
241     "\n"
242     "Documentation:\n"
243     "\n"
244     "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
245     "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
246     "should give you access to this document.\n"
247     "\n"
248     "See also:\n"
249     "\n"
250     "gprofng(1), gp-archive(1), gp-collect-app(1), gp-display-html(1), gp-display-src(1)\n"));
251 }
252 
253 int // returns count of experiments read
check_args(int argc,char * argv[])254 er_print::check_args (int argc, char *argv[])
255 {
256   CmdType cmd_type;
257   int arg_count;
258   int cparam;
259   int exp_no;
260   error_msg = NULL;
261 
262   Emsg *rcmsg = fetch_comments ();
263   while (rcmsg != NULL)
264     {
265       fprintf (stderr, NTXT ("%s: %s\n"), prog_name, rcmsg->get_msg ());
266       rcmsg = rcmsg->next;
267     }
268   delete_comments ();
269 
270   // Set up the list of experiments to add after checking the args
271   Vector<Vector<char*>*> *exp_list = new Vector<Vector<char*>*>();
272 
273   // Prescan the command line arguments, processing only a few
274   for (int i = 1; i < argc; i++)
275     {
276       if (*argv[i] != '-')
277 	{
278 	  // we're at the end -- get the list of experiments
279 	  //  Build the list of experiments, and set the searchpath
280 	  Vector<char*> *list = dbeSession->get_group_or_expt (argv[i]);
281 	  if (list->size () > 0)
282 	    {
283 	      for (int j = 0, list_sz = list->size (); j < list_sz; j++)
284 		{
285 		  char *path = list->fetch (j);
286 		  if (strlen (path) == 0 || strcmp (path, NTXT ("\\")) == 0)
287 		    continue;
288 		  char *p = strrchr (path, '/');
289 		  if (p)
290 		    {
291 		      // there's a directory in front of the name; add it to search path
292 		      *p = '\0';
293 		      dbeSession->set_search_path (path, false);
294 		    }
295 		}
296 	      list->destroy ();
297 	      list->append (dbe_strdup (argv[i]));
298 	      exp_list->append (list);
299 	    }
300 	  else
301 	    delete list;
302 	  continue;
303 	}
304 
305       // Not at the end yet, treat the next argument as a command
306       switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam))
307 	{
308 	case WHOAMI:
309 	  whoami = argv[i] + 1 + cparam;
310 	  break;
311 	case HELP:
312 	  if (i + 1 + arg_count == argc)
313 	    {
314 	      usage();
315 	      exit (0);
316 	    }
317 	  break;
318 	case HHELP:
319 	  Command::print_help (whoami, true, false, stdout);
320 	  fprintf (stdout, "\n");
321 	  indxo_list (false, stdout);
322 	  fprintf (stdout, "\n");
323 	  mo_list (false, stdout);
324 	  if (!getenv ("_BUILDING_MANPAGE"))
325 	    fprintf (stdout, GTXT ("\nSee gprofng(1) for more details\n"));
326 	  exit (0);
327 	case ADD_EXP:
328 	case DROP_EXP:
329 	case OPEN_EXP:
330 	  printf (GTXT ("Error: command %s can not appear on the command line\n"), argv[i]);
331 	  exit (2);
332 	case VERSION_cmd:
333 	  Application::print_version_info ();
334 	  exit (0);
335 	case AMBIGUOUS_CMD:
336 	  fprintf (stderr, GTXT ("Error: Ambiguous command: %s\n"), argv[i]);
337 	  exit (2);
338 	case UNKNOWN_CMD:
339 	  fprintf (stderr, GTXT ("Error: Invalid command: %s\n"), argv[i]);
340 	  exit (2);
341 	  // it's a plausible argument; see if we process now or later
342 	case SOURCE:
343 	case DISASM:
344 	case CSINGLE:
345 	case CPREPEND:
346 	case CAPPEND:
347 	case FSINGLE:
348 	case SAMPLE_DETAIL:
349 	case STATISTICS:
350 	case HEADER:
351 	  //skip the arguments to that command
352 	  i += arg_count;
353 	  if (i >= argc || end_command (argv[i]))
354 	    i--;
355 	  break;
356 	case PRINTMODE:
357 	case INDXOBJDEF:
358 	case ADDPATH:
359 	case SETPATH:
360 	case PATHMAP:
361 	case OBJECT_SHOW:
362 	case OBJECT_HIDE:
363 	case OBJECT_API:
364 	case OBJECTS_DEFAULT:
365 	case EN_DESC:
366 	  // these are processed in the initial pass over the arguments
367 	  proc_cmd (cmd_type, cparam, (arg_count > 0) ? argv[i + 1] : NULL,
368 		    (arg_count > 1) ? argv[i + 2] : NULL,
369 		    (arg_count > 2) ? argv[i + 3] : NULL,
370 		    (arg_count > 3) ? argv[i + 4] : NULL);
371 	  i += arg_count;
372 	  break;
373 	default:
374 	  // any others, we skip for now
375 	  i += arg_count;
376 	  break;
377 	}
378     }
379 
380   // Make sure some experiments were specified
381   exp_no = exp_list->size ();
382   if (exp_no == 0)
383     { // no experiment name
384       fprintf (stderr, GTXT ("%s: Missing experiment directory (use the --help option to get a usage overview)\n"), whoami);
385       exit (1);
386     }
387 
388   // add the experiments to the session
389   char *errstr = dbeOpenExperimentList (0, exp_list, false);
390   for (long i = 0; i < exp_list->size (); i++)
391     {
392       Vector<char*>* p = exp_list->get (i);
393       Destroy (p);
394     }
395   delete exp_list;
396   if (errstr != NULL)
397     {
398       fprintf (stderr, NTXT ("%s"), errstr);
399       free (errstr);
400     }
401 
402   return exp_no;
403 }
404 
405 int
is_valid_seg_name(char * lo_name,int prev)406 er_print::is_valid_seg_name (char *lo_name, int prev)
407 {
408   // prev is the loadobject segment index that was last returned
409   // search starts following that loadobject
410   int index;
411   LoadObject *lo;
412   char *p_lo_name = lo_name;
413   char *name = NULL;
414 
415   // strip angle brackets from all but <Unknown> and <Total>
416   if (strcmp (lo_name, "<Unknown>") && strcmp (lo_name, "<Total>"))
417     {
418       if (*lo_name == '<')
419 	{
420 	  name = dbe_strdup (lo_name + 1);
421 	  p_lo_name = name;
422 	  char *p = strchr (name, '>');
423 	  if (p)
424 	    *p = '\0';
425 	}
426     }
427 
428   // get the load object list from the session
429   Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
430   Vec_loop (LoadObject*, lobjs, index, lo)
431   {
432     if (prev > 0)
433       {
434 	if (lo->seg_idx == prev)    // this is where we left off
435 	  prev = -1;
436 	continue;
437       }
438 
439     // does this one match?
440     if (cmp_seg_name (lo->get_pathname (), p_lo_name))
441       {
442 	delete lobjs;
443 	free (name);
444 	size_t len = strlen (lo_name);
445 	if ((len > 7 && streq (lo_name + len - 7, NTXT (".class>"))) ||
446 	    (len > 6 && streq (lo_name + len - 6, NTXT (".class"))))
447 	  {
448 	    fprintf (stderr, GTXT ("Error: Java class `%s' is not selectable\n"), lo_name);
449 	    return -1;
450 	  }
451 	return lo->seg_idx;
452       }
453   }
454   delete lobjs;
455   free (name);
456   return -1;
457 }
458 
459 int
cmp_seg_name(char * full_name,char * lo_name)460 er_print::cmp_seg_name (char *full_name, char *lo_name)
461 {
462   char *cmp_name;
463   if (!strchr (lo_name, '/') && (cmp_name = strrchr (full_name, '/')))
464     cmp_name++; // basename
465   else
466     cmp_name = full_name; // full path name
467   return !strcmp (lo_name, cmp_name);
468 }
469 
470 // processing object_select
471 //	Note that this does not affect the strings in Settings,
472 //	unlike object_show, object_hide, and object_api
473 int
process_object_select(char * names)474 er_print::process_object_select (char *names)
475 {
476   int index;
477   LoadObject *lo;
478   int no_lobj = 0;
479   bool got_err = false;
480   Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
481   if ((names == NULL) || !strcasecmp (names, Command::ALL_CMD))
482     { // full coverage
483       Vec_loop (LoadObject*, lobjs, index, lo)
484       {
485 	dbev->set_lo_expand (lo->seg_idx, LIBEX_SHOW);
486       }
487     }
488   else
489     { // parsing coverage
490       // first, hide functions from all loadobjects
491       // except the java ones
492       Vec_loop (LoadObject*, lobjs, index, lo)
493       {
494 	char *lo_name = lo->get_name ();
495 	if (lo_name != NULL)
496 	  {
497 	    size_t len = strlen (lo_name);
498 	    if ((len > 7 && streq (lo_name + len - 7, NTXT (".class>"))) ||
499 		(len > 6 && streq (lo_name + len - 6, NTXT (".class"))))
500 	      continue;
501 	  }
502 	dbev->set_lo_expand (lo->seg_idx, LIBEX_HIDE);
503       }
504 
505       Vector <char *> *tokens = split_str (names, ',');
506       for (long j = 0, sz = VecSize (tokens); j < sz; j++)
507 	{
508 	  // loop over the provided names
509 	  char *lo_name = tokens->get (j);
510 	  int seg_idx = -1;
511 	  seg_idx = is_valid_seg_name (lo_name, seg_idx);
512 	  while (seg_idx != -1)
513 	    {
514 	      dbev->set_lo_expand (seg_idx, LIBEX_SHOW);
515 	      no_lobj++;
516 	      seg_idx = is_valid_seg_name (lo_name, seg_idx);
517 	    }
518 	  if (no_lobj == 0)
519 	    {
520 	      got_err = true;
521 	      fprintf (stderr, GTXT ("Error: Unknown load object: `%s'\n"), lo_name);
522 	    }
523 	  free (lo_name);
524 	}
525       delete tokens;
526     }
527 
528   if (!got_err)
529     { // good coverage string
530       free (cov_string);
531       cov_string = strdup (names);
532     }
533   else
534     { // bad, restore original coverage
535       no_lobj = -1;
536       process_object_select (cov_string);
537     }
538   delete lobjs;
539   return no_lobj;
540 }
541 
542 int
set_libexpand(char * cov,enum LibExpand expand)543 er_print::set_libexpand (char *cov, enum LibExpand expand)
544 {
545   bool changed = dbev->set_libexpand (cov, expand);
546   if (changed == true)
547     dbev->update_lo_expands ();
548   return 0;
549 }
550 
551 int
set_libdefaults()552 er_print::set_libdefaults ()
553 {
554   dbev->set_libdefaults ();
555   return 0;
556 }
557 
558 bool
end_command(char * cmd)559 er_print::end_command (char *cmd)
560 {
561   if (cmd == NULL || *cmd == '-')
562     return true;
563   size_t len = strlen (cmd);
564   if (cmd[len - 1] == '/')
565     len--;
566   if ((len > 3 && !strncmp (&cmd[len - 3], NTXT (".er"), 3)) ||
567       (len > 4 && !strncmp (&cmd[len - 4], NTXT (".erg"), 4)))
568     return true;
569   return false;
570 }
571 
572 // Now actually start processing the arguments
573 void
run(int argc,char * argv[])574 er_print::run (int argc, char *argv[])
575 {
576   CmdType cmd_type;
577   int arg_count, cparam, i;
578   bool got = false;
579   char *arg1, *arg2;
580   for (i = 1; i < argc; i++)
581     {
582       if (*argv[i] != '-') // open experiment pointer files
583 	continue;
584       switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam))
585 	{
586 	case WHOAMI:
587 	  whoami = argv[i] + 1 + cparam;
588 	  break;
589 	case SCRIPT:
590 	  got = true;
591 	  inp_file = fopen (argv[++i], "r");
592 	  if (inp_file == NULL)
593 	    {
594 	      fprintf (stderr, GTXT ("Error: Script file cannot be opened: %s\n"), argv[i]);
595 	      exit (3);
596 	    }
597 	  proc_script ();
598 	  break;
599 	case STDIN:
600 	  got = true;
601 	  inp_file = stdin;
602 	  proc_script ();
603 	  break;
604 	case SOURCE: // with option arg_count == 2
605 	case DISASM:
606 	  got = true;
607 	  i += arg_count;
608 	  if ((i >= argc) || end_command (argv[i]))
609 	    {
610 	      i--;
611 	      arg1 = argv[i];
612 	      arg2 = NTXT ("");
613 	    }
614 	  else
615 	    {
616 	      arg1 = argv[i - 1];
617 	      arg2 = argv[i];
618 	    }
619 	  proc_cmd (cmd_type, cparam, arg1, arg2, NULL, NULL, true);
620 	  break;
621 	case CSINGLE:
622 	case CPREPEND:
623 	case CAPPEND:
624 	case FSINGLE:
625 	  got = true;
626 	  i += arg_count;
627 	  if ((i >= argc) || end_command (argv[i]))
628 	    {
629 	      i--;
630 	      proc_cmd (cmd_type, cparam, argv[i], NTXT ("1"));
631 	    }
632 	  else
633 	    proc_cmd (cmd_type, cparam, argv[i - 1], argv[i]);
634 	  break;
635 	case SAMPLE_DETAIL: // with option arg_count == 1
636 	case STATISTICS:
637 	case HEADER:
638 	  got = true;
639 	  // now fall through to process the command
640 	case COMPARE:
641 	  got = true;
642 	  i += arg_count;
643 	  if ((i >= argc) || end_command (argv[i]))
644 	    {
645 	      i--;
646 	      proc_cmd (cmd_type, cparam, NULL, NULL);
647 	    }
648 	  else
649 	    proc_cmd (cmd_type, cparam, argv[i], NULL);
650 	  break;
651 	case PRINTMODE:
652 	case INDXOBJDEF:
653 	case ADDPATH:
654 	case SETPATH:
655 	case PATHMAP:
656 	case OBJECT_SHOW:
657 	case OBJECT_HIDE:
658 	case OBJECT_API:
659 	case OBJECTS_DEFAULT:
660 	case EN_DESC:
661 	  got = true;
662 	  // these have been processed already
663 	  i += arg_count;
664 	  break;
665 	case LIMIT:
666 	  got = true;
667 	  proc_cmd (cmd_type, cparam, (arg_count > 0) ? argv[i + 1] : NULL,
668 		    (arg_count > 1) ? argv[i + 2] : NULL);
669 	  i += arg_count;
670 	  break;
671 	default:
672 	  got = true;
673 	  proc_cmd (cmd_type, cparam, (arg_count > 0) ? argv[i + 1] : NULL,
674 		    (arg_count > 1) ? argv[i + 2] : NULL);
675 	  i += arg_count;
676 	  break;
677 	}
678     }
679   if (!got) // no command has been specified
680     proc_script ();
681 }
682 
683 #define MAXARGS 20
684 
685 void
proc_script()686 er_print::proc_script ()
687 {
688   CmdType cmd_type;
689   int arg_count, cparam;
690   char *cmd, *end_cmd;
691   char *script = NULL;
692   char *arglist[MAXARGS];
693   char *line = NULL;
694   int lineno = 0;
695   while (!feof (inp_file))
696     {
697       if (inp_file == stdin)
698 	printf (NTXT ("(%s) "), get_basename (prog_name));
699       free (script);
700       script = read_line (inp_file);
701       if (script == NULL)
702 	continue;
703       free (line);
704       line = dbe_strdup (script);
705       lineno++;
706       for (int i = 0; i < MAXARGS; i++)
707 	arglist[i] = NULL;
708 
709       // ensure it's terminated by a \n, and remove that character
710       strtok (script, NTXT ("\n"));
711 
712       // extract the command
713       cmd = strtok (script, NTXT (" \t"));
714       if (cmd == NULL)
715 	continue;
716       if (*cmd == '#')
717 	{
718 	  fprintf (stderr, NTXT ("%s"), line);
719 	  continue;
720 	}
721       if (*cmd == '\n')
722 	continue;
723 
724       char *remainder = strtok (NULL, NTXT ("\n"));
725       // now extract the arguments
726       int nargs = 0;
727       for (;;)
728 	{
729 	  end_cmd = NULL;
730 	  if (nargs >= MAXARGS)
731 	    fprintf (stderr, GTXT ("Warning: more than %d arguments to %s command, line %d\n"),
732 		     MAXARGS, cmd, lineno);
733 	  char *nextarg = strtok (remainder, NTXT ("\n"));
734 	  if ((nextarg == NULL) || (*nextarg == '#'))
735 	    // either the end of the line, or a comment indicator
736 	    break;
737 	  if (nargs >= MAXARGS)
738 	    {
739 	      parse_qstring (nextarg, &end_cmd);
740 	      nargs++;
741 	    }
742 	  else
743 	    arglist[nargs++] = parse_qstring (nextarg, &end_cmd);
744 	  remainder = end_cmd;
745 	  if (remainder == NULL)
746 	    break;
747 	  // skip any blanks or tabs to get to next argument
748 	  while (*remainder == ' ' || *remainder == '\t')
749 	    remainder++;
750 	}
751 
752       cmd_type = Command::get_command (cmd, arg_count, cparam);
753 
754       // check for extra arguments
755       if (cmd_type != UNKNOWN_CMD && cmd_type != INDXOBJDEF && nargs > arg_count)
756 	fprintf (stderr, GTXT ("Warning: extra arguments to %s command, line %d\n"),
757 		 cmd, lineno);
758       switch (cmd_type)
759 	{
760 	case SOURCE:
761 	case DISASM:
762 	  // ignore any third parameter
763 	  // if there was, we have written a warning
764 	  proc_cmd (cmd_type, cparam, arglist[0], arglist[1], NULL, NULL,
765 		    (inp_file != stdin));
766 	  break;
767 	case QUIT:
768 	  free (script);
769 	  free (line);
770 	  exit (0);
771 	case QQUIT:
772 	  was_QQUIT = true;
773 	  free (script);
774 	  free (line);
775 	  return;
776 	case STDIN:
777 	  break;
778 	case COMMENT:
779 	  fprintf (dis_file, NTXT ("%s"), line);
780 	  break;
781 	case AMBIGUOUS_CMD:
782 	  fprintf (stderr, GTXT ("Error: Ambiguous command: %s\n"), cmd);
783 	  break;
784 	case UNKNOWN_CMD:
785 	  if (*cmd != '\n')
786 	    fprintf (stderr, GTXT ("Error: Invalid command: %s\n"), cmd);
787 	  break;
788 	default:
789 	  proc_cmd (cmd_type, cparam, arglist[0], arglist[1]);
790 	  break;
791 	}
792     }
793   // free up the input line
794   free (script);
795   free (line);
796 }
797 
798 void
proc_cmd(CmdType cmd_type,int cparam,char * arg1,char * arg2,char * arg3,char * arg4,bool xdefault)799 er_print::proc_cmd (CmdType cmd_type, int cparam,
800 		    char *arg1, char *arg2, char *arg3, char *arg4, bool xdefault)
801 {
802   er_print_common_display *cd;
803   FILE *ck_file, *save_file;
804   char *name;
805   int bgn_index, end_index, index;
806   Cmd_status status;
807   char *scratch, *scratch1;
808   switch (cmd_type)
809     {
810     case FUNCS:
811       print_func (Histable::FUNCTION, MODE_LIST,
812 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_list (MET_NORMAL));
813       break;
814     case FDETAIL:
815       print_func (Histable::FUNCTION, MODE_DETAIL,
816 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL));
817       break;
818     case FSINGLE:
819       print_func (Histable::FUNCTION, MODE_DETAIL,
820 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL),
821 		  arg1, arg2);
822       break;
823     case HOTPCS:
824       print_func (Histable::INSTR, MODE_LIST,
825 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_list (MET_NORMAL));
826       break;
827     case PDETAIL:
828       print_func (Histable::INSTR, MODE_DETAIL,
829 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL));
830       break;
831     case HOTLINES:
832       print_func (Histable::LINE, MODE_LIST,
833 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_list (MET_NORMAL));
834       break;
835     case LDETAIL:
836       print_func (Histable::LINE, MODE_DETAIL,
837 		  dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL));
838       break;
839     case OBJECTS:
840       print_objects ();
841       break;
842     case OVERVIEW_NEW:
843       print_overview ();
844       break;
845     case LOADOBJECT:
846       print_segments ();
847       break;
848     case GPROF:
849       print_func (Histable::FUNCTION, MODE_GPROF,
850 		  dbev->get_metric_list (MET_CALL), dbev->get_metric_list (MET_NORMAL));
851       break;
852     case CALLTREE:
853       if (dbev->comparingExperiments ())
854 	{
855 	  fprintf (out_file, GTXT ("\nNot available when comparing experiments\n\n"));
856 	  break;
857 	}
858       print_ctree (cmd_type);
859       break;
860     case CSINGLE:
861     case CPREPEND:
862     case CAPPEND:
863     case CRMFIRST:
864     case CRMLAST:
865       print_gprof (cmd_type, arg1, arg2);
866       break;
867     case EXP_LIST:
868       exp_list ();
869       break;
870     case DESCRIBE:
871       describe ();
872       break;
873     case SCOMPCOM:
874       status = dbev->proc_compcom (arg1, true, false);
875       if (status != CMD_OK)
876 	fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
877       break;
878     case STHRESH:
879       status = dbev->proc_thresh (arg1, true, false);
880       if (status != CMD_OK)
881 	fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
882       break;
883     case DCOMPCOM:
884       status = dbev->proc_compcom (arg1, false, false);
885       if (status != CMD_OK)
886 	fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
887       break;
888     case COMPCOM:
889       status = dbev->proc_compcom (arg1, true, false);
890       if (status != CMD_OK)
891 	fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
892       status = dbev->proc_compcom (arg1, false, false);
893       if (status != CMD_OK)
894 	fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
895       break;
896     case DTHRESH:
897       status = dbev->proc_thresh (arg1, false, false);
898       if (status != CMD_OK)
899 	fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
900       break;
901     case SOURCE:
902     case DISASM:
903       {
904 	if (arg3 != NULL)
905 	  abort ();
906 	if (arg1 == NULL)
907 	  {
908 	    fprintf (stderr, GTXT ("Error: Invalid function/file setting: \n"));
909 	    break;
910 	  }
911 	char *fcontext = NULL;
912 	char *arg = parse_fname (arg1, &fcontext);
913 	if (arg == NULL)
914 	  {
915 	    fprintf (stderr, GTXT ("Error: Invalid function/file setting: %s\n"), arg1);
916 	    free (fcontext);
917 	    break;
918 	  }
919 	if (arg2 && (strlen (arg2) == 0))
920 	  arg2 = NULL;
921 	print_anno_file (arg, arg2, fcontext, cmd_type == DISASM,
922 			 dis_file, inp_file, out_file, dbev, xdefault);
923 	free (arg);
924 	free (fcontext);
925 	break;
926       }
927     case METRIC_LIST:
928       proc_cmd (METRICS, cparam, NULL, NULL);
929       dbev->get_metric_ref (MET_NORMAL)->print_metric_list (dis_file,
930 							    GTXT ("Available metrics:\n"), false);
931       break;
932     case METRICS:
933       if (arg1)
934 	{
935 	  char *ret = dbev->setMetrics (arg1, false);
936 	  if (ret != NULL)
937 	    {
938 	      fprintf (stderr, GTXT ("Error: %s\n"), ret);
939 	      proc_cmd (METRIC_LIST, cparam, NULL, NULL);
940 	      break;
941 	    }
942 	}
943       scratch = dbev->get_metric_list (MET_NORMAL)->get_metrics ();
944       fprintf (dis_file, GTXT ("Current metrics: %s\n"), scratch);
945       free (scratch);
946       proc_cmd (SORT, cparam, NULL, NULL);
947       break;
948     case GMETRIC_LIST:
949       scratch = dbev->get_metric_list (MET_CALL)->get_metrics ();
950       fprintf (dis_file, GTXT ("Current caller-callee metrics: %s\n"), scratch);
951       free (scratch);
952       fprintf (dis_file, GTXT ("Current caller-callee sort Metric: %s\n"),
953 	       dbev->getSort (MET_DATA));
954       break;
955     case INDX_METRIC_LIST:
956       scratch = dbev->get_metric_list (MET_INDX)->get_metrics ();
957       fprintf (dis_file, GTXT ("Current index-object metrics: %s\n"), scratch);
958       free (scratch);
959       scratch = dbev->getSort (MET_INDX);
960       fprintf (dis_file, GTXT ("Current index-object sort Metric: %s\n"), scratch);
961       free (scratch);
962       break;
963     case SORT:
964       if (arg1)
965 	{
966 	  char *ret = dbev->setSort (arg1, MET_NORMAL, false);
967 	  if (ret != NULL)
968 	    {
969 	      fprintf (stderr, GTXT ("Error: %s\n"), ret);
970 	      proc_cmd (METRICS, cparam, NULL, NULL);
971 	      break;
972 	    }
973 	  dbev->setSort (arg1, MET_SRCDIS, false);
974 	  dbev->setSort (arg1, MET_CALL, false);
975 	  dbev->setSort (arg1, MET_DATA, false);
976 	  dbev->setSort (arg1, MET_INDX, false);
977 	  dbev->setSort (arg1, MET_CALL_AGR, false);
978 	  dbev->setSort (arg1, MET_IO, false);
979 	  dbev->setSort (arg1, MET_HEAP, false);
980 	}
981       scratch = dbev->getSort (MET_NORMAL);
982       scratch1 = dbev->getSortCmd (MET_NORMAL);
983       fprintf (dis_file,
984 	       GTXT ("Current Sort Metric: %s ( %s )\n"), scratch, scratch1);
985       free (scratch1);
986       free (scratch);
987       break;
988     case OBJECT_SHOW:
989       if (arg1)
990 	set_libexpand (arg1, LIBEX_SHOW);
991       obj_list ();
992       break;
993     case OBJECT_HIDE:
994       if (arg1)
995 	set_libexpand (arg1, LIBEX_HIDE);
996       obj_list ();
997       break;
998     case OBJECT_API:
999       if (arg1)
1000 	set_libexpand (arg1, LIBEX_API);
1001       obj_list ();
1002       break;
1003     case OBJECTS_DEFAULT:
1004       set_libdefaults ();
1005       obj_list ();
1006       break;
1007     case OBJECT_LIST:
1008       obj_list ();
1009       break;
1010     case OBJECT_SELECT:
1011       if (arg1)
1012 	{
1013 	  if (process_object_select (arg1) != -1)
1014 	    proc_cmd (OBJECT_LIST, cparam, NULL, NULL);
1015 	  else
1016 	    fprintf (stderr, GTXT ("Error: Type \"object_list\" for a list of all load objects.\n"));
1017 	}
1018       else
1019 	fprintf (stderr, GTXT ("Error: No load object has been specified.\n"));
1020       break;
1021     case LOADOBJECT_LIST:
1022       seg_list ();
1023       break;
1024     case LOADOBJECT_SELECT:
1025       if (arg1)
1026 	{
1027 	  if (process_object_select (arg1) != -1)
1028 	    proc_cmd (LOADOBJECT_LIST, cparam, NULL, NULL);
1029 	  else
1030 	    fprintf (stderr, GTXT ("Error: Type \"segment_list\" for a list of all segments.\n"));
1031 	}
1032       else
1033 	fprintf (stderr, GTXT ("Error: No segment has been specified.\n"));
1034       break;
1035     case SAMPLE_LIST:
1036       filter_list (SAMPLE_LIST);
1037       break;
1038     case SAMPLE_SELECT:
1039       if (arg1 && !dbev->set_pattern (SAMPLE_FILTER_IDX, arg1))
1040 	fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
1041       proc_cmd (SAMPLE_LIST, cparam, NULL, NULL);
1042       break;
1043     case THREAD_LIST:
1044       filter_list (THREAD_LIST);
1045       break;
1046     case THREAD_SELECT:
1047       if (arg1 && !dbev->set_pattern (THREAD_FILTER_IDX, arg1))
1048 	fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
1049       proc_cmd (THREAD_LIST, cparam, NULL, NULL);
1050       break;
1051     case LWP_LIST:
1052       filter_list (LWP_LIST);
1053       break;
1054     case LWP_SELECT:
1055       if (arg1 && !dbev->set_pattern (LWP_FILTER_IDX, arg1))
1056 	fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
1057       proc_cmd (LWP_LIST, cparam, NULL, NULL);
1058       break;
1059     case CPU_LIST:
1060       filter_list (CPU_LIST);
1061       break;
1062     case CPU_SELECT:
1063       if (arg1 && !dbev->set_pattern (CPU_FILTER_IDX, arg1))
1064 	fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
1065       proc_cmd (CPU_LIST, cparam, NULL, NULL);
1066       break;
1067     case FILTERS:
1068       if (arg1 != NULL)
1069 	{
1070 	  if (strcmp (arg1, NTXT ("True")) == 0)
1071 	    scratch = dbev->set_filter (NULL);
1072 	  else
1073 	    scratch = dbev->set_filter (arg1);
1074 	  if (scratch != NULL)
1075 	    fprintf (stderr, GTXT ("Error: %s\n"), scratch);
1076 	}
1077       scratch = dbev->get_filter ();
1078       fprintf (dis_file, GTXT ("current filter setting: \"%s\"\n"),
1079 	       scratch == NULL ? GTXT ("<none>") : scratch);
1080       break;
1081     case OUTFILE:
1082       if (arg1)
1083 	{
1084 	  set_outfile (arg1, out_file, false);
1085 	  if (inp_file != stdin)
1086 	    dis_file = out_file;
1087 	}
1088       break;
1089     case APPENDFILE:
1090       if (arg1)
1091 	{
1092 	  set_outfile (arg1, out_file, true);
1093 	  if (inp_file != stdin)
1094 	    dis_file = out_file;
1095 	}
1096       break;
1097     case LIMIT:
1098       if (arg1)
1099 	{
1100 	  limit = (int) strtol (arg1, (char **) NULL, 10);
1101 	  char *res = dbeSetPrintLimit (dbevindex, limit);
1102 	  if (res != NULL)
1103 	    fprintf (stderr, NTXT ("%s\n"), res);
1104 	}
1105 
1106       limit = dbeGetPrintLimit (dbevindex);
1107       fprintf (stderr, GTXT ("Print limit set to %d\n"), limit);
1108       break;
1109     case NAMEFMT:
1110       if (arg1)
1111 	{
1112 	  status = dbev->set_name_format (arg1);
1113 	  if (status != CMD_OK)
1114 	    fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
1115 	}
1116       else
1117 	fprintf (stderr, GTXT ("Error: No format has been specified.\n"));
1118       break;
1119     case VIEWMODE:
1120       {
1121 	if (arg1)
1122 	  {
1123 	    status = dbev->set_view_mode (arg1, false);
1124 	    if (status != CMD_OK)
1125 	      fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
1126 	  }
1127 	const char *vname = "unknown";
1128 	int vm = dbev->get_view_mode ();
1129 	switch (vm)
1130 	  {
1131 	  case VMODE_USER:
1132 	    vname = "user";
1133 	    break;
1134 	  case VMODE_EXPERT:
1135 	    vname = "expert";
1136 	    break;
1137 	  case VMODE_MACHINE:
1138 	    vname = "machine";
1139 	    break;
1140 	  }
1141 	fprintf (stderr, GTXT ("Viewmode set to %s\n"), vname);
1142       }
1143       break;
1144 
1145       // EN_DESC does not make sense after experiments are read, but it does make sense on the command line,
1146       //	processed before the experiments are read.
1147     case EN_DESC:
1148       if (arg1)
1149 	{
1150 	  status = dbev->set_en_desc (arg1, false);
1151 	  if (status != CMD_OK)
1152 	    fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
1153 	}
1154       else
1155 	fprintf (stderr, GTXT ("Error: No descendant processing has been specified.\n"));
1156       break;
1157     case SETPATH:
1158     case ADDPATH:
1159       if (arg1)
1160 	dbeSession->set_search_path (arg1, (cmd_type == SETPATH));
1161       fprintf (dis_file, GTXT ("search path:\n"));
1162       Vec_loop (char*, dbeSession->get_search_path (), index, name)
1163       {
1164 	fprintf (dis_file, NTXT ("\t%s\n"), name);
1165       }
1166       break;
1167     case PATHMAP:
1168       {
1169 	Vector<pathmap_t*> *pathMaps = dbeSession->get_pathmaps ();
1170 	if (arg1 != NULL)
1171 	  {
1172 	    if (arg2 == NULL)
1173 	      {
1174 		fprintf (stderr, GTXT ("Error: No replacement path prefix has been specified.\n"));
1175 		break;
1176 	      }
1177 	    // add this mapping to the session
1178 	    char *err = Settings::add_pathmap (pathMaps, arg1, arg2);
1179 	    if (err != NULL)
1180 	      {
1181 		fprintf (stderr, NTXT ("%s"), err);
1182 		free (err);
1183 	      }
1184 	  }
1185 	fprintf (dis_file, GTXT ("Path mappings: from -> to\n"));
1186 	for (int i = 0, sz = pathMaps->size (); i < sz; i++)
1187 	  {
1188 	    pathmap_t *thismap = pathMaps->get (i);
1189 	    fprintf (dis_file, NTXT ("\t`%s' -> `%s'\n"), thismap->old_prefix, thismap->new_prefix);
1190 	  }
1191       }
1192       break;
1193     case SAMPLE_DETAIL:
1194       if (get_exp_id (arg1, bgn_index, end_index) != -1)
1195 	{
1196 	  cd = new er_print_experiment (dbev, bgn_index, end_index, false,
1197 					false, false, true, true);
1198 	  print_cmd (cd);
1199 	  delete cd;
1200 	}
1201       break;
1202     case STATISTICS:
1203       if (get_exp_id (arg1, bgn_index, end_index) != -1)
1204 	{
1205 	  cd = new er_print_experiment (dbev, bgn_index, end_index, false,
1206 					false, true, true, false);
1207 	  print_cmd (cd);
1208 	  delete cd;
1209 	}
1210       break;
1211     case PRINTMODE:
1212       {
1213 	if (arg1 == NULL)
1214 	  {
1215 	    fprintf (stderr, GTXT ("printmode is set to `%s'\n\n"), dbeGetPrintModeString (dbevindex));
1216 	    break;
1217 	  }
1218 	char *s = dbeSetPrintMode (dbevindex, arg1);
1219 	if (s != NULL)
1220 	  {
1221 	    fprintf (stderr, NTXT ("%s\n"), s);
1222 	    break;
1223 	  }
1224 	fprintf (stderr, GTXT ("printmode is set to `%s'\n\n"), dbeGetPrintModeString (dbevindex));
1225       }
1226       break;
1227     case HEADER:
1228       if (get_exp_id (arg1, bgn_index, end_index) != -1)
1229 	{
1230 	  cd = new er_print_experiment (dbev, bgn_index, end_index, false,
1231 					true, false, false, false);
1232 	  print_cmd (cd);
1233 	  delete cd;
1234 	}
1235       break;
1236     case COMPARE:
1237       if (arg1 == NULL)
1238 	{
1239 	  fprintf (out_file, GTXT ("The argument to `compare' must be `on', `off', `delta', or `ratio'\n\n"));
1240 	  break;
1241 	}
1242       else
1243 	{
1244 	  int cmp;
1245 	  if (strcasecmp (arg1, NTXT ("OFF")) == 0 || strcmp (arg1, NTXT ("0")) == 0)
1246 	    cmp = CMP_DISABLE;
1247 	  else if (strcasecmp (arg1, NTXT ("ON")) == 0 || strcmp (arg1, NTXT ("1")) == 0)
1248 	    cmp = CMP_ENABLE;
1249 	  else if (strcasecmp (arg1, NTXT ("DELTA")) == 0)
1250 	    cmp = CMP_DELTA;
1251 	  else if (strcasecmp (arg1, NTXT ("RATIO")) == 0)
1252 	    cmp = CMP_RATIO;
1253 	  else
1254 	    {
1255 	      fprintf (out_file, GTXT ("The argument to `compare' must be `on', `off', `delta', or `ratio'\n\n"));
1256 	      break;
1257 	    }
1258 	  int oldMode = dbev->get_compare_mode ();
1259 	  dbev->set_compare_mode (cmp);
1260 	  if (oldMode != cmp)
1261 	    {
1262 	      dbev->reset_data (false);
1263 	      dbeSession->reset_data ();
1264 	    }
1265 	}
1266       break;
1267     case LEAKS:
1268       if (!dbeSession->is_leaklist_available ())
1269 	{
1270 	  fprintf (out_file, GTXT ("\nHeap trace information was not requested when recording experiments\n\n"));
1271 	  break;
1272 	}
1273       if (dbev->comparingExperiments ())
1274 	{ // XXXX show warning for compare
1275 	  fprintf (out_file, GTXT ("\nNot available when comparing experiments\n\n"));
1276 	  break;
1277 	}
1278       cd = new er_print_leaklist (dbev, true, false, dbev->get_limit ());
1279       print_cmd (cd);
1280       delete cd;
1281       break;
1282     case ALLOCS:
1283       if (!dbeSession->is_leaklist_available ())
1284 	{
1285 	  fprintf (out_file, GTXT ("\nHeap trace information was not requested when recording experiments\n\n"));
1286 	  break;
1287 	}
1288       cd = new er_print_leaklist (dbev, false, true, dbev->get_limit ());
1289       print_cmd (cd);
1290       delete cd;
1291       break;
1292     case HEAP:
1293       if (!dbeSession->is_heapdata_available ())
1294 	{
1295 	  fprintf (out_file, GTXT ("Heap trace information was not requested when recording experiments\n\n"));
1296 	  break;
1297 	}
1298       cd = new er_print_heapactivity (dbev, Histable::HEAPCALLSTACK, false, dbev->get_limit ());
1299       print_cmd (cd);
1300       delete cd;
1301       break;
1302     case HEAPSTAT:
1303       if (!dbeSession->is_heapdata_available ())
1304 	{
1305 	  fprintf (out_file, GTXT ("Heap trace information was not requested when recording experiments\n\n"));
1306 	  break;
1307 	}
1308       cd = new er_print_heapactivity (dbev, Histable::HEAPCALLSTACK, true, dbev->get_limit ());
1309       print_cmd (cd);
1310       delete cd;
1311       break;
1312     case IOACTIVITY:
1313       if (!dbeSession->is_iodata_available ())
1314 	{
1315 	  fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
1316 	  break;
1317 	}
1318       if (dbev->comparingExperiments ())
1319 	{ // XXXX show warning for compare
1320 	  fprintf (out_file, GTXT ("\nNot available when comparing experiments\n\n"));
1321 	  break;
1322 	}
1323       cd = new er_print_ioactivity (dbev, Histable::IOACTFILE, false, dbev->get_limit ());
1324       print_cmd (cd);
1325       delete cd;
1326       break;
1327     case IOVFD:
1328       if (!dbeSession->is_iodata_available ())
1329 	{
1330 	  fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
1331 	  break;
1332 	}
1333       cd = new er_print_ioactivity (dbev, Histable::IOACTVFD, false, dbev->get_limit ());
1334       print_cmd (cd);
1335       delete cd;
1336       break;
1337     case IOCALLSTACK:
1338       if (!dbeSession->is_iodata_available ())
1339 	{
1340 	  fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
1341 	  break;
1342 	}
1343       cd = new er_print_ioactivity (dbev, Histable::IOCALLSTACK, false, dbev->get_limit ());
1344       print_cmd (cd);
1345       delete cd;
1346       break;
1347     case IOSTAT:
1348       if (!dbeSession->is_iodata_available ())
1349 	{
1350 	  fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
1351 	  break;
1352 	}
1353       cd = new er_print_ioactivity (dbev, Histable::IOACTVFD, true, dbev->get_limit ());
1354       print_cmd (cd);
1355       delete cd;
1356       break;
1357     case HELP:
1358       Command::print_help(whoami, false, true, out_file);
1359       break;
1360     case VERSION_cmd:
1361       Application::print_version_info ();
1362       break;
1363     case SCRIPT:
1364       if (arg1)
1365 	{
1366 	  ck_file = fopen (arg1, NTXT ("r"));
1367 	  if (ck_file == NULL)
1368 	    fprintf (stderr, GTXT ("Error: Script file cannot be opened: %s\n"), arg1);
1369 	  else
1370 	    {
1371 	      save_file = inp_file;
1372 	      inp_file = ck_file;
1373 	      proc_script ();
1374 	      inp_file = save_file;
1375 	    }
1376 	}
1377       else
1378 	fprintf (stderr, GTXT ("Error: No filename has been specified.\n"));
1379       break;
1380     case QUIT:
1381       exit (0);
1382       break;
1383 
1384       // commands relating to index Objects
1385     case INDXOBJ:
1386       if ((cparam == -1) && (arg1 == NULL))
1387 	{
1388 	  fprintf (stderr, GTXT ("Error: No index object name has been specified.\n"));
1389 	  break;
1390 	}
1391       // automatically load machine model if applicable
1392       dbeDetectLoadMachineModel (dbevindex);
1393       indxobj (arg1, cparam);
1394       break;
1395     case INDXOBJLIST:
1396       // automatically load machine model if applicable
1397       dbeDetectLoadMachineModel (dbevindex);
1398       indxo_list (false, out_file);
1399       break;
1400 
1401       // define a new IndexObject type
1402     case INDXOBJDEF:
1403       if (arg1 == NULL)
1404 	{
1405 	  fprintf (stderr, GTXT ("Error: No index object name has been specified.\n"));
1406 	  break;
1407 	}
1408       if (arg2 == NULL)
1409 	{
1410 	  fprintf (stderr, GTXT ("Error: No index-expr has been specified.\n"));
1411 	  break;
1412 	}
1413       indxo_define (arg1, arg2, arg3, arg4);
1414       break;
1415 
1416       // the commands following this are unsupported/hidden
1417     case IFREQ:
1418       if (!dbeSession->is_ifreq_available ())
1419 	{
1420 	  fprintf (out_file, GTXT ("\nInstruction frequency data was not requested when recording experiments\n\n"));
1421 	  break;
1422 	}
1423       ifreq ();
1424       break;
1425     case DUMPNODES:
1426       dump_nodes ();
1427       break;
1428     case DUMPSTACKS:
1429       dump_stacks ();
1430       break;
1431     case DUMPUNK:
1432       dump_unk_pcs ();
1433       break;
1434     case DUMPFUNC:
1435       dump_funcs (arg1);
1436       break;
1437     case DUMPDOBJS:
1438       dump_dataobjects (arg1);
1439       break;
1440     case DUMPMAP:
1441       dump_map ();
1442       break;
1443     case DUMPENTITIES:
1444       dump_entities ();
1445       break;
1446     case DUMP_PROFILE:
1447       dbev->dump_profile (out_file);
1448       break;
1449     case DUMP_SYNC:
1450       dbev->dump_sync (out_file);
1451       break;
1452     case DUMP_HWC:
1453       dbev->dump_hwc (out_file);
1454       break;
1455     case DUMP_HEAP:
1456       if (!dbeSession->is_leaklist_available ())
1457 	{
1458 	  fprintf (out_file, GTXT ("\nHeap trace information was not requested when recording experiments\n\n"));
1459 	  break;
1460 	}
1461       dbev->dump_heap (out_file);
1462       break;
1463     case DUMP_IOTRACE:
1464       if (!dbeSession->is_iodata_available ())
1465 	{
1466 	  fprintf (out_file, GTXT ("\nI/O trace information was not requested when recording experiments\n\n"));
1467 	  break;
1468 	}
1469       dbev->dump_iotrace (out_file);
1470       break;
1471     case DMEM:
1472       if (arg1 == NULL)
1473 	fprintf (stderr, GTXT ("Error: No sample has been specified.\n"));
1474       else
1475 	{
1476 	  Experiment *exp = dbeSession->get_exp (0);
1477 	  if (exp != NULL)
1478 	    exp->DBG_memuse (arg1);
1479 	}
1480       break;
1481     case DUMP_GC:
1482       if (!dbeSession->has_java ())
1483 	{
1484 	  fprintf (out_file, GTXT ("\nJava garbage collection information was not requested when recording experiments\n\n"));
1485 	  break;
1486 	}
1487       dbev->dump_gc_events (out_file);
1488       break;
1489     case DKILL:
1490       {
1491 	if (arg1 == NULL)
1492 	  {
1493 	    fprintf (stderr, GTXT ("Error: No process has been specified.\n"));
1494 	    break;
1495 	  }
1496 	if (arg2 == NULL)
1497 	  {
1498 	    fprintf (stderr, GTXT ("Error: No signal has been specified.\n"));
1499 	    break;
1500 	  }
1501 	pid_t p = (pid_t) atoi (arg1);
1502 	int signum = atoi (arg2);
1503 	char *ret = dbeSendSignal (p, signum);
1504 	if (ret != NULL)
1505 	  fprintf (stderr, GTXT ("Error: %s"), ret);
1506       }
1507       break;
1508     case PROCSTATS:
1509       dump_stats ();
1510       break;
1511     case ADD_EXP:
1512     case OPEN_EXP:
1513       if (arg1 == NULL)
1514 	fprintf (stderr, GTXT ("Error: No experiment name has been specified.\n"));
1515       else
1516 	{
1517 	  Vector<Vector<char*>*> *groups = new Vector<Vector<char*>*>(1);
1518 	  Vector<char*> *list = new Vector<char*>(1);
1519 	  list->append (arg1);
1520 	  groups->append (list);
1521 	  char *res = dbeOpenExperimentList (dbevindex, groups, cmd_type == OPEN_EXP);
1522 	  if (cmd_type == OPEN_EXP)
1523 	    fprintf (stderr, GTXT ("Previously loaded experiment have been dropped.\n"));
1524 	  if (res != NULL)
1525 	    fprintf (stderr, NTXT ("%s"), res);
1526 	  else
1527 	    fprintf (stderr, GTXT ("Experiment %s has been loaded\n"), arg1);
1528 	  free (res);
1529 	  delete list;
1530 	  delete groups;
1531 	}
1532       break;
1533     case DROP_EXP:
1534       {
1535 	if (arg1 == NULL)
1536 	  fprintf (stderr, GTXT ("Error: No experiment name has been specified.\n"));
1537 	else
1538 	  {
1539 	    int exp_index = dbeSession->find_experiment (arg1);
1540 	    if (exp_index < 0)
1541 	      fprintf (stderr, GTXT ("Error: experiment %s has not been opened.\n"), arg1);
1542 	    else
1543 	      {
1544 		Vector<int> *expid = new Vector<int> (1);
1545 		expid->append (exp_index);
1546 		char *res = dbeDropExperiment (dbevindex, expid);
1547 		if (res != NULL)
1548 		  fprintf (stderr, NTXT ("%s"), res);
1549 		else
1550 		  fprintf (stderr, GTXT ("Experiment %s has been dropped\n"), arg1);
1551 		delete expid;
1552 		free (res);
1553 	      }
1554 	  }
1555       }
1556       break;
1557     case HHELP:
1558       // automatically load machine model if applicable
1559       dbeDetectLoadMachineModel (dbevindex);
1560       Command::print_help (whoami, false, false, out_file);
1561       fprintf (out_file, NTXT ("\n"));
1562       indxo_list (false, out_file);
1563       fprintf (out_file, NTXT ("\n"));
1564       mo_list (false, out_file);
1565       if (!getenv ("_BUILDING_MANPAGE"))
1566 	fprintf (out_file, GTXT ("\nSee gprofng(1) for more details\n"));
1567       break;
1568     case QQUIT:
1569       was_QQUIT = true;
1570       return;
1571     default:
1572       fprintf (stderr, GTXT ("Error: Invalid option\n"));
1573       break;
1574     }
1575 
1576   // check for any processing error messages
1577   dump_proc_warnings ();
1578   fflush (out_file);
1579 }
1580 
1581 #define MAX_NUM_HEADER      4
1582 
1583 void
disp_list(int num_header,int size,int align[],char * header[],char ** lists[])1584 er_print::disp_list (int num_header, int size, int align[], char *header[],
1585 		     char **lists[])
1586 {
1587   size_t maxlen[MAX_NUM_HEADER];
1588   char fmt[MAX_NUM_HEADER][64];
1589   if (num_header > MAX_NUM_HEADER)
1590     abort ();
1591   for (int i = 0; i < num_header; i++)
1592     {
1593       maxlen[i] = strlen (header[i]);
1594       for (int j = 0; j < size; j++)
1595 	{
1596 	  size_t len = strlen (lists[i][j]);
1597 	  if (maxlen[i] < len)
1598 	    maxlen[i] = len;
1599 	}
1600 
1601       // get format string
1602       if ((align[i] == -1) && (i == num_header - 1))
1603 	snprintf (fmt[i], sizeof (fmt[i]), NTXT ("%%s "));
1604       else
1605 	snprintf (fmt[i], sizeof (fmt[i]), NTXT ("%%%ds "), (int) (align[i] * maxlen[i]));
1606 
1607       // write header
1608       fprintf (out_file, fmt[i], header[i]);
1609     }
1610   putc ('\n', out_file);
1611 
1612   // write separator "==="
1613   size_t np = 0;
1614   for (int i = 0; (i < num_header) && (np < 132); i++)
1615     {
1616       size_t nc = maxlen[i];
1617       if (nc + np > 132)
1618 	nc = 132 - np;
1619       for (size_t j = 0; j < nc; j++)
1620 	putc ('=', out_file);
1621       putc (' ', out_file);
1622       np += nc + 1;
1623     }
1624   putc ('\n', out_file);
1625 
1626   // write lists
1627   for (int j = 0; j < size; j++)
1628     {
1629       for (int i = 0; i < num_header; i++)
1630 	fprintf (out_file, fmt[i], lists[i][j]);
1631       putc ('\n', out_file);
1632     }
1633 }
1634 
1635 void
exp_list()1636 er_print::exp_list ()
1637 {
1638   int size, index;
1639   int align[MAX_NUM_HEADER];
1640   char *header[MAX_NUM_HEADER];
1641   char **lists[MAX_NUM_HEADER];
1642 
1643   align[0] = 1;     // right-justify
1644   align[1] = 1;     // right-justify
1645   align[2] = 1;     // right-justify
1646   align[3] = -1;    // left-justify
1647   header[0] = GTXT ("ID");
1648   header[1] = GTXT ("Sel");
1649   header[2] = GTXT ("PID");
1650   header[3] = GTXT ("Experiment");
1651 
1652   size = dbeSession->nexps ();
1653   lists[0] = new char*[size];
1654   lists[1] = new char*[size];
1655   lists[2] = new char*[size];
1656   lists[3] = new char*[size];
1657   for (index = 0; index < size; index++)
1658     {
1659       lists[0][index] = dbe_sprintf (NTXT ("%d"), index + 1);
1660       lists[1][index] = strdup (dbev->get_exp_enable (index) ? GTXT ("yes") : GTXT ("no"));
1661       lists[2][index] = dbe_sprintf (NTXT ("%d"), dbeSession->get_exp (index)->getPID ());
1662       lists[3][index] = strdup (dbeSession->get_exp (index)->get_expt_name ());
1663     }
1664   disp_list (4, size, align, header, lists);
1665   for (int i = 0; i < 4; i++)
1666     {
1667       for (int j = 0; j < size; j++)
1668 	free (lists[i][j]);
1669       delete[] lists[i];
1670     }
1671 }
1672 
1673 void
describe()1674 er_print::describe ()
1675 {
1676   Vector<void*> *res = dbeGetFilterKeywords (dbev->vindex);
1677   if (res == NULL)
1678     return;
1679   Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
1680   Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
1681   Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
1682   Vector <char*> *kwDescrip = (Vector<char*>*) res->fetch (5);
1683   Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
1684   String sectionFormat = NTXT ("\n------ %s ------\n");
1685   String categoryFormat = NTXT ("\n%s\n");
1686   String keywordFormat = NTXT ("   %-20s  %s\n");
1687   String empty = NTXT ("");
1688   String previousCategory = empty;
1689 
1690   for (int i = 0; i < kwKeyword->size (); i++)
1691     {
1692       if (kwKeyword->fetch (i) == NULL)
1693 	{
1694 	  fprintf (dis_file, sectionFormat, kwCategoryI18N->fetch (i));
1695 	  continue;
1696 	}
1697       String cat = kwCategoryI18N->fetch (i);
1698       if (dbe_strcmp (previousCategory, cat) != 0)
1699 	fprintf (dis_file, categoryFormat, cat);
1700       previousCategory = cat;
1701       Vector <String> *enumDescs = (Vector <String> *) kwEnumDescs->fetch (i);
1702       String keyword = kwKeyword->fetch (i);
1703       if (kwDescrip->fetch (i) != NULL)
1704 	{
1705 	  fprintf (dis_file, keywordFormat, keyword, kwDescrip->fetch (i));
1706 	  keyword = empty;
1707 	}
1708       if (kwFormula->fetch (i) != NULL)
1709 	{
1710 	  fprintf (dis_file, keywordFormat, keyword, kwFormula->fetch (i));
1711 	  keyword = empty;
1712 	  continue;
1713 	}
1714       int numEnums = enumDescs != NULL ? enumDescs->size () : 0;
1715       for (int jj = 0; jj < numEnums; jj++)
1716 	{
1717 	  fprintf (dis_file, keywordFormat, keyword, enumDescs->fetch (jj));
1718 	  keyword = empty;
1719 	}
1720     }
1721   destroy (res);
1722 }
1723 
1724 void
obj_list()1725 er_print::obj_list ()
1726 {
1727   LoadObject *lo;
1728   int index;
1729   int align[MAX_NUM_HEADER];
1730   char *header[MAX_NUM_HEADER];
1731   char **lists[MAX_NUM_HEADER];
1732   Vector<LoadObject*> *text_segments = dbeSession->get_text_segments ();
1733   if (text_segments->size () == 0)
1734     {
1735       fprintf (dis_file, GTXT ("There are no load objects in this experiment\n"));
1736       return;
1737     }
1738   align[0] = -1; // left-justify
1739   align[1] = -1; // left-justify
1740   align[2] = -1; // left-justify
1741   align[3] = -1; // left-justify
1742   header[0] = GTXT ("Sel");
1743   header[1] = GTXT ("Load Object");
1744   header[2] = GTXT ("Index");
1745   header[3] = GTXT ("Path");
1746 
1747   int size = text_segments->size ();
1748   lists[0] = new char*[size];
1749   lists[1] = new char*[size];
1750   lists[2] = new char*[size];
1751   lists[3] = new char*[size];
1752 
1753   char *lo_name;
1754   int new_index = 0;
1755   Vec_loop (LoadObject*, text_segments, index, lo)
1756   {
1757     lo_name = lo->get_name ();
1758     if (lo_name != NULL)
1759       {
1760 	size_t len = strlen (lo_name);
1761 	if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
1762 	  continue;
1763       }
1764     LibExpand expand = dbev->get_lo_expand (lo->seg_idx);
1765     switch (expand)
1766       {
1767       case LIBEX_SHOW:
1768 	lists[0][new_index] = dbe_strdup (GTXT ("show"));
1769 	break;
1770       case LIBEX_HIDE:
1771 	lists[0][new_index] = dbe_strdup (GTXT ("hide"));
1772 	break;
1773       case LIBEX_API:
1774 	lists[0][new_index] = dbe_strdup (GTXT ("API-only"));
1775 	break;
1776       }
1777     lists[1][new_index] = dbe_strdup (lo_name);
1778     lists[2][new_index] = dbe_sprintf (NTXT ("%d"), lo->seg_idx);
1779     lists[3][new_index] = dbe_strdup (lo->get_pathname ());
1780     new_index++;
1781   }
1782   disp_list (4, new_index, align, header, lists);
1783   for (int i = 0; i < 4; i++)
1784     {
1785       for (int j = 0; j < new_index; j++)
1786 	free (lists[i][j]);
1787       delete[] lists[i];
1788     }
1789   delete text_segments;
1790 }
1791 
1792 void
seg_list()1793 er_print::seg_list ()
1794 {
1795   LoadObject *lo;
1796   int index;
1797   int align[MAX_NUM_HEADER];
1798   char *header[MAX_NUM_HEADER];
1799   char **lists[MAX_NUM_HEADER];
1800 
1801   // XXX seg_list only prints text segments; should extend to all
1802   Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
1803   if (lobjs->size () == 0)
1804     {
1805       fprintf (dis_file, GTXT ("There are no segments in this experiment\n"));
1806       return;
1807     }
1808   align[0] = -1; // left-justify
1809   align[1] = 1;  // right-justify
1810   align[2] = -1; // left-justify
1811   header[0] = GTXT ("Sel");
1812   header[1] = GTXT ("Size");
1813   header[2] = GTXT ("Segment");
1814 
1815   int size = lobjs->size ();
1816   lists[0] = new char*[size];
1817   lists[1] = new char*[size];
1818   lists[2] = new char*[size];
1819 
1820   char *lo_name;
1821   int new_index = 0;
1822   Vec_loop (LoadObject*, lobjs, index, lo)
1823   {
1824     lo_name = lo->get_name ();
1825     if (lo_name != NULL)
1826       {
1827 	size_t len = strlen (lo_name);
1828 	if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
1829 	  continue;
1830       }
1831     bool expand = dbev->get_lo_expand (lo->seg_idx);
1832     lists[0][new_index] = strdup (expand ? GTXT ("yes") : GTXT ("no"));
1833     lists[1][new_index] = dbe_sprintf (NTXT ("%lld"), (ll_t) lo->get_size ());
1834     lists[2][new_index] = strdup (lo->get_pathname ());
1835     new_index++;
1836   }
1837 
1838   disp_list (3, new_index, align, header, lists);
1839   for (int i = 0; i < 4; i++)
1840     {
1841       for (int j = 0; j < new_index; j++)
1842 	free (lists[i][j]);
1843       delete[] lists[i];
1844     }
1845   delete lobjs;
1846 }
1847 
1848 void
filter_list(CmdType cmd_type)1849 er_print::filter_list (CmdType cmd_type)
1850 {
1851   FilterNumeric *select;
1852   int index;
1853   int align[MAX_NUM_HEADER];
1854   char *header[MAX_NUM_HEADER];
1855   char **lists[MAX_NUM_HEADER];
1856   char *pattern;
1857 
1858   // first ensure that the data has been read
1859   MetricList *mlist = dbev->get_metric_list (MET_INDX);
1860   Hist_data *data = dbev->get_hist_data (mlist, Histable::INDEXOBJ, 0, Hist_data::ALL);
1861   delete data;
1862 
1863   align[0] = 1;  // right-justify
1864   align[1] = -1; // left-justify
1865   align[2] = 1;  // right-justify
1866   align[3] = 1;  // right-justify
1867   header[0] = GTXT ("Exp");
1868   header[1] = GTXT ("Sel");
1869   header[2] = GTXT ("Total");
1870   header[3] = GTXT ("Status");
1871 
1872   int size = dbeSession->nexps ();
1873   lists[0] = new char*[size];
1874   lists[1] = new char*[size];
1875   lists[2] = new char*[size];
1876   lists[3] = new char*[size];
1877   int new_index = 0;
1878   for (index = 0; index < size; index++)
1879     {
1880       switch (cmd_type)
1881 	{
1882 	case SAMPLE_LIST:
1883 	  select = dbev->get_FilterNumeric (index, SAMPLE_FILTER_IDX);
1884 	  break;
1885 	case THREAD_LIST:
1886 	  select = dbev->get_FilterNumeric (index, THREAD_FILTER_IDX);
1887 	  break;
1888 	case LWP_LIST:
1889 	  select = dbev->get_FilterNumeric (index, LWP_FILTER_IDX);
1890 	  break;
1891 	case CPU_LIST:
1892 	  select = dbev->get_FilterNumeric (index, CPU_FILTER_IDX);
1893 	  break;
1894 	default:
1895 	  abort (); // internal error
1896 	}
1897       if (select == NULL)
1898 	continue;
1899       lists[0][new_index] = dbe_sprintf (NTXT ("%d"), index + 1);
1900       pattern = dbev->get_exp_enable (index) ? select->get_pattern () : NULL;
1901       lists[1][new_index] = strdup (pattern && *pattern ? pattern : GTXT ("none"));
1902       lists[2][new_index] = dbe_sprintf (NTXT ("%lld"), (ll_t) select->nelem ());
1903       lists[3][new_index] = select->get_status ();
1904       new_index++;
1905     }
1906   disp_list (3, size, align, header, lists);
1907   for (int i = 0; i < 4; i++)
1908     {
1909       for (int j = 0; j < new_index; j++)
1910 	free (lists[i][j]);
1911       delete[] lists[i];
1912     }
1913 }
1914 
1915 int
check_exp_id(int exp_id,char * sel)1916 er_print::check_exp_id (int exp_id, char *sel)
1917 {
1918   if (exp_id < 0 || exp_id >= dbeSession->nexps ())
1919     {
1920       fprintf (stderr, GTXT ("Error: Invalid number entered: %s\nType \"exp_list\" for a list of all experiments.\n"),
1921 	       sel);
1922       return -1;
1923     }
1924   return exp_id;
1925 }
1926 
1927 int
get_exp_id(char * sel,int & bgn_index,int & end_index)1928 er_print::get_exp_id (char *sel, int &bgn_index, int &end_index)
1929 {
1930   int id, exp_id;
1931   if (sel == NULL || strcmp (sel, NTXT ("all")) == 0)
1932     {
1933       // loop over all experiments
1934       bgn_index = 0;
1935       end_index = dbeSession->nexps () - 1;
1936     }
1937   else
1938     {
1939       id = (int) strtol (sel, (char **) NULL, 10) - 1;
1940       exp_id = check_exp_id (id, sel);
1941      if (exp_id == -1)
1942 	return -1;
1943       bgn_index = end_index = exp_id;
1944     }
1945   return 0;
1946 }
1947 
1948 void
print_objects()1949 er_print::print_objects ()
1950 {
1951   Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
1952   char *msg = pr_load_objects (lobjs, NTXT (""));
1953   delete lobjs;
1954   fprintf (out_file, NTXT ("%s\n"), msg);
1955   free (msg);
1956 }
1957 
1958 void
print_overview()1959 er_print::print_overview ()
1960 {
1961   //fprintf(out_file, NTXT("%s\n"), GTXT("Not implemented yet."));//YXXX
1962   Vector<char*> *status = dbeGetOverviewText (dbevindex);
1963   StringBuilder sb;
1964   sb.append (GTXT ("Experiment(s):\n\n"));
1965   for (int i = 0; i < status->size (); i++)
1966     sb.appendf (NTXT ("%s\n"), status->fetch (i));
1967   sb.append (GTXT ("Metrics:\n"));
1968   sb.toFile (out_file);
1969 
1970   Vector<void*> *data = dbeGetRefMetricTree (dbevindex, false);
1971   Vector<char *> *metric_cmds = new Vector<char *>();
1972   Vector<char *> *non_metric_cmds = new Vector<char *>();
1973   print_overview_nodes (data, 0, metric_cmds, non_metric_cmds);
1974   Vector<void*> *values = dbeGetRefMetricTreeValues (0, metric_cmds, non_metric_cmds);
1975   print_overview_tree (data, 0, values, metric_cmds, non_metric_cmds);
1976 
1977   StringBuilder sb2;
1978   sb2.append (GTXT ("\nNotes: '*' indicates hot metrics, '[X]' indicates currently enabled metrics.\n"));
1979   sb2.append (GTXT ("       The metrics command can be used to change selections. The metric_list command lists all available metrics.\n"));
1980   sb2.toFile (out_file);
1981 }
1982 
1983 void
print_overview_nodes(Vector<void * > * data,int level,Vector<char * > * metric_cmds,Vector<char * > * non_metric_cmds)1984 er_print::print_overview_nodes (Vector<void*> * data, int level, Vector<char *> *metric_cmds, Vector<char *> *non_metric_cmds)
1985 {
1986   Vector<void*> *fields = (Vector<void*> *) data->fetch (0);
1987   Vector<void*> *children = (Vector<void*> *) data->fetch (1);
1988   char *name = ((Vector<char*> *)fields->fetch (0))->fetch (0);
1989   int vstyles_capable = ((Vector<int>*) fields->fetch (5))->fetch (0); //bitmask e.g.VAL_TIMEVAL
1990   bool has_value = ((Vector<bool>*) fields->fetch (10))->fetch (0);
1991   bool selectable = (vstyles_capable != 0) ? true : false;
1992   if (selectable)
1993     metric_cmds->append (name);
1994   else if (has_value)
1995     non_metric_cmds->append (name);
1996 
1997   level++;
1998   for (int i = 0; i < children->size (); i++)
1999     print_overview_nodes ((Vector<void*> *)(children->fetch (i)), level, metric_cmds, non_metric_cmds);
2000 }
2001 
2002 void
print_overview_tree(Vector<void * > * data,int level,Vector<void * > * values,Vector<char * > * metric_cmds,Vector<char * > * non_metric_cmds)2003 er_print::print_overview_tree (Vector<void*> * data, int level, Vector<void*> * values, Vector<char *> *metric_cmds, Vector<char *> *non_metric_cmds)
2004 {
2005   Vector<void*> * fields = (Vector<void*> *) data->fetch (0);
2006   Vector<void*> * children = (Vector<void*> *) data->fetch (1);
2007   char *name = ((Vector<char*> *)fields->fetch (0))->fetch (0);
2008   char *username = ((Vector<char*> *)fields->fetch (1))->fetch (0);
2009   int flavors = ((Vector<int>*) fields->fetch (3))->fetch (0); //bitmask e.g. EXCLUSIVE
2010   int vstyles_capable = ((Vector<int>*) fields->fetch (5))->fetch (0); //bitmask e.g.VAL_TIMEVAL
2011   //    bool aggregation = ((Vector<bool>*) fields->fetch(9))->fetch(0);
2012   //    bool has_value = ((Vector<bool>*) fields->fetch(10))->fetch(0);
2013   char *unit = ((Vector<char*> *) fields->fetch (11))->fetch (0);
2014 
2015   StringBuilder sb;
2016   for (int i = 0; i < level * 2; i++)
2017     sb.append (NTXT (" ")); // NOI18N
2018 
2019   bool selectable = (vstyles_capable != 0) ? true : false;
2020   if (selectable)
2021     {
2022       bool isSelected = dbev->get_metric_list (MET_NORMAL)->find_metric_by_name (name) == NULL ? false : true;
2023       if (isSelected)
2024 	sb.append (NTXT ("[X]"));
2025       else
2026 	sb.append (NTXT ("[ ]"));
2027     }
2028   if ((unit != NULL && dbe_strcmp (unit, UNIT_SECONDS) == 0)
2029       || (unit == NULL && vstyles_capable & VAL_TIMEVAL))
2030     unit = GTXT ("Seconds");
2031 
2032   bool isHiddenInOverview = ((flavors & BaseMetric::STATIC) != 0);
2033   if (name != NULL && dbe_strcmp (name, L1_STATIC) == 0)
2034     isHiddenInOverview = true;
2035   if (!dbeSession->has_java () && name != NULL && dbe_strcmp (name, L1_GCDURATION) == 0)
2036     isHiddenInOverview = true;
2037   if (isHiddenInOverview)
2038     return;
2039 
2040   sb.append (username == NULL ? NTXT ("") : username); // NOI18N
2041   int show = 0;
2042   if (name == NULL)
2043     show = 0;
2044   else if (strstr (name, NTXT ("PROFDATA_TYPE_")) == NULL)
2045     show = 1;
2046 
2047   if (show)
2048     {
2049       sb.append (username == NULL ? NTXT ("") : NTXT (" - ")); // NOI18N
2050       sb.append (name == NULL ? NTXT ("") : name); // NOI18N
2051     }
2052 
2053   // "Bugs 16624403 and 19539622" (leave this string intact for searches)
2054   // add an extra condition for now
2055   // once we have proper fixes, eliminate test on Bug16624402_extra_condition
2056   int Bug16624402_extra_condition = 1;
2057   if (username)
2058     {
2059       if (strcmp (username, NTXT ("Block Covered %")) == 0) Bug16624402_extra_condition = 0;
2060       if (strcmp (username, NTXT ("Instr Covered %")) == 0) Bug16624402_extra_condition = 0;
2061     }
2062   if (Bug16624402_extra_condition > 0 && values->size () > 0)
2063     {
2064       Vector<void*> * valueColumns = (Vector<void*> *)values->fetch (0);
2065       Vector<void*> * highlightColumns = (Vector<void*> *)values->fetch (1);
2066       int jj = 0;
2067       int found = 0;
2068       for (jj = 0; jj < valueColumns->size (); jj++)
2069 	{
2070 	  const char *value_name = "";
2071 	  if (jj < metric_cmds->size ())
2072 	    value_name = metric_cmds->fetch (jj);
2073 	  else
2074 	    value_name = non_metric_cmds->fetch (jj - metric_cmds->size ());
2075 	  if (dbe_strcmp (value_name, name) != 0)
2076 	    continue;
2077 	  else
2078 	    {
2079 	      found = 1;
2080 	      break;
2081 	    }
2082 	}
2083       if (found)
2084 	{
2085 	  Vector<void*> * valueVec = (Vector<void*> *)valueColumns->fetch (jj);
2086 	  Vector<bool> * highlights = (Vector<bool> *)highlightColumns->fetch (jj);
2087 	  for (int kk = 0; kk < valueVec->size (); kk++)
2088 	    {
2089 	      char * value_str;
2090 	      int show_value = 0;
2091 	      switch (valueVec->type ())
2092 		{
2093 		case VEC_INTEGER:
2094 		  value_str = dbe_sprintf (NTXT ("%ld"), (long) (((Vector<int> *)valueVec)->fetch (kk)));
2095 		  show_value = 1;
2096 		  break;
2097 		case VEC_DOUBLE:
2098 		  value_str = dbe_sprintf (NTXT ("%.3f"), (double) (((Vector<double> *)valueVec)->fetch (kk)));
2099 		  show_value = 1;
2100 		  break;
2101 		case VEC_LLONG:
2102 		  value_str = dbe_sprintf (NTXT ("%lld"), (long long) (((Vector<long> *)valueVec)->fetch (kk)));
2103 		  show_value = 1;
2104 		  break;
2105 		case VEC_STRING:
2106 		  value_str = NTXT ("");
2107 		  break;
2108 		default:
2109 		  value_str = NTXT ("");
2110 		}
2111 	      if (show_value)
2112 		{
2113 		  if (kk == 0)
2114 		    {
2115 		      sb.append (unit == NULL ? NTXT ("") : NTXT (" ("));
2116 		      sb.append (unit == NULL ? NTXT ("") : unit);
2117 		      sb.append (unit == NULL ? NTXT ("") : NTXT (")"));
2118 		      sb.append (NTXT (":"));
2119 		    }
2120 		  bool highlight = highlights->fetch (kk);
2121 		  const char * hilite = highlight ? NTXT ("*") : NTXT ("");
2122 		  sb.append (NTXT (" ["));
2123 		  sb.append (hilite);
2124 		  sb.append (value_str);
2125 		  sb.append (NTXT ("]"));
2126 		}
2127 	    }
2128 	}
2129     }
2130   sb.append (NTXT ("\n"));
2131   sb.toFile (out_file);
2132   level++;
2133   for (int i = 0; i < children->size (); i++)
2134     print_overview_tree ((Vector<void*> *)(children->fetch (i)), level, values, metric_cmds, non_metric_cmds);
2135 }
2136 
2137 void
print_segments()2138 er_print::print_segments ()
2139 {
2140   Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
2141   char *msg = pr_load_objects (lobjs, NTXT (""));
2142   delete lobjs;
2143   fprintf (dis_file, NTXT ("Not implemented yet!\n"));
2144   free (msg);
2145 }
2146 
2147 void
print_dobj(Print_mode mode,MetricList * mlist1,char * dobj_name,char * sel)2148 er_print::print_dobj (Print_mode mode, MetricList *mlist1,
2149 		      char *dobj_name, char *sel)
2150 {
2151   Hist_data *hist_data = NULL;
2152   char *errstr;
2153   er_print_common_display *cd;
2154   int list_limit = limit;
2155   Histable *sobj = NULL;
2156   Dprintf (DEBUG_DATAOBJ, NTXT ("er_print::print_dobj(mode=%d,dobj=%s,sel=%s)\n"),
2157 	   mode, (dobj_name == NULL) ? NTXT ("0") : dobj_name, (sel == NULL) ? NTXT ("0") : sel);
2158   char *name = dbev->getSort (MET_DATA);
2159   switch (mode)
2160     {
2161     case MODE_LIST:
2162       hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::ALL);
2163       break;
2164     case MODE_DETAIL:
2165       // if specified, find the dataobject from the name
2166       if (dobj_name && strcmp (dobj_name, NTXT ("<All>")))
2167 	{
2168 	  if (!dbeSession->find_obj (dis_file, inp_file, sobj, dobj_name,
2169 				     sel, Histable::DOBJECT, (inp_file != stdin)))
2170 	    return;
2171 	  if (sobj == NULL)
2172 	    { // dataobject/segment not found
2173 	      hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::DETAIL);
2174 	      if (!dbeSession->find_obj (dis_file, inp_file, sobj, dobj_name,
2175 					 sel, Histable::DOBJECT, (inp_file != stdin)))
2176 		return;
2177 	      if (sobj == NULL)
2178 		{ // dataobject/segment not found
2179 		  fprintf (stderr, GTXT ("Error: No dataobject with given name `%s' found.\n"),
2180 			   dobj_name);
2181 		  return;
2182 		}
2183 	    }
2184 
2185 	  list_limit = 1;
2186 	}
2187       if (!hist_data)
2188 	hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::DETAIL);
2189       break;
2190     case MODE_ANNOTATED:
2191       hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::LAYOUT);
2192       break;
2193     default: // MODE_GPROF is not relevant for DataObjects
2194       abort ();
2195     }
2196 
2197   if (hist_data->get_status () != Hist_data::SUCCESS)
2198     {
2199       // XXXX is this error message adequate?
2200       errstr = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
2201       if (errstr)
2202 	{
2203 	  fprintf (stderr, GTXT ("Error: %s\n"), errstr);
2204 	  free (errstr);
2205 	}
2206       delete hist_data;
2207       return;
2208     }
2209   cd = (er_print_common_display *) new er_print_histogram (dbev, hist_data,
2210 							   hist_data->get_metric_list (), mode, list_limit, name, sobj, false, false);
2211   free (name);
2212   print_cmd (cd);
2213 
2214   delete hist_data;
2215   delete cd;
2216 }
2217 
2218 void
print_func(Histable::Type type,Print_mode mode,MetricList * mlist1,MetricList * mlist2,char * func_name,char * sel)2219 er_print::print_func (Histable::Type type, Print_mode mode, MetricList *mlist1,
2220 		      MetricList *mlist2, char *func_name, char *sel)
2221 {
2222   Hist_data *hist_data;
2223   Hist_data::HistItem *hitem;
2224   int index;
2225   char *errstr;
2226   int list_limit = limit;
2227   Histable *sobj = NULL;
2228   MetricList *mlist;
2229   StringBuilder sb;
2230   char *sname = dbev->getSort (MET_NORMAL);
2231   sb.append (sname);
2232   free (sname);
2233 
2234   switch (mode)
2235     {
2236     case MODE_DETAIL:
2237       {
2238 	// The first metric list, mlist1, is only used to pick out the sort
2239 	//    mlist2 is the one used to generate the data
2240 	char *prevsort = NULL;
2241 	// if specified, find the function from the function name
2242 	if (func_name && strcmp (func_name, NTXT ("<All>")))
2243 	  {
2244 	    if ((!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
2245 					sel, Histable::FUNCTION, (inp_file != stdin)) || (sobj == NULL)) &&
2246 		!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
2247 				       sel, Histable::LOADOBJECT, (inp_file != stdin)))
2248 	      return;
2249 	    if (sobj == NULL)
2250 	      { // function/segment object not found
2251 		fprintf (stderr, GTXT ("Error: No function with given name `%s' found.\n"),
2252 			 func_name);
2253 		return;
2254 	      }
2255 	    list_limit = 1;
2256 	  }
2257 	else
2258 	  {
2259 	    // find the sort metric from the reference list
2260 	    prevsort = mlist2->get_sort_cmd ();
2261 
2262 	    // find the current sort metric from the current list
2263 	    char *cursort = mlist1->get_sort_cmd ();
2264 
2265 	    // find the corresponding metric in the reference list
2266 	    (void) mlist2->set_sort (cursort, false);
2267 	    free (cursort);
2268 	    // if it fails, nothing is needed
2269 	  }
2270 	hist_data = dbev->get_hist_data (mlist2, type, 0, Hist_data::ALL);
2271 
2272 	// restore
2273 	if (sobj == NULL)
2274 	  {
2275 	    if (prevsort == NULL)
2276 	      abort ();
2277 	    (void) mlist2->set_sort (prevsort, false);
2278 	  }
2279 	mlist = mlist2;
2280 	free (prevsort);
2281 	break;
2282       }
2283     case MODE_GPROF:
2284       // if specified, find the function from the function name
2285       if (func_name && strcmp (func_name, NTXT ("<All>")))
2286 	{
2287 	  if (!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
2288 				     sel, Histable::FUNCTION, (inp_file != stdin)))
2289 	    return;
2290 	  if (sobj == NULL)
2291 	    { // function/segment object not found
2292 	      fprintf (stderr, GTXT ("Error: No function with given name `%s' found.\n"),
2293 		       func_name);
2294 	      return;
2295 	    }
2296 	  list_limit = 1;
2297 	  sb.setLength (0);
2298 	}
2299       sb.append (GTXT ("\nCallers and callees sorted by metric: "));
2300       sname = dbev->getSort (MET_CALL);
2301       sb.append (sname);
2302       free (sname);
2303 
2304       // Use mlist2 to generate the sort order.
2305       // mlist1 is used to generate the data.
2306       hist_data = dbev->get_hist_data (mlist2, type, 0, Hist_data::ALL);
2307       mlist = mlist1;
2308       break;
2309     default:
2310       hist_data = dbev->get_hist_data (mlist1, type, 0, Hist_data::ALL);
2311       mlist = mlist1;
2312     }
2313 
2314   if (hist_data->get_status () != Hist_data::SUCCESS)
2315     {
2316       errstr = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
2317       if (errstr)
2318 	{
2319 	  fprintf (stderr, GTXT ("Error: %s\n"), errstr);
2320 	  free (errstr);
2321 	}
2322       delete hist_data;
2323       return;
2324     }
2325 
2326   if (type == Histable::FUNCTION)
2327     {
2328       for (index = 0; index < hist_data->size (); index++)
2329 	{
2330 	  hitem = hist_data->fetch (index);
2331 	  if (hitem->obj->get_type () == Histable::FUNCTION)
2332 	    // fetch the name, since that will force a format conversion
2333 	    ((Function *) hitem->obj)->get_name ();
2334 	}
2335     }
2336 
2337   char *name = sb.toString ();
2338   er_print_histogram *cd = new er_print_histogram (dbev, hist_data,
2339 						   mlist, mode, list_limit, name, sobj, false, false);
2340   print_cmd (cd);
2341   delete hist_data;
2342   free (name);
2343   delete cd;
2344 }
2345 
2346 void
print_gprof(CmdType cmd_type,char * func_name,char * sel)2347 er_print::print_gprof (CmdType cmd_type, char *func_name, char *sel)
2348 {
2349   Histable *sobj = NULL;
2350   if (func_name != NULL)
2351     {
2352       if ((!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
2353 				  sel, Histable::FUNCTION, (inp_file != stdin))
2354 	   || sobj == NULL)
2355 	  && !dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
2356 				    sel, Histable::LOADOBJECT, (inp_file != stdin)))
2357 	return;
2358       if (sobj == NULL)
2359 	{ // function/segment object not found
2360 	  fprintf (stderr, GTXT ("Error: No function with given name `%s' found.\n"),
2361 		   func_name);
2362 	  return;
2363 	}
2364     }
2365   if (cmd_type == CPREPEND)
2366     {
2367       if (sobj == NULL)
2368 	{
2369 	  fprintf (stderr, GTXT ("Error: No function name has been specified.\n"));
2370 	  return;
2371 	}
2372       cstack->insert (0, sobj);
2373     }
2374   else if (cmd_type == CAPPEND)
2375     {
2376       if (sobj == NULL)
2377 	{
2378 	  fprintf (stderr, GTXT ("Error: No function name has been specified.\n"));
2379 	  return;
2380 	}
2381       cstack->append (sobj);
2382     }
2383   else if (cmd_type == CSINGLE)
2384     {
2385       if (sobj != NULL)
2386 	{
2387 	  cstack->reset ();
2388 	  cstack->append (sobj);
2389 	}
2390       else if (cstack->size () == 0)
2391 	{
2392 	  fprintf (stderr, GTXT ("Error: No function name has been specified.\n"));
2393 	  return;
2394 	}
2395     }
2396   else if (cmd_type == CRMFIRST)
2397     {
2398       if (cstack->size () <= 1)
2399 	{
2400 	  fprintf (stderr, GTXT ("Warning: there is only one function in the stack segment; cannot remove it.\n"));
2401 	  return;
2402 	}
2403       cstack->remove (0);
2404     }
2405   else if (cmd_type == CRMLAST)
2406     {
2407       if (cstack->size () <= 1)
2408 	{
2409 	  fprintf (stderr, GTXT ("Warning: there is only one function in the stack segment; cannot remove it.\n"));
2410 	  return;
2411 	}
2412       cstack->remove (cstack->size () - 1);
2413     }
2414 
2415   er_print_gprof *cd = new er_print_gprof (dbev, cstack);
2416   print_cmd (cd);
2417   delete cd;
2418 }
2419 
2420 /*
2421  * Method print_ctree() prints Functions Call Tree.
2422  */
2423 void
print_ctree(CmdType cmd_type)2424 er_print::print_ctree (CmdType cmd_type)
2425 {
2426   if (cmd_type != CALLTREE)
2427     {
2428       fprintf (stderr, GTXT ("Error: Invalid command type: %d\n"), cmd_type);
2429       return;
2430     }
2431 
2432   Histable *sobj = dbeSession->get_Total_Function ();
2433   Vector<Histable*> *ctree_cstack = new Vector<Histable*>();
2434   ctree_cstack->reset ();
2435   er_print_ctree *cd = new er_print_ctree (dbev, ctree_cstack, sobj, limit);
2436   print_cmd (cd);
2437   delete ctree_cstack;
2438   delete cd;
2439 }
2440 
2441 void
memobj(char * name,int cparam)2442 er_print::memobj (char *name, int cparam)
2443 {
2444   int type;
2445   if (name != NULL)
2446     {
2447       // find the memory object index for the name
2448       MemObjType_t *mot = MemorySpace::findMemSpaceByName (name);
2449       if (mot == NULL)
2450 	{
2451 	  // unknown type, report the error
2452 	  fprintf (stderr, GTXT ("Error: Unknown Memory Object type: %s\n"), name);
2453 	  return;
2454 	}
2455       type = mot->type;
2456     }
2457   else
2458     {
2459       MemObjType_t *mot = MemorySpace::findMemSpaceByIndex (cparam);
2460       if (mot == NULL)
2461 	{
2462 	  // unknown type, report the error
2463 	  fprintf (stderr, GTXT ("Error: Unknown Memory Object type: %s\n"), name);
2464 	  return;
2465 	}
2466       type = cparam;
2467     }
2468   dbePrintData (0, DSP_MEMOBJ, type, NULL, NULL, out_file);
2469 }
2470 
2471 void
mo_define(char * moname,char * mo_index_exp,char * machmodel,char * short_desc,char * long_desc)2472 er_print::mo_define (char *moname, char *mo_index_exp, char *machmodel, char *short_desc, char *long_desc)
2473 {
2474   char *ret = MemorySpace::mobj_define (moname, mo_index_exp, machmodel, short_desc, long_desc);
2475   if (ret != NULL)
2476     fprintf (stderr, GTXT ("mobj_define for %s failed: %s\n"), moname, ret);
2477 }
2478 
2479 void
mo_list(bool showtab,FILE * outf)2480 er_print::mo_list (bool showtab, FILE *outf)
2481 {
2482   Vector<bool> *mtab = NULL;
2483   Vector<void*>*res = MemorySpace::getMemObjects ();
2484   if (showtab)
2485     mtab = dbev->get_MemTabState ();
2486   if (res == NULL)
2487     // Since we checked already, this is an internal error
2488     abort ();
2489 
2490   // unpack the return
2491   // Vector<char*> *index = (Vector<int> *)res->fetch(0);  // not used
2492   Vector<char*> *mo_names = (Vector<char*> *)res->fetch (1);
2493   // Vector<char*> *mnemonic = (Vector<char> *)res->fetch(2);  // not used
2494   Vector<char*> *mo_expr = (Vector<char*> *)res->fetch (3);
2495   Vector<char*> *mo_mach_m = (Vector<char*> *)res->fetch (4);
2496   // Vector<char*> *tmpOrder = (Vector<int> *)res->fetch(5);  // not used
2497 
2498   int size = mo_names->size ();
2499   if (size == 0)
2500     {
2501       if (!getenv ("_BUILDING_MANPAGE"))
2502 	fprintf (outf, GTXT (" No Memory Object Types Defined\n"));
2503     }
2504   else
2505     {
2506       if (!getenv ("_BUILDING_MANPAGE"))
2507 	fprintf (outf, GTXT (" Memory Object Types Available:\n"));
2508       else
2509 	fprintf (outf, GTXT ("*Memory Object Types*\n"));
2510       for (int i = 0; i < size; i++)
2511 	{
2512 	  if (mtab)
2513 	    fprintf (outf, NTXT ("  %c %s\n"), mtab->fetch (i) ? 'T' : 'F',
2514 		     mo_names->fetch (i));
2515 	  else
2516 	    {
2517 	      if (mo_mach_m->fetch (i) != NULL)
2518 		fprintf (outf, NTXT ("  %s\t\t\"%s\"\t\t(machinemodel: %s)\n"),
2519 			 mo_names->fetch (i), mo_expr->fetch (i), mo_mach_m->fetch (i));
2520 	      else
2521 		fprintf (outf, NTXT ("  %s\t\t\"%s\"\n"),
2522 			 mo_names->fetch (i), mo_expr->fetch (i));
2523 	    }
2524 	}
2525     }
2526   delete mo_names;
2527   delete mo_expr;
2528   delete mo_mach_m;
2529   delete res;
2530 }
2531 
2532 void
indxobj(char * name,int cparam)2533 er_print::indxobj (char *name, int cparam)
2534 {
2535   int type;
2536   if (name != NULL)
2537     {
2538       // find the index object index for the name
2539       type = dbeSession->findIndexSpaceByName (name);
2540       if (type < 0)
2541 	{
2542 	  // unknown type, report the error
2543 	  fprintf (stderr, GTXT ("Error: Unknown Index Object type: %s\n"), name);
2544 	  return;
2545 	}
2546     }
2547   else
2548     {
2549       char *indxname = dbeSession->getIndexSpaceName (cparam);
2550       if (indxname == NULL)
2551 	{
2552 	  // unknown type, report the error
2553 	  fprintf (stderr, GTXT ("Error: Unknown Index Object type: %d\n"), cparam);
2554 	  return;
2555 	}
2556       type = cparam;
2557     }
2558   dbePrintData (0, DSP_INDXOBJ, type, NULL, NULL, out_file);
2559 }
2560 
2561 void
indxo_define(char * ioname,char * io_index_exp,char * sdesc,char * ldesc)2562 er_print::indxo_define (char *ioname, char *io_index_exp, char *sdesc, char *ldesc)
2563 {
2564   char *ret = dbeDefineIndxObj (ioname, io_index_exp, sdesc, ldesc);
2565   if (ret != NULL)
2566     fprintf (stderr, GTXT ("indxobj_define for %s failed: %s\n"), ioname, ret);
2567 }
2568 
2569 void
indxo_list(bool showtab,FILE * outf)2570 er_print::indxo_list (bool showtab, FILE *outf)
2571 {
2572   Vector<bool> *indxtab = NULL;
2573   char *name;
2574   char *i18n_name;
2575   if (!getenv ("_BUILDING_MANPAGE"))
2576     fprintf (outf, GTXT (" Index Object Types Available:\n"));
2577   else
2578     fprintf (outf, GTXT ("*Index Object Types*\n"));
2579   Vector<void*>*res = dbeGetIndxObjDescriptions (0);
2580   if (showtab)
2581     indxtab = dbev->get_IndxTabState ();
2582   if (res == NULL)  // If none is defined
2583     return;
2584   Vector<char*> *indxo_names = (Vector<char*> *)res->fetch (1);
2585   Vector<char*> *indxo_i18nnames = (Vector<char*> *)res->fetch (3);
2586   Vector<char*> *indxo_exprlist = (Vector<char*> *)res->fetch (5);
2587   int size = indxo_names->size ();
2588   for (int i = 0; i < size; i++)
2589     {
2590       name = indxo_names->fetch (i);
2591       i18n_name = indxo_i18nnames->fetch (i);
2592       if (indxtab)
2593 	{
2594 	  if ((i18n_name != NULL) && (strcmp (i18n_name, name) != 0))
2595 	    fprintf (outf, NTXT ("  %c %s (%s)\n"), indxtab->fetch (i) ? 'T' : 'F',
2596 		     i18n_name, name);
2597 	  else
2598 	    fprintf (outf, NTXT ("  %c %s\n"), indxtab->fetch (i) ? 'T' : 'F', name);
2599 	}
2600       else
2601 	{
2602 	  if (i18n_name != NULL && strcmp (i18n_name, indxo_names->fetch (i)) != 0)
2603 	    fprintf (outf, NTXT ("  %s (%s)"), i18n_name, name);
2604 	  else
2605 	    fprintf (outf, NTXT ("  %s"), name);
2606 	}
2607       char *exprs = indxo_exprlist->fetch (i);
2608       if (exprs != NULL)
2609 	fprintf (outf, NTXT (" \t%s\n"), exprs);
2610       else
2611 	fprintf (outf, NTXT ("\n"));
2612     }
2613   delete indxo_names;
2614   if (showtab)
2615     delete res;
2616 }
2617 
2618 void
ifreq()2619 er_print::ifreq ()
2620 {
2621   dbev->ifreq (out_file);
2622 }
2623 
2624 void
dump_nodes()2625 er_print::dump_nodes ()
2626 {
2627   dbev->dump_nodes (out_file);
2628 }
2629 
2630 void
dump_stacks()2631 er_print::dump_stacks ()
2632 {
2633   dbeSession->dump_stacks (out_file);
2634 }
2635 
2636 void
dump_unk_pcs()2637 er_print::dump_unk_pcs ()
2638 {
2639   // Dump the nodes associated with the <Unknown> function
2640   dbev->get_path_tree ()->dumpNodes (out_file, dbeSession->get_Unknown_Function ());
2641 
2642   // Dump the nodes associated with the <no Java callstack recorded> function
2643   Vector<Function *> *matches = dbeSession->match_func_names ("<no Java callstack recorded>", dbev->get_name_format ());
2644   if (matches == NULL || matches->size () == 0)
2645     fprintf (out_file, GTXT ("No %s functions found\n"), "<no Java callstack recorded>");
2646   else
2647     {
2648       Function *fitem;
2649       int index;
2650       Vec_loop (Function*, matches, index, fitem)
2651       {
2652 	dbev->get_path_tree ()->dumpNodes (out_file, fitem);
2653       }
2654       delete matches;
2655     }
2656 }
2657 
2658 void
dump_funcs(char * arg1)2659 er_print::dump_funcs (char *arg1)
2660 {
2661   if (arg1 == NULL || strlen (arg1) == 0)
2662     dbeSession->dump_segments (out_file);
2663   else
2664     {
2665       Vector<Function *> *matches = dbeSession->match_func_names (arg1, dbev->get_name_format ());
2666       if (matches == NULL)
2667 	{
2668 	  fprintf (stderr, GTXT ("Invalid argument `%s' -- not a regular expression\n"), arg1);
2669 	  return;
2670 	}
2671       fprintf (out_file, GTXT ("%d Function's match `%s'\n"), (int) matches->size (), arg1);
2672       Function *fitem;
2673       int index;
2674       Vec_loop (Function*, matches, index, fitem)
2675       {
2676 	fprintf (out_file, NTXT (" %5lld -- %s (%s) [%s]\n"),
2677 		 (ll_t) fitem->id, fitem->get_name (),
2678 		 (fitem->module ? fitem->module->file_name : NTXT ("<unknown>")),
2679 		 ((fitem->module && fitem->module->loadobject) ?
2680 		  get_basename (fitem->module->loadobject->get_name ()) : NTXT ("<unknown>")));
2681       }
2682       delete matches;
2683     }
2684 }
2685 
2686 void
dump_dataobjects(char * arg1)2687 er_print::dump_dataobjects (char *arg1)
2688 {
2689   // Force computation of data objects, to update master table; discard it
2690   MetricList *mlist1 = dbev->get_metric_list (MET_DATA);
2691   Hist_data *data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::ALL);
2692   delete data;
2693 
2694   if (arg1 == NULL || strlen (arg1) == 0)
2695     dbeSession->dump_dataobjects (out_file);
2696   else
2697     {
2698       Vector<DataObject *> *matches = dbeSession->match_dobj_names (arg1);
2699       if (matches == NULL)
2700 	{
2701 	  fprintf (stderr, GTXT ("Invalid argument `%s' -- not a regular expression\n"), arg1);
2702 	  return;
2703 	}
2704       fprintf (out_file, GTXT ("%d DataObject's match `%s'\n"), (int) matches->size (), arg1);
2705       DataObject *ditem;
2706       int index;
2707       Vec_loop (DataObject*, matches, index, ditem)
2708       {
2709 	fprintf (out_file, NTXT (" %5lld -- %s\n"), (ll_t) ditem->id, ditem->get_name ());
2710       }
2711       delete matches;
2712     }
2713 }
2714 
2715 void
dump_map()2716 er_print::dump_map ()
2717 {
2718   dbeSession->dump_map (out_file);
2719 }
2720 
2721 void
dump_entities()2722 er_print::dump_entities ()
2723 {
2724   int ent_prop_ids[] = {PROP_THRID, PROP_LWPID, PROP_CPUID, PROP_EXPID, -1};
2725 
2726   // loop over experiments
2727   for (int exp_id = 0; exp_id < dbeSession->nexps (); exp_id++)
2728     {
2729       Experiment *exp = dbeSession->get_exp (exp_id);
2730       fprintf (out_file, GTXT ("Experiment %d (%s)\n"),
2731 	       exp_id, exp->get_expt_name ());
2732 
2733       for (int kk = 0; ent_prop_ids[kk] != -1; kk++)
2734 	{
2735 	  int ent_prop_id = ent_prop_ids[kk];
2736 	  Vector<void*> *elist = dbeGetEntities (0, exp_id, ent_prop_id);
2737 	  if (!elist)
2738 	    continue;
2739 	  Vector<int> *entity_vals = (Vector<int> *) elist->fetch (0);
2740 	  Vector<char*> *jthr_names = (Vector<char*> *)elist->fetch (1);
2741 	  Vector<char*> *jthr_g_names = (Vector<char*> *)elist->fetch (2);
2742 	  Vector<char*> *jthr_p_names = (Vector<char*> *)elist->fetch (3);
2743 	  Vector<char*> *entity_name = (Vector<char*> *)elist->fetch (4);
2744 	  int nent = entity_vals->size ();
2745 	  char *entName = entity_name->fetch (0);
2746 	  if (!entName)
2747 	    entName = NTXT ("<unknown>");
2748 	  fprintf (out_file, GTXT ("  %s\n"), entName);
2749 	  for (int i = 0; i < nent; i++)
2750 	      fprintf (out_file, GTXT ("    %s=%d: %s, %s, %s\n"),
2751 		       entName, entity_vals->fetch (i),
2752 		       jthr_names->fetch (i) != NULL ? jthr_names->fetch (i) : NTXT ("N/A"),
2753 		       jthr_g_names->fetch (i) != NULL ? jthr_g_names->fetch (i) : NTXT ("N/A"),
2754 		       jthr_p_names->fetch (i) != NULL ? jthr_names->fetch (i) : NTXT ("N/A"));
2755 	  destroy (elist);
2756 	}
2757     }
2758 }
2759 
2760 void
dump_stats()2761 er_print::dump_stats ()
2762 {
2763   Emsg *m = dbev->get_path_tree ()->fetch_stats ();
2764   while (m != NULL)
2765     {
2766       fprintf (out_file, NTXT ("%s\n"), m->get_msg ());
2767       m = m->next;
2768     }
2769   dbev->get_path_tree ()->delete_stats ();
2770 }
2771 
2772 void
dump_proc_warnings()2773 er_print::dump_proc_warnings ()
2774 {
2775   PathTree *p = dbev->get_path_tree ();
2776   if (p == NULL)
2777     return;
2778   Emsg *m = p->fetch_warnings ();
2779   while (m != NULL)
2780     {
2781       fprintf (out_file, NTXT ("%s\n"), m->get_msg ());
2782       m = m->next;
2783     }
2784   dbev->get_path_tree ()->delete_warnings ();
2785 }
2786 
2787 void
print_cmd(er_print_common_display * cd)2788 er_print::print_cmd (er_print_common_display *cd)
2789 {
2790   cd->set_out_file (out_file);
2791   cd->data_dump ();
2792 }
2793 
2794 FILE *
set_outfile(char * cmd,FILE * & set_file,bool append)2795 er_print::set_outfile (char *cmd, FILE *&set_file, bool append)
2796 {
2797   FILE *new_file;
2798   char *home;
2799   if (!strcasecmp (cmd, NTXT ("-")))
2800     {
2801       new_file = stdout;
2802       out_fname = NTXT ("<stdout>");
2803     }
2804   else if (!strcasecmp (cmd, NTXT ("--")))
2805     {
2806       new_file = stderr;
2807       out_fname = NTXT ("<stderr>");
2808     }
2809   else
2810     {
2811       char *fname;
2812       char *path = NULL;
2813       // Handle ~ in file names
2814       home = getenv (NTXT ("HOME"));
2815       if ((fname = strstr (cmd, NTXT ("~/"))) != NULL && home != NULL)
2816 	path = dbe_sprintf (NTXT ("%s/%s"), home, fname + 2);
2817       else if ((fname = strstr (cmd, NTXT ("~"))) != NULL && home != NULL)
2818 	path = dbe_sprintf (NTXT ("/home/%s"), fname + 1);
2819       else
2820 	path = strdup (cmd);
2821       new_file = fopen (path, append ? NTXT ("a") : NTXT ("w"));
2822       if (new_file == NULL)
2823 	{
2824 	  fprintf (stderr, GTXT ("Error: Unable to open file: %s\n"), cmd);
2825 	  free (path);
2826 	  return NULL;
2827 	}
2828       out_fname = path;
2829     }
2830   if (set_file && set_file != stdout)
2831     fclose (set_file);
2832   set_file = new_file;
2833   return set_file;
2834 }
2835