* __bb_exit_func.c: New file, from David Mosberger-Tang.
[binutils-gdb.git] / gprof / gprof.c
1 /*
2 * Copyright (c) 1983 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 "core.h"
27 #include "gmon_io.h"
28 #include "hertz.h"
29 #include "hist.h"
30 #include "source.h"
31 #include "sym_ids.h"
32
33 #define VERSION "2.6"
34
35 const char *whoami;
36 const char *a_out_name = A_OUTNAME;
37 long hz = HZ_WRONG;
38
39 /*
40 * Default options values:
41 */
42 int debug_level = 0;
43 int output_style = 0;
44 int output_width = 80;
45 bool bsd_style_output = FALSE;
46 bool discard_underscores = TRUE;
47 bool ignore_direct_calls = FALSE;
48 bool ignore_static_funcs = FALSE;
49 bool ignore_zeros = TRUE;
50 bool line_granularity = FALSE;
51 bool print_descriptions = TRUE;
52 bool print_path = FALSE;
53 File_Format file_format = FF_AUTO;
54
55 bool first_output = TRUE;
56
57 char copyright[] =
58 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
59 All rights reserved.\n";
60
61 static char *gmon_name = GMONNAME; /* profile filename */
62
63 bfd *abfd;
64
65 /*
66 * Functions that get excluded by default:
67 */
68 static char *default_excluded_list[] =
69 {
70 "_gprof_mcount", "mcount", "_mcount", "__mcleanup",
71 "<locore>", "<hicore>",
72 0
73 };
74
75 static struct option long_options[] =
76 {
77 {"line", no_argument, 0, 'l'},
78 {"no-static", no_argument, 0, 'a'},
79
80 /* output styles: */
81
82 {"annotated-source", optional_argument, 0, 'A'},
83 {"no-annotated-source", optional_argument, 0, 'J'},
84 {"flat-profile", optional_argument, 0, 'p'},
85 {"no-flat-profile", optional_argument, 0, 'P'},
86 {"graph", optional_argument, 0, 'q'},
87 {"no-graph", optional_argument, 0, 'Q'},
88 {"exec-counts", optional_argument, 0, 'C'},
89 {"no-exec-counts", optional_argument, 0, 'Z'},
90 {"file-info", no_argument, 0, 'i'},
91 {"sum", no_argument, 0, 's'},
92
93 /* various options to affect output: */
94
95 {"all-lines", no_argument, 0, 'x'},
96 {"directory-path", required_argument, 0, 'I'},
97 {"display-unused-functions", no_argument, 0, 'z'},
98 {"min-count", required_argument, 0, 'm'},
99 {"print-path", no_argument, 0, 'L'},
100 {"separate-files", no_argument, 0, 'y'},
101 {"static-call-graph", no_argument, 0, 'c'},
102 {"table-length", required_argument, 0, 't'},
103 {"time", required_argument, 0, 'n'},
104 {"no-time", required_argument, 0, 'N'},
105 {"width", required_argument, 0, 'w'},
106 /*
107 * These are for backwards-compatibility only. Their functionality
108 * is provided by the output style options already:
109 */
110 {"", required_argument, 0, 'e'},
111 {"", required_argument, 0, 'E'},
112 {"", required_argument, 0, 'f'},
113 {"", required_argument, 0, 'F'},
114 {"", required_argument, 0, 'k'},
115
116 /* miscellaneous: */
117
118 {"brief", no_argument, 0, 'b'},
119 {"debug", optional_argument, 0, 'd'},
120 {"help", no_argument, 0, 'h'},
121 {"file-format", required_argument, 0, 'O'},
122 {"traditional", no_argument, 0, 'T'},
123 {"version", no_argument, 0, 'v'},
124 {0, no_argument, 0, 0}
125 };
126
127
128 static void
129 DEFUN (usage, (stream, status), FILE * stream AND int status)
130 {
131 fprintf (stream, "\
132 Usage: %s [-[abchilLsTvwxyz]] [-[ACeEfFJnNOpPqQZ][name]] [-I dirs]\n\
133 [-d[num]] [-k from/to] [-m min-count] [-t table-length]\n\
134 [--[no-]annotated-source[=name]] [--[no-]exec-counts[=name]]\n\
135 [--[no-]flat-profile[=name]] [--[no-]graph[=name]]\n\
136 [--[no-]time=name] [--all-lines] [--brief] [--debug[=level]]\n\
137 [--directory-path=dirs] [--display-unused-functions]\n\
138 [--file-format=name] [--file-info] [--help] [--line] [--min-count=n]\n\
139 [--no-static] [--print-path] [--separate-files]\n\
140 [--static-call-graph] [--sum] [--table-length=len] [--traditional]\n\
141 [--version] [--width=n]\n\
142 [image-file] [profile-file...]\n",
143 whoami);
144 done (status);
145 }
146
147
148 int
149 DEFUN (main, (argc, argv), int argc AND char **argv)
150 {
151 char **sp, *str;
152 Sym **cg = 0;
153 int ch, user_specified = 0;
154
155 whoami = argv[0];
156 xmalloc_set_program_name (whoami);
157
158 while ((ch = getopt_long (argc, argv,
159 "aA::bBcCd::e:E:f:F:hiI:J::k:lLm:n::N::O:p::P::q::Q::st:Tvw:xyzZ::",
160 long_options, 0))
161 != EOF)
162 {
163 switch (ch)
164 {
165 case 'a':
166 ignore_static_funcs = TRUE;
167 break;
168 case 'A':
169 if (optarg)
170 {
171 sym_id_add (optarg, INCL_ANNO);
172 }
173 output_style |= STYLE_ANNOTATED_SOURCE;
174 user_specified |= STYLE_ANNOTATED_SOURCE;
175 break;
176 case 'b':
177 print_descriptions = FALSE;
178 break;
179 case 'B':
180 output_style |= STYLE_CALL_GRAPH;
181 user_specified |= STYLE_CALL_GRAPH;
182 break;
183 case 'c':
184 ignore_direct_calls = TRUE;
185 break;
186 case 'C':
187 if (optarg)
188 {
189 sym_id_add (optarg, INCL_EXEC);
190 }
191 output_style |= STYLE_EXEC_COUNTS;
192 user_specified |= STYLE_EXEC_COUNTS;
193 break;
194 case 'd':
195 if (optarg)
196 {
197 debug_level |= atoi (optarg);
198 debug_level |= ANYDEBUG;
199 }
200 else
201 {
202 debug_level = ~0;
203 }
204 DBG (ANYDEBUG, printf ("[main] debug-level=0x%x\n", debug_level));
205 #ifndef DEBUG
206 printf ("%s: debugging not supported; -d ignored\n", whoami);
207 #endif /* DEBUG */
208 break;
209 case 'E':
210 sym_id_add (optarg, EXCL_TIME);
211 case 'e':
212 sym_id_add (optarg, EXCL_GRAPH);
213 break;
214 case 'F':
215 sym_id_add (optarg, INCL_TIME);
216 case 'f':
217 sym_id_add (optarg, INCL_GRAPH);
218 break;
219 case 'g':
220 sym_id_add (optarg, EXCL_FLAT);
221 break;
222 case 'G':
223 sym_id_add (optarg, INCL_FLAT);
224 break;
225 case 'h':
226 usage (stdout, 0);
227 case 'i':
228 output_style |= STYLE_GMON_INFO;
229 user_specified |= STYLE_GMON_INFO;
230 break;
231 case 'I':
232 search_list_append (&src_search_list, optarg);
233 break;
234 case 'J':
235 if (optarg)
236 {
237 sym_id_add (optarg, EXCL_ANNO);
238 output_style |= STYLE_ANNOTATED_SOURCE;
239 }
240 else
241 {
242 output_style &= ~STYLE_ANNOTATED_SOURCE;
243 }
244 user_specified |= STYLE_ANNOTATED_SOURCE;
245 break;
246 case 'k':
247 sym_id_add (optarg, EXCL_ARCS);
248 break;
249 case 'l':
250 line_granularity = TRUE;
251 break;
252 case 'L':
253 print_path = TRUE;
254 break;
255 case 'm':
256 bb_min_calls = atoi (optarg);
257 break;
258 case 'n':
259 sym_id_add (optarg, INCL_TIME);
260 break;
261 case 'N':
262 sym_id_add (optarg, EXCL_TIME);
263 break;
264 case 'O':
265 switch (optarg[0])
266 {
267 case 'a':
268 file_format = FF_AUTO;
269 break;
270 case 'm':
271 file_format = FF_MAGIC;
272 break;
273 case 'b':
274 file_format = FF_BSD;
275 break;
276 case 'p':
277 file_format = FF_PROF;
278 break;
279 default:
280 fprintf (stderr, "%s: unknown file format %s\n",
281 optarg, whoami);
282 done (1);
283 }
284 break;
285 case 'p':
286 if (optarg)
287 {
288 sym_id_add (optarg, INCL_FLAT);
289 }
290 output_style |= STYLE_FLAT_PROFILE;
291 user_specified |= STYLE_FLAT_PROFILE;
292 break;
293 case 'P':
294 if (optarg)
295 {
296 sym_id_add (optarg, EXCL_FLAT);
297 output_style |= STYLE_FLAT_PROFILE;
298 }
299 else
300 {
301 output_style &= ~STYLE_FLAT_PROFILE;
302 }
303 user_specified |= STYLE_FLAT_PROFILE;
304 break;
305 case 'q':
306 if (optarg)
307 {
308 if (strchr (optarg, '/'))
309 {
310 sym_id_add (optarg, INCL_ARCS);
311 }
312 else
313 {
314 sym_id_add (optarg, INCL_GRAPH);
315 }
316 }
317 output_style |= STYLE_CALL_GRAPH;
318 user_specified |= STYLE_CALL_GRAPH;
319 break;
320 case 'Q':
321 if (optarg)
322 {
323 if (strchr (optarg, '/'))
324 {
325 sym_id_add (optarg, EXCL_ARCS);
326 }
327 else
328 {
329 sym_id_add (optarg, EXCL_GRAPH);
330 }
331 output_style |= STYLE_CALL_GRAPH;
332 }
333 else
334 {
335 output_style &= ~STYLE_CALL_GRAPH;
336 }
337 user_specified |= STYLE_CALL_GRAPH;
338 break;
339 case 's':
340 output_style |= STYLE_SUMMARY_FILE;
341 user_specified |= STYLE_SUMMARY_FILE;
342 break;
343 case 't':
344 bb_table_length = atoi (optarg);
345 if (bb_table_length < 0)
346 {
347 bb_table_length = 0;
348 }
349 break;
350 case 'T':
351 bsd_style_output = TRUE;
352 break;
353 case 'v':
354 printf ("%s version %s\n", whoami, VERSION);
355 done (0);
356 case 'w':
357 output_width = atoi (optarg);
358 if (output_width < 1)
359 {
360 output_width = 1;
361 }
362 break;
363 case 'x':
364 bb_annotate_all_lines = TRUE;
365 break;
366 case 'y':
367 create_annotation_files = TRUE;
368 break;
369 case 'z':
370 ignore_zeros = FALSE;
371 break;
372 case 'Z':
373 if (optarg)
374 {
375 sym_id_add (optarg, EXCL_EXEC);
376 output_style |= STYLE_EXEC_COUNTS;
377 }
378 else
379 {
380 output_style &= ~STYLE_EXEC_COUNTS;
381 }
382 user_specified |= STYLE_ANNOTATED_SOURCE;
383 break;
384 default:
385 usage (stderr, 1);
386 }
387 }
388
389 /* append value of GPROF_PATH to source search list if set: */
390 str = getenv ("GPROF_PATH");
391 if (str)
392 {
393 search_list_append (&src_search_list, str);
394 }
395
396 if (optind < argc)
397 {
398 a_out_name = argv[optind++];
399 }
400 if (optind < argc)
401 {
402 gmon_name = argv[optind++];
403 }
404
405 /*
406 * Turn off default functions:
407 */
408 for (sp = &default_excluded_list[0]; *sp; sp++)
409 {
410 sym_id_add (*sp, EXCL_TIME);
411 sym_id_add (*sp, EXCL_GRAPH);
412 #ifdef __osf__
413 sym_id_add (*sp, EXCL_FLAT);
414 #endif
415 }
416
417 /*
418 * For line-by-line profiling, also want to keep those
419 * functions off the flat profile:
420 */
421 if (line_granularity)
422 {
423 for (sp = &default_excluded_list[0]; *sp; sp++)
424 {
425 sym_id_add (*sp, EXCL_FLAT);
426 }
427 }
428
429 /*
430 * Read symbol table from core file:
431 */
432 core_init (a_out_name);
433
434 /*
435 * If we should ignore direct function calls, we need to load
436 * to core's text-space:
437 */
438 if (ignore_direct_calls)
439 {
440 core_get_text_space (core_bfd);
441 }
442
443 /*
444 * Create symbols from core image:
445 */
446 if (line_granularity)
447 {
448 core_create_line_syms (core_bfd);
449 }
450 else
451 {
452 core_create_function_syms (core_bfd);
453 }
454
455 /*
456 * Translate sym specs into syms:
457 */
458 sym_id_parse ();
459
460 if (file_format == FF_PROF)
461 {
462 #ifdef PROF_SUPPORT_IMPLEMENTED
463 /*
464 * Get information about mon.out file(s):
465 */
466 do
467 {
468 mon_out_read (gmon_name);
469 if (optind < argc)
470 {
471 gmon_name = argv[optind];
472 }
473 }
474 while (optind++ < argc);
475 #else
476 fprintf (stderr,
477 "%s: sorry, file format `prof' is not yet supported\n",
478 whoami);
479 done (1);
480 #endif
481 }
482 else
483 {
484 /*
485 * Get information about gmon.out file(s):
486 */
487 do
488 {
489 gmon_out_read (gmon_name);
490 if (optind < argc)
491 {
492 gmon_name = argv[optind];
493 }
494 }
495 while (optind++ < argc);
496 }
497
498 /*
499 * If user did not specify output style, try to guess something
500 * reasonable:
501 */
502 if (output_style == 0)
503 {
504 if (gmon_input & (INPUT_HISTOGRAM | INPUT_CALL_GRAPH))
505 {
506 output_style = STYLE_FLAT_PROFILE | STYLE_CALL_GRAPH;
507 }
508 else
509 {
510 output_style = STYLE_EXEC_COUNTS;
511 }
512 output_style &= ~user_specified;
513 }
514
515 /*
516 * Dump a gmon.sum file if requested (before any other processing!):
517 */
518 if (output_style & STYLE_SUMMARY_FILE)
519 {
520 gmon_out_write (GMONSUM);
521 }
522
523 if (gmon_input & INPUT_HISTOGRAM)
524 {
525 hist_assign_samples ();
526 }
527
528 if (gmon_input & INPUT_CALL_GRAPH)
529 {
530 cg = cg_assemble ();
531 }
532
533 /* do some simple sanity checks: */
534
535 if ((output_style & STYLE_FLAT_PROFILE)
536 && !(gmon_input & INPUT_HISTOGRAM))
537 {
538 fprintf (stderr, "%s: gmon.out file is missing histogram\n", whoami);
539 done (1);
540 }
541
542 if ((output_style & STYLE_CALL_GRAPH) && !(gmon_input & INPUT_CALL_GRAPH))
543 {
544 fprintf (stderr,
545 "%s: gmon.out file is missing call-graph data\n", whoami);
546 done (1);
547 }
548
549 /* output whatever user whishes to see: */
550
551 if (cg && (output_style & STYLE_CALL_GRAPH) && bsd_style_output)
552 {
553 cg_print (cg); /* print the dynamic profile */
554 }
555
556 if (output_style & STYLE_FLAT_PROFILE)
557 {
558 hist_print (); /* print the flat profile */
559 }
560
561 if (cg && (output_style & STYLE_CALL_GRAPH))
562 {
563 if (!bsd_style_output)
564 {
565 cg_print (cg); /* print the dynamic profile */
566 }
567 cg_print_index ();
568 }
569
570 if (output_style & STYLE_EXEC_COUNTS)
571 {
572 print_exec_counts ();
573 }
574
575 if (output_style & STYLE_ANNOTATED_SOURCE)
576 {
577 print_annotated_source ();
578 }
579 return 0;
580 }
581
582 void
583 done (status)
584 int status;
585 {
586 exit (status);
587 }