gprof.c revision 1.5
1/*
2 * Copyright (c) 1983, 1998 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that: (1) source distributions retain this entire copyright
7 * notice and comment, and (2) distributions including binaries display
8 * the following acknowledgement:  ``This product includes software
9 * developed by the University of California, Berkeley and its contributors''
10 * in the documentation or other materials provided with the distribution
11 * and in all advertising materials mentioning features or use of this
12 * software. Neither the name of the University nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19#include "getopt.h"
20#include "libiberty.h"
21#include "gprof.h"
22#include "basic_blocks.h"
23#include "call_graph.h"
24#include "cg_arcs.h"
25#include "cg_print.h"
26#include "corefile.h"
27#include "gmon_io.h"
28#include "hertz.h"
29#include "hist.h"
30#include "source.h"
31#include "sym_ids.h"
32
33const char *whoami;
34const char *function_mapping_file;
35const char *a_out_name = A_OUTNAME;
36long hz = HZ_WRONG;
37
38/*
39 * Default options values:
40 */
41int debug_level = 0;
42int output_style = 0;
43int output_width = 80;
44bool bsd_style_output = FALSE;
45bool demangle = TRUE;
46bool discard_underscores = TRUE;
47bool ignore_direct_calls = FALSE;
48bool ignore_static_funcs = FALSE;
49bool ignore_zeros = TRUE;
50bool line_granularity = FALSE;
51bool print_descriptions = TRUE;
52bool print_path = FALSE;
53bool ignore_non_functions = FALSE;
54File_Format file_format = FF_AUTO;
55
56bool first_output = TRUE;
57
58char copyright[] =
59 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
60 All rights reserved.\n";
61
62static char *gmon_name = GMONNAME;	/* profile filename */
63
64bfd *abfd;
65
66/*
67 * Functions that get excluded by default:
68 */
69static char *default_excluded_list[] =
70{
71  "_gprof_mcount", "mcount", "_mcount", "__mcount", "__mcount_internal",
72  "__mcleanup",
73  "<locore>", "<hicore>",
74  0
75};
76
77/* Codes used for the long options with no short synonyms.  150 isn't
78   special; it's just an arbitrary non-ASCII char value.  */
79
80#define OPTION_DEMANGLE		(150)
81#define OPTION_NO_DEMANGLE	(OPTION_DEMANGLE + 1)
82
83static struct option long_options[] =
84{
85  {"line", no_argument, 0, 'l'},
86  {"no-static", no_argument, 0, 'a'},
87  {"ignore-non-functions", no_argument, 0, 'D'},
88
89    /* output styles: */
90
91  {"annotated-source", optional_argument, 0, 'A'},
92  {"no-annotated-source", optional_argument, 0, 'J'},
93  {"flat-profile", optional_argument, 0, 'p'},
94  {"no-flat-profile", optional_argument, 0, 'P'},
95  {"graph", optional_argument, 0, 'q'},
96  {"no-graph", optional_argument, 0, 'Q'},
97  {"exec-counts", optional_argument, 0, 'C'},
98  {"no-exec-counts", optional_argument, 0, 'Z'},
99  {"function-ordering", no_argument, 0, 'r'},
100  {"file-ordering", required_argument, 0, 'R'},
101  {"file-info", no_argument, 0, 'i'},
102  {"sum", no_argument, 0, 's'},
103
104    /* various options to affect output: */
105
106  {"all-lines", no_argument, 0, 'x'},
107  {"demangle", no_argument, 0, OPTION_DEMANGLE},
108  {"no-demangle", no_argument, 0, OPTION_NO_DEMANGLE},
109  {"directory-path", required_argument, 0, 'I'},
110  {"display-unused-functions", no_argument, 0, 'z'},
111  {"min-count", required_argument, 0, 'm'},
112  {"print-path", no_argument, 0, 'L'},
113  {"separate-files", no_argument, 0, 'y'},
114  {"static-call-graph", no_argument, 0, 'c'},
115  {"table-length", required_argument, 0, 't'},
116  {"time", required_argument, 0, 'n'},
117  {"no-time", required_argument, 0, 'N'},
118  {"width", required_argument, 0, 'w'},
119    /*
120     * These are for backwards-compatibility only.  Their functionality
121     * is provided by the output style options already:
122     */
123  {"", required_argument, 0, 'e'},
124  {"", required_argument, 0, 'E'},
125  {"", required_argument, 0, 'f'},
126  {"", required_argument, 0, 'F'},
127  {"", required_argument, 0, 'k'},
128
129    /* miscellaneous: */
130
131  {"brief", no_argument, 0, 'b'},
132  {"debug", optional_argument, 0, 'd'},
133  {"help", no_argument, 0, 'h'},
134  {"file-format", required_argument, 0, 'O'},
135  {"traditional", no_argument, 0, 'T'},
136  {"version", no_argument, 0, 'v'},
137  {0, no_argument, 0, 0}
138};
139
140
141static void
142DEFUN (usage, (stream, status), FILE * stream AND int status)
143{
144  fprintf (stream, _("\
145Usage: %s [-[abcDhilLsTvwxyz]] [-[ACeEfFJnNOpPqQZ][name]] [-I dirs]\n\
146	[-d[num]] [-k from/to] [-m min-count] [-t table-length]\n\
147	[--[no-]annotated-source[=name]] [--[no-]exec-counts[=name]]\n\
148	[--[no-]flat-profile[=name]] [--[no-]graph[=name]]\n\
149	[--[no-]time=name] [--all-lines] [--brief] [--debug[=level]]\n\
150	[--function-ordering] [--file-ordering]\n\
151	[--directory-path=dirs] [--display-unused-functions]\n\
152	[--file-format=name] [--file-info] [--help] [--line] [--min-count=n]\n\
153	[--no-static] [--print-path] [--separate-files]\n\
154	[--static-call-graph] [--sum] [--table-length=len] [--traditional]\n\
155	[--version] [--width=n] [--ignore-non-functions]\n\
156	[--demangle] [--no-demangle]\n\
157	[image-file] [profile-file...]\n"),
158	   whoami);
159  if (status == 0)
160    fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
161  done (status);
162}
163
164
165int
166DEFUN (main, (argc, argv), int argc AND char **argv)
167{
168  char **sp, *str;
169  Sym **cg = 0;
170  int ch, user_specified = 0;
171
172#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
173  setlocale (LC_MESSAGES, "");
174#endif
175  bindtextdomain (PACKAGE, LOCALEDIR);
176  textdomain (PACKAGE);
177
178  whoami = argv[0];
179  xmalloc_set_program_name (whoami);
180
181  while ((ch = getopt_long (argc, argv,
182	"aA::bBcCdD::e:E:f:F:hiI:J::k:lLm:n::N::O:p::P::q::Q::st:Tvw:xyzZ::",
183			    long_options, 0))
184	 != EOF)
185    {
186      switch (ch)
187	{
188	case 'a':
189	  ignore_static_funcs = TRUE;
190	  break;
191	case 'A':
192	  if (optarg)
193	    {
194	      sym_id_add (optarg, INCL_ANNO);
195	    }
196	  output_style |= STYLE_ANNOTATED_SOURCE;
197	  user_specified |= STYLE_ANNOTATED_SOURCE;
198	  break;
199	case 'b':
200	  print_descriptions = FALSE;
201	  break;
202	case 'B':
203	  output_style |= STYLE_CALL_GRAPH;
204	  user_specified |= STYLE_CALL_GRAPH;
205	  break;
206	case 'c':
207	  ignore_direct_calls = TRUE;
208	  break;
209	case 'C':
210	  if (optarg)
211	    {
212	      sym_id_add (optarg, INCL_EXEC);
213	    }
214	  output_style |= STYLE_EXEC_COUNTS;
215	  user_specified |= STYLE_EXEC_COUNTS;
216	  break;
217	case 'd':
218	  if (optarg)
219	    {
220	      debug_level |= atoi (optarg);
221	      debug_level |= ANYDEBUG;
222	    }
223	  else
224	    {
225	      debug_level = ~0;
226	    }
227	  DBG (ANYDEBUG, printf ("[main] debug-level=0x%x\n", debug_level));
228#ifndef DEBUG
229	  printf (_("%s: debugging not supported; -d ignored\n"), whoami);
230#endif	/* DEBUG */
231	  break;
232	case 'D':
233	  ignore_non_functions = TRUE;
234	  break;
235	case 'E':
236	  sym_id_add (optarg, EXCL_TIME);
237	case 'e':
238	  sym_id_add (optarg, EXCL_GRAPH);
239	  break;
240	case 'F':
241	  sym_id_add (optarg, INCL_TIME);
242	case 'f':
243	  sym_id_add (optarg, INCL_GRAPH);
244	  break;
245	case 'g':
246	  sym_id_add (optarg, EXCL_FLAT);
247	  break;
248	case 'G':
249	  sym_id_add (optarg, INCL_FLAT);
250	  break;
251	case 'h':
252	  usage (stdout, 0);
253	case 'i':
254	  output_style |= STYLE_GMON_INFO;
255	  user_specified |= STYLE_GMON_INFO;
256	  break;
257	case 'I':
258	  search_list_append (&src_search_list, optarg);
259	  break;
260	case 'J':
261	  if (optarg)
262	    {
263	      sym_id_add (optarg, EXCL_ANNO);
264	      output_style |= STYLE_ANNOTATED_SOURCE;
265	    }
266	  else
267	    {
268	      output_style &= ~STYLE_ANNOTATED_SOURCE;
269	    }
270	  user_specified |= STYLE_ANNOTATED_SOURCE;
271	  break;
272	case 'k':
273	  sym_id_add (optarg, EXCL_ARCS);
274	  break;
275	case 'l':
276	  line_granularity = TRUE;
277	  break;
278	case 'L':
279	  print_path = TRUE;
280	  break;
281	case 'm':
282	  bb_min_calls = (unsigned long) strtoul (optarg, (char **) NULL, 10);
283	  break;
284	case 'n':
285	  sym_id_add (optarg, INCL_TIME);
286	  break;
287	case 'N':
288	  sym_id_add (optarg, EXCL_TIME);
289	  break;
290	case 'O':
291	  switch (optarg[0])
292	    {
293	    case 'a':
294	      file_format = FF_AUTO;
295	      break;
296	    case 'm':
297	      file_format = FF_MAGIC;
298	      break;
299	    case 'b':
300	      file_format = FF_BSD;
301	      break;
302	    case '4':
303	      file_format = FF_BSD44;
304	      break;
305	    case 'p':
306	      file_format = FF_PROF;
307	      break;
308	    default:
309	      fprintf (stderr, _("%s: unknown file format %s\n"),
310		       optarg, whoami);
311	      done (1);
312	    }
313	  break;
314	case 'p':
315	  if (optarg)
316	    {
317	      sym_id_add (optarg, INCL_FLAT);
318	    }
319	  output_style |= STYLE_FLAT_PROFILE;
320	  user_specified |= STYLE_FLAT_PROFILE;
321	  break;
322	case 'P':
323	  if (optarg)
324	    {
325	      sym_id_add (optarg, EXCL_FLAT);
326	      output_style |= STYLE_FLAT_PROFILE;
327	    }
328	  else
329	    {
330	      output_style &= ~STYLE_FLAT_PROFILE;
331	    }
332	  user_specified |= STYLE_FLAT_PROFILE;
333	  break;
334	case 'q':
335	  if (optarg)
336	    {
337	      if (strchr (optarg, '/'))
338		{
339		  sym_id_add (optarg, INCL_ARCS);
340		}
341	      else
342		{
343		  sym_id_add (optarg, INCL_GRAPH);
344		}
345	    }
346	  output_style |= STYLE_CALL_GRAPH;
347	  user_specified |= STYLE_CALL_GRAPH;
348	  break;
349	case 'r':
350	  output_style |= STYLE_FUNCTION_ORDER;
351	  user_specified |= STYLE_FUNCTION_ORDER;
352	  break;
353	case 'R':
354	  output_style |= STYLE_FILE_ORDER;
355	  user_specified |= STYLE_FILE_ORDER;
356	  function_mapping_file = optarg;
357	  break;
358	case 'Q':
359	  if (optarg)
360	    {
361	      if (strchr (optarg, '/'))
362		{
363		  sym_id_add (optarg, EXCL_ARCS);
364		}
365	      else
366		{
367		  sym_id_add (optarg, EXCL_GRAPH);
368		}
369	      output_style |= STYLE_CALL_GRAPH;
370	    }
371	  else
372	    {
373	      output_style &= ~STYLE_CALL_GRAPH;
374	    }
375	  user_specified |= STYLE_CALL_GRAPH;
376	  break;
377	case 's':
378	  output_style |= STYLE_SUMMARY_FILE;
379	  user_specified |= STYLE_SUMMARY_FILE;
380	  break;
381	case 't':
382	  bb_table_length = atoi (optarg);
383	  if (bb_table_length < 0)
384	    {
385	      bb_table_length = 0;
386	    }
387	  break;
388	case 'T':
389	  bsd_style_output = TRUE;
390	  break;
391	case 'v':
392	  /* This output is intended to follow the GNU standards document.  */
393	  printf (_("GNU gprof %s\n"), VERSION);
394	  printf (_("Based on BSD gprof, copyright 1983 Regents of the University of California.\n"));
395	  printf (_("\
396This program is free software.  This program has absolutely no warranty.\n"));
397	  done (0);
398	case 'w':
399	  output_width = atoi (optarg);
400	  if (output_width < 1)
401	    {
402	      output_width = 1;
403	    }
404	  break;
405	case 'x':
406	  bb_annotate_all_lines = TRUE;
407	  break;
408	case 'y':
409	  create_annotation_files = TRUE;
410	  break;
411	case 'z':
412	  ignore_zeros = FALSE;
413	  break;
414	case 'Z':
415	  if (optarg)
416	    {
417	      sym_id_add (optarg, EXCL_EXEC);
418	      output_style |= STYLE_EXEC_COUNTS;
419	    }
420	  else
421	    {
422	      output_style &= ~STYLE_EXEC_COUNTS;
423	    }
424	  user_specified |= STYLE_ANNOTATED_SOURCE;
425	  break;
426	case OPTION_DEMANGLE:
427	  demangle = TRUE;
428	  break;
429	case OPTION_NO_DEMANGLE:
430	  demangle = FALSE;
431	  break;
432	default:
433	  usage (stderr, 1);
434	}
435    }
436
437  /* Don't allow both ordering options, they modify the arc data in-place.  */
438  if ((user_specified & STYLE_FUNCTION_ORDER)
439      && (user_specified & STYLE_FILE_ORDER))
440    {
441      fprintf (stderr,_("\
442%s: Only one of --function-ordering and --file-ordering may be specified.\n"),
443	       whoami);
444      done (1);
445    }
446
447  /* --sum implies --line, otherwise we'd lose b-b counts in gmon.sum */
448  if (output_style & STYLE_SUMMARY_FILE)
449    {
450      line_granularity = 1;
451    }
452
453  /* append value of GPROF_PATH to source search list if set: */
454  str = (char *) getenv ("GPROF_PATH");
455  if (str)
456    {
457      search_list_append (&src_search_list, str);
458    }
459
460  if (optind < argc)
461    {
462      a_out_name = argv[optind++];
463    }
464  if (optind < argc)
465    {
466      gmon_name = argv[optind++];
467    }
468
469  /*
470   * Turn off default functions:
471   */
472  for (sp = &default_excluded_list[0]; *sp; sp++)
473    {
474      sym_id_add (*sp, EXCL_TIME);
475      sym_id_add (*sp, EXCL_GRAPH);
476#ifdef __alpha__
477      sym_id_add (*sp, EXCL_FLAT);
478#endif
479    }
480
481  /*
482   * For line-by-line profiling, also want to keep those
483   * functions off the flat profile:
484   */
485  if (line_granularity)
486    {
487      for (sp = &default_excluded_list[0]; *sp; sp++)
488	{
489	  sym_id_add (*sp, EXCL_FLAT);
490	}
491    }
492
493  /*
494   * Read symbol table from core file:
495   */
496  core_init (a_out_name);
497
498  /*
499   * If we should ignore direct function calls, we need to load
500   * to core's text-space:
501   */
502  if (ignore_direct_calls)
503    {
504      core_get_text_space (core_bfd);
505    }
506
507  /*
508   * Create symbols from core image:
509   */
510  if (line_granularity)
511    {
512      core_create_line_syms (core_bfd);
513    }
514  else
515    {
516      core_create_function_syms (core_bfd);
517    }
518
519  /*
520   * Translate sym specs into syms:
521   */
522  sym_id_parse ();
523
524  if (file_format == FF_PROF)
525    {
526#ifdef PROF_SUPPORT_IMPLEMENTED
527      /*
528       * Get information about mon.out file(s):
529       */
530      do
531	{
532	  mon_out_read (gmon_name);
533	  if (optind < argc)
534	    {
535	      gmon_name = argv[optind];
536	    }
537	}
538      while (optind++ < argc);
539#else
540      fprintf (stderr,
541	       _("%s: sorry, file format `prof' is not yet supported\n"),
542	       whoami);
543      done (1);
544#endif
545    }
546  else
547    {
548      /*
549       * Get information about gmon.out file(s):
550       */
551      do
552	{
553	  gmon_out_read (gmon_name);
554	  if (optind < argc)
555	    {
556	      gmon_name = argv[optind];
557	    }
558	}
559      while (optind++ < argc);
560    }
561
562  /*
563   * If user did not specify output style, try to guess something
564   * reasonable:
565   */
566  if (output_style == 0)
567    {
568      if (gmon_input & (INPUT_HISTOGRAM | INPUT_CALL_GRAPH))
569	{
570	  output_style = STYLE_FLAT_PROFILE | STYLE_CALL_GRAPH;
571	}
572      else
573	{
574	  output_style = STYLE_EXEC_COUNTS;
575	}
576      output_style &= ~user_specified;
577    }
578
579  /*
580   * Dump a gmon.sum file if requested (before any other processing!):
581   */
582  if (output_style & STYLE_SUMMARY_FILE)
583    {
584      gmon_out_write (GMONSUM);
585    }
586
587  if (gmon_input & INPUT_HISTOGRAM)
588    {
589      hist_assign_samples ();
590    }
591
592  if (gmon_input & INPUT_CALL_GRAPH)
593    {
594      cg = cg_assemble ();
595    }
596
597  /* do some simple sanity checks: */
598
599  if ((output_style & STYLE_FLAT_PROFILE)
600      && !(gmon_input & INPUT_HISTOGRAM))
601    {
602      fprintf (stderr, _("%s: gmon.out file is missing histogram\n"), whoami);
603      done (1);
604    }
605
606  if ((output_style & STYLE_CALL_GRAPH) && !(gmon_input & INPUT_CALL_GRAPH))
607    {
608      fprintf (stderr,
609	       _("%s: gmon.out file is missing call-graph data\n"), whoami);
610      done (1);
611    }
612
613  /* output whatever user whishes to see: */
614
615  if (cg && (output_style & STYLE_CALL_GRAPH) && bsd_style_output)
616    {
617      cg_print (cg);		/* print the dynamic profile */
618    }
619
620  if (output_style & STYLE_FLAT_PROFILE)
621    {
622      hist_print ();		/* print the flat profile */
623    }
624
625  if (cg && (output_style & STYLE_CALL_GRAPH))
626    {
627      if (!bsd_style_output)
628	{
629	  cg_print (cg);	/* print the dynamic profile */
630	}
631      cg_print_index ();
632    }
633
634  if (output_style & STYLE_EXEC_COUNTS)
635    {
636      print_exec_counts ();
637    }
638
639  if (output_style & STYLE_ANNOTATED_SOURCE)
640    {
641      print_annotated_source ();
642    }
643  if (output_style & STYLE_FUNCTION_ORDER)
644    {
645      cg_print_function_ordering ();
646    }
647  if (output_style & STYLE_FILE_ORDER)
648    {
649      cg_print_file_ordering ();
650    }
651  return 0;
652}
653
654void
655done (status)
656     int status;
657{
658  exit (status);
659}
660