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