"Fossies" - the Fresh Open Source Software Archive 
Member "FunctionCheck-3.2.0/src/fcdump/fc_dump.c" (2 Jun 2012, 44431 Bytes) of package /linux/privat/old/FunctionCheck-3.2.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * FunctionCheck profiler
3 * (C) Copyright 2000-2012 Yannick Perret
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /** fc_dump.c: **/
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include "fc_dump.h"
25 #include "fc_graph.h"
26 #include "fc_tools.h"
27 #include "fc_global.h"
28 #include "fc_names.h"
29 #include "demangle.h"
30
31 /* list of arcs */
32 FC_Arc *fc_list_of_arcs = NULL;
33 int fc_nb_list_of_arcs = 0;
34
35 /* list of functions */
36 FC_Function *fc_list_of_functions = NULL;
37 int fc_nb_list_of_functions = 0;
38
39 /* list of libs */
40 FC_LDyn *fc_list_of_lib = NULL;
41 int fc_nb_list_of_lib = 0;
42
43 /* list of memory leaks */
44 FC_MLeak *fc_list_of_leaks = NULL;
45 int fc_nb_list_of_leaks = 0;
46
47 /* list of invalid free */
48 FC_MFree *fc_list_of_free = NULL;
49 int fc_nb_list_of_free = 0;
50
51 /* list of invalid realloc */
52 FC_MRealloc *fc_list_of_realloc = NULL;
53 int fc_nb_list_of_realloc = 0;
54
55 /* global flag to reverse sort order */
56 int fc_sort_order=-1;
57
58 /* gcc specific */
59 #ifndef ATTRIBUTE_UNUSED
60 #define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
61 #endif // ATTRIBUTE_UNUSED
62
63 /* the same function than scanf which test for
64 unexpected end of file */
65 #define fc_fscanf(f, args...) {int len ATTRIBUTE_UNUSED = fscanf(f, ##args); if (feof(f)) \
66 fc_message_fatal(FC_ERR_EOF, "profile data file seems to be truncated."); }
67
68 /* usage of the program */
69 void usage(char *name)
70 {
71 printf("%s V%s by Y.Perret\n", FC_PACKAGE, FC_VERSION);
72 printf("Usage: %s [options] prog\n", name);
73 printf("Options are:\n"
74 " --help : print this message\n"
75 " --version : functioncheck version\n"
76 " --contact : informations relative to functioncheck\n"
77 " -debug : switch to debug mode\n"
78 " -pfile <file> : set the profile data file name\n"
79 " -flat : display flat profile (default)\n"
80 " -no-flat : do not display flat profile\n"
81 " -sort <type> : set the sort mode for flat profile\n"
82 " -rsort <type> : set the sort mode for flat profile (reverse)\n"
83 " -cumul : add the cumuled %% of local time (-> -sort local)\n"
84 " -graph : display call-graph (default)\n"
85 " -rgraph : display reverse call-graph (callers instead of called)\n"
86 " -no-graph : do not display call-graph\n"
87 " -header : display 'FunctionDump' header (default)\n"
88 " -no-header : do not display 'FunctionDump' header\n"
89 " -info : display general informations on the profile (default)\n"
90 " -no-info : do not display general informations\n"
91 " -demangle : demangle functions name (default)\n"
92 " -demangle-gnu : demangle style GNU\n"
93 " -demangle-java : demangle style JAVA\n"
94 " -demangle-ansi : include const, volatile... (put it AFTER style)\n"
95 " -demangle-params: include function args (put it AFTER style)\n"
96 " -no-demangle : do not demangle names\n"
97 " -details : add file/line for functions name\n"
98 " -basename : use basename for files\n"
99 " -no-names : do not convert symbols into names\n"
100 " -cycles : display detected cycles in the call-graph (default)\n"
101 " -no-cycles : do not display detected cycles\n"
102 " -only <list> : only use these functions (f1,f2,f3...,fn)\n"
103 " -not <list> : do not use these functions (f1,f2,f3...,fn)\n"
104 " -propagate : propagate -not/-only effect to children\n"
105 " -rpropagate : propagate -not/-only effect to parents\n"
106 " -vcg : print call-graph in VCG format and exit\n"
107 );
108 printf(
109 " -memory : print memory informations (default)\n"
110 " -no-memory : do not print memory informations at all\n"
111 " -mem-leaks : print memory leaks (if any) (default)\n"
112 " -no-mem-leaks : do not print memory leaks\n"
113 " -mem-free : print invalid free (if any) (default)\n"
114 " -no-mem-free : do not print invalid free\n"
115 " -mem-realloc : print invalid realloc (if any) (default)\n"
116 " -no-mem-realloc: do not print invalid realloc\n"
117 " -force-names : gives addresses if symbols are not solved\n"
118 );
119
120 printf("\n"
121 "<type> for sort mode are:\n"
122 " total : by total time\n"
123 " local : by local time\n"
124 " name : by function name\n"
125 " calls : by number of calls\n"
126 " min : by min total time\n"
127 " max : by max total time\n"
128 " lmin : by min local time\n"
129 " lmax : by max local time\n");
130 printf("\n");
131 }
132
133 /* current version */
134 void version(char *name)
135 {
136 printf("%s V%s\n", FC_PACKAGE, FC_VERSION);
137 }
138
139 /* various informations */
140 void contacts(char *name)
141 {
142 printf("\n%s V%s\n\n", FC_PACKAGE, FC_VERSION);
143 printf("Author: Yannick Perret\n"
144 " mail: yperret@ligim.univ-lyon1.fr\n"
145 "\n"
146 "WEB page:\n"
147 "http://sourceforge.net/projects/fnccheck/\n"
148 "\n"
149 "Send bugs via sourceforge page.\n\n");
150 }
151
152 /** list of sort functions **/
153 /* by total time */
154 int fc_sort_total(const void *f1, const void *f2)
155 {
156 if (((FC_Function*) f1)->total_time <
157 ((FC_Function*) f2)->total_time)
158 return (fc_sort_order*-1);
159 else
160 if (((FC_Function*) f1)->total_time >
161 ((FC_Function*) f2)->total_time)
162 return (fc_sort_order * 1);
163 return 0;
164 }
165
166 /* by local time */
167 int fc_sort_local(const void *f1, const void *f2)
168 {
169 if (((FC_Function*) f1)->local_time <
170 ((FC_Function*) f2)->local_time)
171 return (fc_sort_order*-1);
172 else
173 if (((FC_Function*) f1)->local_time >
174 ((FC_Function*) f2)->local_time)
175 return (fc_sort_order * 1);
176 return 0;
177 }
178
179 /* by name time */
180 int fc_sort_name(const void *f1, const void *f2)
181 {
182 return(fc_sort_order*strcmp(((FC_Function*)f1)->name.name, ((FC_Function*)f2)->name.name));
183 }
184
185 /* by calls time */
186 int fc_sort_calls(const void *f1, const void *f2)
187 {
188 if (((FC_Function*) f1)->calls <
189 ((FC_Function*) f2)->calls)
190 return (fc_sort_order*-1);
191 else
192 if (((FC_Function*) f1)->calls >
193 ((FC_Function*) f2)->calls)
194 return (fc_sort_order * 1);
195 return 0;
196 }
197
198 /* by max time */
199 int fc_sort_max(const void *f1, const void *f2)
200 {
201 if (((FC_Function*) f1)->max_time <
202 ((FC_Function*) f2)->max_time)
203 return (fc_sort_order*-1);
204 else
205 if (((FC_Function*) f1)->max_time >
206 ((FC_Function*) f2)->max_time)
207 return (fc_sort_order * 1);
208 return 0;
209 }
210
211 /* by min time */
212 int fc_sort_min(const void *f1, const void *f2)
213 {
214 if (((FC_Function*) f1)->min_time <
215 ((FC_Function*) f2)->min_time)
216 return (fc_sort_order*-1);
217 else
218 if (((FC_Function*) f1)->min_time >
219 ((FC_Function*) f2)->min_time)
220 return (fc_sort_order * 1);
221 return 0;
222 }
223
224 /* by min local time */
225 int fc_sort_lmin(const void *f1, const void *f2)
226 {
227 if (((FC_Function*) f1)->min_ltime <
228 ((FC_Function*) f2)->min_ltime)
229 return (fc_sort_order*-1);
230 else
231 if (((FC_Function*) f1)->min_ltime >
232 ((FC_Function*) f2)->min_ltime)
233 return (fc_sort_order * 1);
234 return 0;
235 }
236
237 /* by max local time */
238 int fc_sort_lmax(const void *f1, const void *f2)
239 {
240 if (((FC_Function*) f1)->max_ltime <
241 ((FC_Function*) f2)->max_ltime)
242 return (fc_sort_order*-1);
243 else
244 if (((FC_Function*) f1)->max_ltime >
245 ((FC_Function*) f2)->max_ltime)
246 return (fc_sort_order * 1);
247 return 0;
248 }
249
250 /* get the basename of a given filename */
251 char *fc_basename(char *name)
252 {
253 int i;
254
255 for (i = strlen(name) - 1; i >= 0; i--)
256 {
257 if (name[i] == '/')
258 break;
259 }
260 if (name[i] != '/')
261 return (name);
262 return (&(name[i + 1]));
263 }
264
265 /* set a buffer with the function name or address */
266 void fc_convert_name(FC_Function *fnc, char *buffer, int details, int basen)
267 {
268 char temp[1024];
269
270 buffer[0] = '\0';
271 if (fnc->name.name != NULL)
272 strcat(buffer, fnc->name.name);
273 else
274 {
275 sprintf(buffer, "%p", fnc->symbol);
276 }
277
278 /* if details requiered */
279 if (details)
280 {
281 if (fnc->name.object == NULL)
282 strcat(buffer, ":??");
283 else
284 {
285 strcat(buffer, ":");
286 if (basen)
287 strcat(buffer, fc_basename(fnc->name.object));
288 else
289 strcat(buffer, fnc->name.object);
290 }
291 sprintf(temp, ":%d", fnc->name.line);
292 strcat(buffer, temp);
293 }
294 }
295
296 /* reads 'string' as a comma-separated list of functions and create a NSym
297 list using it. If names are addresses (in decimal or hexadecimal format)
298 they are directly converted into symbol address. */
299 int fc_read_flist(FC_NSym **list, int *nb_list, char *_string)
300 {
301 int i, nb, taddr;
302 char *pos;
303 char string[1024] = {'\0'};
304
305 /* first duplicate the incoming string (it might be write protected) */
306 strcat(string, _string);
307
308 /* count the number of ',' to allocate the list */
309 nb = 0;
310 for (i = 0; i < strlen(string); i++)
311 {
312 if (string[i] == ',')
313 nb++;
314 }
315 nb++;
316
317 /* allocate or reallocate the list */
318 if (*list == NULL)
319 {
320 if (((*list) = malloc(sizeof (FC_NSym) * nb)) == NULL)
321 {
322 fc_message("cannot allocate %d bytes for a list of functions.", sizeof (FC_NSym) * nb);
323 *list = NULL;
324 *nb_list = 0;
325 return 0;
326 }
327 }
328 else
329 {
330 if (((*list) = realloc(*list, sizeof (FC_NSym)*(*nb_list + nb))) == NULL)
331 {
332 fc_message("cannot reallocate %d bytes for a list of functions.", sizeof (FC_NSym)*(nb + *nb_list));
333 *list = NULL;
334 *nb_list = 0;
335 return 0;
336 }
337 }
338
339 /* clean up */
340 for (i = 0; i < nb; i++)
341 {
342 (*list)[*nb_list + i].name = NULL;
343 (*list)[*nb_list + i].file = NULL;
344 (*list)[*nb_list + i].addr = NULL;
345 }
346
347 /* parse each entry */
348 strtok(string, ",");
349 pos = string;
350 for (i = 0; i < nb; i++)
351 {
352 if (pos == NULL)
353 {
354 fc_message("unexpected end of function list!");
355 break;
356 }
357 /* numerical address */
358 if ((pos[0] >= '0') && (pos[0] <= '9'))
359 {
360 if ((pos[1] == 'x') || (pos[1] == 'X'))
361 {
362 /* hexadecimal address */
363 sscanf(pos, "%p", &((*list)[*nb_list + i].addr));
364 }
365 else
366 {
367 /* integer address (anyone gives integer addresses ?) */
368 sscanf(pos, "%d", &taddr);
369 (*list)[*nb_list + i].addr = (void*) taddr;
370 }
371 }
372 else
373 {
374 /* duplicate the text entry */
375 (*list)[*nb_list + i].name = strdup(pos);
376 }
377 /* go to the next token */
378 pos = strtok(NULL, ",");
379 }
380
381 /* if an unexected end of list occur, i might be < than nb */
382 *nb_list += i;
383
384 return 1;
385 }
386
387 int fc_read_stack(FILE *f, void **stack)
388 {
389 void *tmp;
390 int pos = 0, len ATTRIBUTE_UNUSED;
391
392 len = fscanf(f, "%p", &tmp);
393 while (tmp != NULL)
394 {
395 stack[pos++] = tmp;
396 if (pos == FC_MAX_STACK_SIZE - 1)
397 {
398 break;
399 }
400 len = fscanf(f, "%p", &tmp);
401 }
402 stack[pos] = NULL;
403
404 return pos;
405 }
406
407 int fc_print_stack(void **stack, FC_Name *names)
408 {
409 int i = 0;
410
411 while (stack[i] != NULL)
412 {
413 printf(" %p", stack[i]);
414 i++;
415 }
416
417 printf("\n");
418 return 1;
419 }
420
421 /* main */
422 int main(int argc, char *argv[])
423 {
424 int i, j, rj;
425 /* relative to profile data file */
426 char *pfile = NULL;
427 char *efile = NULL;
428 FILE *f;
429 /* temporary data */
430 char temp[1024];
431 /* status of the profile */
432 int time_mode, prof_mode;
433 int id, pid;
434 long long int total_time;
435 /* function pointer for sorts */
436 int (*to_sort)(const void*, const void*) = fc_sort_total;
437 /* cumul treatments */
438 int cumul = 0;
439 long long int total_cumul = 0;
440 char scum[32];
441 /* call graph modifiers */
442 int no_call_graph = 0;
443 int call_called = 0;
444 /* flat profile */
445 int no_flat_profile = 0;
446 /* header */
447 int no_header = 0;
448 /* general */
449 int no_general = 0;
450 /* demangle */
451 int demangle = 1;
452 int style = DMGL_AUTO; /* default */
453 /* details */
454 int draw_details = 0;
455 int use_basename = 0;
456 /* names */
457 int no_names = 0;
458 /* cycles */
459 int no_cycles = 0;
460 /* -only/-not list of functions (symbols and names) */
461 FC_NSym * only_list = NULL;
462 int nb_only_list = 0;
463 FC_NSym * not_list = NULL;
464 int nb_not_list = 0;
465 int do_propagate = 0;
466 int do_rpropagate = 0;
467 int nb_hide = 0; /* number of hiden functions */
468 /* call-graph output */
469 int show_callgraph = 0;
470 /* for call-stack managment */
471 int nbstack = 0;
472 /* memory info */
473 int no_memory = 0;
474 int no_memory_leaks = 0;
475 int no_memory_free = 0;
476 int no_memory_realloc = 0;
477 /* debug */
478 int debug_state = 0;
479 /* force the use of addresses if invalid object */
480 int force_names = 0;
481
482 /* name for messages */
483 fc_set_message_name(FC_DUMP_NAME);
484
485 /** first, read the options **/
486 if (argc < 2)
487 {
488 usage(argv[0]);
489 fc_message_fatal(FC_ERR_ARGS, "not enough parameters.");
490 }
491 fc_debug("reading command line (%d)", argc);
492 for (i = 1; i < argc; i++)
493 {
494 if (argv[i][0] == '-') /* an option */
495 {
496 /* print usage */
497 if ((strcmp(argv[i], "--help") == 0) ||
498 (strcmp(argv[i], "-help") == 0) ||
499 (strcmp(argv[i], "--h") == 0) ||
500 (strcmp(argv[i], "-h") == 0) ||
501 (strcmp(argv[i], "-?") == 0))
502 {
503 usage(argv[0]);
504 return (FC_ERR_OK);
505 }
506 else
507 if ((strcmp(argv[i], "--version") == 0) ||
508 (strcmp(argv[i], "-version") == 0) ||
509 (strcmp(argv[i], "--v") == 0) ||
510 (strcmp(argv[i], "-v") == 0))
511 {/* current version */
512 version(argv[0]);
513 return (FC_ERR_OK);
514 }
515 else
516 if (strcmp(argv[i], "--contact") == 0)
517 {/* various informations */
518 contacts(argv[0]);
519 return (FC_ERR_OK);
520 }
521 else
522 if (strcmp(argv[i], "-cumul") == 0)
523 {/* add cumul */
524 cumul = 1;
525 to_sort = fc_sort_local;
526 }
527 else
528 if (strcmp(argv[i], "-debug") == 0)
529 {/* debug mode */
530 debug_state = 1;
531 fc_set_debug_mode(debug_state);
532 }
533 else
534 if (strcmp(argv[i], "-no-graph") == 0)
535 {/* do not display call-graph */
536 no_call_graph = 1;
537 }
538 else
539 if (strcmp(argv[i], "-graph") == 0)
540 {/* display call-graph */
541 no_call_graph = 0;
542 call_called = 0;
543 }
544 else
545 if (strcmp(argv[i], "-rgraph") == 0)
546 {/* display reverse call-graph */
547 no_call_graph = 0;
548 call_called = 1;
549 }
550 else
551 if (strcmp(argv[i], "-flat") == 0)
552 {/* display flat profile */
553 no_flat_profile = 0;
554 }
555 else
556 if (strcmp(argv[i], "-no-flat") == 0)
557 {/* do not display flat profile */
558 no_flat_profile = 1;
559 }
560 else
561 if (strcmp(argv[i], "-info") == 0)
562 {/* display general info */
563 no_general = 0;
564 }
565 else
566 if (strcmp(argv[i], "-no-info") == 0)
567 {/* do not display general info */
568 no_general = 1;
569 }
570 else
571 if (strcmp(argv[i], "-header") == 0)
572 {/* display header */
573 no_header = 0;
574 }
575 else
576 if (strcmp(argv[i], "-no-header") == 0)
577 {/* do not display header */
578 no_header = 1;
579 }
580 else
581 if (strcmp(argv[i], "-vcg") == 0)
582 {/* only display call-graph in VCG format */
583 show_callgraph = 1;
584 }
585 else
586 if (strcmp(argv[i], "-force-names") == 0)
587 {/* force addresses if names not found */
588 force_names = 1;
589 }
590 else
591 if (strcmp(argv[i], "-demangle") == 0)
592 {/* demangle names */
593 demangle = 1;
594 style = DMGL_AUTO;
595 }
596 else
597 if (strcmp(argv[i], "-demangle-gnu") == 0)
598 {/* demangle names */
599 demangle = 1;
600 style = DMGL_GNU;
601 }
602 else
603 if (strcmp(argv[i], "-demangle-java") == 0)
604 {/* demangle names */
605 demangle = 1;
606 style = DMGL_JAVA;
607 }
608 else
609 if (strcmp(argv[i], "-demangle-ansi") == 0)
610 {/* demangle names */
611 demangle = 1;
612 style |= DMGL_ANSI;
613 }
614 else
615 if (strcmp(argv[i], "-demangle-params") == 0)
616 {/* demangle names */
617 demangle = 1;
618 style |= DMGL_PARAMS;
619 }
620 else
621 if (strcmp(argv[i], "-no-demangle") == 0)
622 {/* do not demangle names */
623 demangle = 0;
624 }
625 else
626 if (strcmp(argv[i], "-details") == 0)
627 {/* add file/line to names */
628 draw_details = 1;
629 }
630 else
631 if (strcmp(argv[i], "-basename") == 0)
632 {/* use basename for files */
633 use_basename = 1;
634 }
635 else
636 if (strcmp(argv[i], "-no-names") == 0)
637 {/* do not solve names */
638 no_names = 1;
639 }
640 else
641 if (strcmp(argv[i], "-no-cycles") == 0)
642 {/* do not display cycles */
643 no_cycles = 1;
644 }
645 else
646 if (strcmp(argv[i], "-cycles") == 0)
647 {/* display cycles */
648 no_cycles = 0;
649 }
650 else
651 if (strcmp(argv[i], "-no-memory") == 0)
652 {/* do not display memory at all */
653 no_memory = 1;
654 }
655 else
656 if (strcmp(argv[i], "-memory") == 0)
657 {/* display memory */
658 no_memory = 0;
659 }
660 else
661 if (strcmp(argv[i], "-no-mem-leaks") == 0)
662 {/* do not display memory leaks */
663 no_memory_leaks = 1;
664 }
665 else
666 if (strcmp(argv[i], "-mem-leaks") == 0)
667 {/* display memory leaks */
668 no_memory_leaks = 0;
669 }
670 else
671 if (strcmp(argv[i], "-no-mem-free") == 0)
672 {/* do not display invalid free */
673 no_memory_free = 1;
674 }
675 else
676 if (strcmp(argv[i], "-mem-free") == 0)
677 {/* display invalid free */
678 no_memory_free = 0;
679 }
680 else
681 if (strcmp(argv[i], "-no-mem-realloc") == 0)
682 {/* do not display invalid realloc */
683 no_memory_realloc = 1;
684 }
685 else
686 if (strcmp(argv[i], "-mem-realloc") == 0)
687 {/* display invalid realloc */
688 no_memory_realloc = 0;
689 }
690 else
691 if ((strcmp(argv[i], "-only") == 0) && (i + 1 < argc))
692 {/* list of functions */
693 if (!fc_read_flist(&only_list, &nb_only_list, argv[i + 1]))
694 {
695 fc_message("'-only' option will not be used.");
696 }
697 i++;
698 }
699 else
700 if ((strcmp(argv[i], "-not") == 0) && (i + 1 < argc))
701 {/* list of functions */
702 if (!fc_read_flist(¬_list, &nb_not_list, argv[i + 1]))
703 {
704 fc_message("'-not' option will not be used.");
705 }
706 i++;
707 }
708 else
709 if (strcmp(argv[i], "-propagate") == 0)
710 {/* propagate -not/-only */
711 do_propagate = 0;
712 }
713 else
714 if (strcmp(argv[i], "-rpropagate") == 0)
715 {/* reverse-propagate -not/-only */
716 do_rpropagate = 0;
717 }
718 else
719 if ((strcmp(argv[i], "-pfile") == 0) && (i + 1 < argc))
720 {/* the profile data file name */
721 if (pfile != NULL)
722 free(pfile);
723 pfile = strdup(argv[i + 1]);
724 i++;
725 }
726 else
727 if (((strcmp(argv[i], "-sort") == 0) || (strcmp(argv[i], "-rsort") == 0)) && (i + 1 < argc))
728 {/* the sort mode */
729 if (strcmp(argv[i], "-sort") == 0)
730 fc_sort_order = -1;
731 else
732 fc_sort_order = 1;
733 i++;
734 if (strcmp(argv[i], "total") == 0)
735 to_sort = fc_sort_total;
736 else
737 if (strcmp(argv[i], "local") == 0)
738 to_sort = fc_sort_local;
739 else
740 if (strcmp(argv[i], "name") == 0)
741 to_sort = fc_sort_name;
742 else
743 if (strcmp(argv[i], "calls") == 0)
744 to_sort = fc_sort_calls;
745 else
746 if (strcmp(argv[i], "min") == 0)
747 to_sort = fc_sort_min;
748 else
749 if (strcmp(argv[i], "max") == 0)
750 to_sort = fc_sort_max;
751 else
752 if (strcmp(argv[i], "lmin") == 0)
753 to_sort = fc_sort_lmin;
754 else
755 if (strcmp(argv[i], "lmax") == 0)
756 to_sort = fc_sort_lmax;
757 else
758 {
759 fc_message("WARNING: unknown sort mode '%s'. ignored.", argv[i]);
760 }
761 }
762 else
763 {
764 fc_message_fatal(FC_ERR_ARGS, "unknown option '%s'.", argv[i]);
765 }
766 }
767 else /* the program name */
768 {
769 if (efile == NULL)
770 {
771 efile = strdup(argv[i]);
772 }
773 else /* duplicatation! */
774 {
775 fc_message("program name given (%s) as an other one", argv[i]);
776 fc_message_fatal(FC_ERR_ARGS, " still exists (%s).", efile);
777 }
778 }
779 }
780
781 /* no program name! */
782 if (efile == NULL)
783 {
784 usage(argv[0]);
785 fc_message_fatal(FC_ERR_ARGS, "no program name given.");
786 }
787
788 /* default name */
789 if (pfile == NULL)
790 pfile = strdup("functioncheck.fc");
791
792 /** open the profile data file **/
793 fc_debug("opening profile data file %s", pfile);
794 if ((f = fopen(pfile, "r")) == NULL)
795 {
796 fc_message("cannot open profile data file '%s'.", pfile);
797 fc_message_fatal(FC_ERR_FOPEN, "check if file exists or if the name is correct.");
798 }
799
800 /** read general data **/
801 /* the header */
802 fc_debug(" reading headers...");
803 fc_fscanf(f, "%1023s", temp);
804 if (strcmp(temp, FC_CTX_HEADER) != 0)
805 {
806 fc_message("invalid header in profile data file '%s'.", pfile);
807 fc_message("maybe this file is not a profile data file");
808 fc_message_fatal(FC_ERR_HEADER, " or is from an old version of FunctionCheck.");
809 }
810 /* the unique ID (not used here) */
811 fc_fscanf(f, "%1023s", temp);
812 /* the time mode used */
813 fc_fscanf(f, "%d", &time_mode);
814 /* the profile mode */
815 fc_fscanf(f, "%d", &prof_mode);
816 /* the processus ID */
817 fc_fscanf(f, "%d", &id);
818 /* the parent ID */
819 fc_fscanf(f, "%d", &pid);
820 /* the execution time */
821 fc_fscanf(f, "%lld", &total_time);
822
823 /** the list of arcs **/
824 /* number of elements */
825 fc_fscanf(f, "%d", &fc_nb_list_of_arcs);
826 fc_debug(" reading arcs (%d)...", fc_nb_list_of_arcs);
827 if (fc_nb_list_of_arcs == 0)
828 {/* may never occur */
829 fc_message_fatal(FC_ERR_MEM, "empty list of arcs in profile data file!");
830 }
831 /* allocate data */
832 fc_malloc(fc_list_of_arcs, fc_nb_list_of_arcs);
833 if (fc_list_of_arcs == NULL)
834 {
835 fc_message_fatal(FC_ERR_MEM, "cannot allocate memory for arcs.");
836 }
837 /* read elements */
838 for (i = 0; i < fc_nb_list_of_arcs; i++)
839 {
840 fc_fscanf(f, "%p%p%d", &(fc_list_of_arcs[i].from),
841 &(fc_list_of_arcs[i].to), &(fc_list_of_arcs[i].number));
842 fc_list_of_arcs[i].ffrom = NULL;
843 fc_list_of_arcs[i].fto = NULL;
844 }
845
846 /** the list of functions **/
847 /* number of elements */
848 fc_fscanf(f, "%d", &fc_nb_list_of_functions);
849 fc_debug(" reading functions (%d)...", fc_nb_list_of_functions);
850 if (fc_nb_list_of_functions == 0)
851 {/* may never occur */
852 fc_message_fatal(FC_ERR_MEM, "empty list of functions in profile data file!");
853 }
854 /* allocate data */
855 fc_malloc(fc_list_of_functions, fc_nb_list_of_functions);
856 if (fc_list_of_functions == NULL)
857 {
858 fc_message_fatal(FC_ERR_MEM, "cannot allocate memory for functions.");
859 }
860 /* read elements */
861 for (i = 0; i < fc_nb_list_of_functions; i++)
862 {
863 fc_fscanf(f, "%p%d%lld%lld%lld%lld%lld%lld",
864 &(fc_list_of_functions[i].symbol),
865 &(fc_list_of_functions[i].calls),
866 &(fc_list_of_functions[i].local_time),
867 &(fc_list_of_functions[i].total_time),
868 &(fc_list_of_functions[i].min_time),
869 &(fc_list_of_functions[i].max_time),
870 &(fc_list_of_functions[i].min_ltime),
871 &(fc_list_of_functions[i].max_ltime));
872 fc_list_of_functions[i].name.name = NULL;
873 fc_list_of_functions[i].name.object = NULL;
874 fc_list_of_functions[i].name.line = 0;
875 fc_list_of_functions[i].hide = 0;
876 fc_list_of_functions[i].my_index = i;
877 fc_list_of_functions[i].node = NULL;
878 }
879
880 /** the list of dynamic libraries **/
881 /* number of elements */
882 fc_fscanf(f, "%d", &fc_nb_list_of_lib);
883 fc_debug(" reading dynamic objects (%d)...", fc_nb_list_of_lib);
884 if (fc_nb_list_of_lib >= 0)
885 {
886 /* allocate data */
887 fc_malloc(fc_list_of_lib, fc_nb_list_of_lib);
888 if (fc_list_of_lib == NULL)
889 {
890 fc_message_fatal(FC_ERR_MEM, "cannot allocate memory for lib.");
891 }
892 /* read elements */
893 for (i = 0; i < fc_nb_list_of_lib; i++)
894 {
895 fc_fscanf(f, "%p%255s", &(fc_list_of_lib[i].address),
896 fc_list_of_lib[i].name);
897 }
898 }
899
900 /** read the list of memory leaks **/
901 fc_fscanf(f, "%d", &fc_nb_list_of_leaks);
902 fc_debug(" reading memory leaks (%d)...", fc_nb_list_of_leaks);
903 /* for backward compatibility: end of file -> old version of
904 profile data files, without memory informations. Just
905 do nothing (treated as if no memory info are available) */
906 if (!feof(f))
907 {
908 if (fc_nb_list_of_leaks > 0)
909 {
910 /* allocate data */
911 fc_malloc(fc_list_of_leaks, fc_nb_list_of_leaks);
912 if (fc_list_of_leaks == NULL)
913 {
914 fc_message("cannot allocate memory for memory leaks.");
915 fc_message(" memory leaks data lost!");
916 }
917 else
918 {
919 int len ATTRIBUTE_UNUSED;
920 /* read elements */
921 for (i = 0; i < fc_nb_list_of_leaks; i++)
922 {
923 /* read common elements */
924 len = fscanf(f, "%p%u%p%p", &(fc_list_of_leaks[i].pointer),
925 &(fc_list_of_leaks[i].size),
926 &(fc_list_of_leaks[i].alloc_place),
927 &(fc_list_of_leaks[i].realloc_place));
928 /* now get the call-stack */
929 nbstack = fc_read_stack(f, fc_list_of_leaks[i].alloc_stack);
930 fc_malloc(fc_list_of_leaks[i].stack_name, nbstack);
931 }
932 }
933 }
934
935 /** read list of invalid free **/
936 fc_fscanf(f, "%d", &fc_nb_list_of_free);
937 fc_debug(" reading invalid free (%d)...", fc_nb_list_of_free);
938 if (fc_nb_list_of_free > 0)
939 {
940 /* allocate data */
941 fc_malloc(fc_list_of_free, fc_nb_list_of_free);
942 if (fc_list_of_free == NULL)
943 {
944 fc_message("cannot allocate memory for invalid free.");
945 fc_message(" invalid free data lost!");
946 }
947 else
948 {
949 int len ATTRIBUTE_UNUSED;
950 /* read elements */
951 for (i = 0; i < fc_nb_list_of_free; i++)
952 {
953 /* read common elements */
954 len = fscanf(f, "%p%p", &(fc_list_of_free[i].free_place),
955 &(fc_list_of_free[i].pointer));
956 /* now get the call-stack */
957 nbstack = fc_read_stack(f, fc_list_of_free[i].free_stack);
958 fc_malloc(fc_list_of_free[i].stack_name, nbstack);
959 }
960 }
961 }
962
963 /** read list of invalid realloc **/
964 fc_fscanf(f, "%d", &fc_nb_list_of_realloc);
965 fc_debug(" reading invalid realloc (%d)...", fc_nb_list_of_realloc);
966 if (fc_nb_list_of_realloc > 0)
967 {
968 /* allocate data */
969 fc_malloc(fc_list_of_realloc, fc_nb_list_of_realloc);
970 if (fc_list_of_realloc == NULL)
971 {
972 fc_message("cannot allocate memory for invalid realloc.");
973 fc_message(" invalid realloc data lost!");
974 }
975 else
976 {
977 int len ATTRIBUTE_UNUSED;
978 /* read elements */
979 for (i = 0; i < fc_nb_list_of_realloc; i++)
980 {
981 /* read common elements */
982 len = fscanf(f, "%p%p", &(fc_list_of_realloc[i].realloc_place),
983 &(fc_list_of_realloc[i].pointer));
984 /* now get the call-stack */
985 nbstack = fc_read_stack(f, fc_list_of_realloc[i].realloc_stack);
986 fc_malloc(fc_list_of_realloc[i].stack_name, nbstack);
987 }
988 }
989 }
990 }
991 /* if no data, switch to no_memory */
992 if ((fc_nb_list_of_realloc == 0) && (fc_nb_list_of_free == 0)
993 && (fc_nb_list_of_leaks == 0))
994 no_memory = 1;
995
996 /** ok. close file **/
997 fc_debug("done.");
998 fclose(f);
999
1000 /** treat data **/
1001
1002 /** solve symbols name **/
1003 fc_debug("computing names...");
1004 if (!no_names)
1005 if (!fc_names_solve(force_names,
1006 fc_nb_list_of_functions, fc_list_of_functions,
1007 fc_nb_list_of_lib, fc_list_of_lib,
1008 fc_nb_list_of_arcs, fc_list_of_arcs,
1009 efile, demangle, style,
1010 only_list, nb_only_list,
1011 not_list, nb_not_list,
1012 no_memory || no_memory_leaks ? 0 : fc_nb_list_of_leaks,
1013 no_memory || no_memory_leaks ? NULL : fc_list_of_leaks,
1014 no_memory || no_memory_free ? 0 : fc_nb_list_of_free,
1015 no_memory || no_memory_free ? NULL : fc_list_of_free,
1016 no_memory || no_memory_realloc ? 0 : fc_nb_list_of_realloc,
1017 no_memory || no_memory_realloc ? NULL : fc_list_of_realloc))
1018 {
1019 fc_message("WARNING: error while solving names.");
1020 fc_message(" names will not be available.");
1021 }
1022
1023 /* sort the list of functions */
1024 fc_debug("sorting functions...");
1025 qsort(fc_list_of_functions, fc_nb_list_of_functions,
1026 sizeof (FC_Function), to_sort);
1027
1028 /** compute the call-graph **/
1029 fc_debug("computing call-graph...");
1030 if (!fc_graph_create(&fc_nb_list_of_arcs, fc_list_of_arcs,
1031 fc_nb_list_of_functions, fc_list_of_functions,
1032 only_list, nb_only_list,
1033 not_list, nb_not_list,
1034 do_propagate, do_rpropagate))
1035 {
1036 fc_message("removing call-graph features.");
1037 no_call_graph = 1;
1038 }
1039
1040 fc_debug("ok.");
1041
1042 /** if requested, output the call-graph in order to be display
1043 with software 'CVG' (a GPL graph visualizer) **/
1044 if (show_callgraph)
1045 {
1046 printf("graph: {\n");
1047 printf(" orientation: left_to_right\n");
1048 /* display nodes */
1049 for (i = 0; i < fc_nb_list_of_functions; i++)
1050 {
1051 printf(" node: { title: \"%d\" label: \"%s\" borderwidth:0}\n",
1052 i, fc_list_of_functions[i].name.name);
1053 }
1054 /* display edges */
1055 for (i = 0; i < fc_nb_list_of_functions; i++)
1056 {
1057 j = 0;
1058 while (((FC_Node*) (fc_list_of_functions[i].node))->nexts[j] != NULL)
1059 {
1060 printf(" edge: { sourcename: \"%d\" targetname: \"%d\" thickness: 1}\n",
1061 i, ((FC_Node*) (fc_list_of_functions[i].node))->nexts[j]->function->my_index);
1062 j++;
1063 }
1064 }
1065 printf(" }\n");
1066
1067 /* I should add memory cleanup here */
1068 return FC_ERR_OK;
1069 }
1070
1071 /** compute how many functions are hidden **/
1072 nb_hide = 0;
1073 for (i = 0; i < fc_nb_list_of_functions; i++)
1074 {
1075 if (fc_list_of_functions[i].hide)
1076 nb_hide++;
1077 }
1078
1079 /** display known informations **/
1080 if (!no_header)
1081 {
1082 printf("\n%s V%s by Y.Perret\n\n", FC_PACKAGE, FC_VERSION);
1083 }
1084
1085 if (!no_general)
1086 {
1087 printf("Execution profile for program '%s'\n", efile);
1088 printf("Time mode used is: ");
1089 if (time_mode == FC_MTIME_EXT)
1090 printf("clock time\n");
1091 else
1092 if (time_mode == FC_MTIME_CPU)
1093 printf("CPU time\n");
1094 else
1095 if (time_mode == FC_MTIME_TSC)
1096 printf("Time stamp counter\n");
1097 else
1098 printf("unknown\n");
1099 printf("Profile mode is: ");
1100 if (prof_mode == FC_MODE_SINGLE)
1101 printf("single process\n");
1102 else
1103 if (prof_mode == FC_MODE_FORK)
1104 printf("forks allowed\n");
1105 else
1106 if (prof_mode == FC_MODE_THREAD)
1107 printf("threads allowed\n");
1108 else
1109 printf("unknown\n");
1110 printf("ID of this process is %d\n", id);
1111 printf("Total time spend in this process is %f\n", total_time / 1000000.);
1112
1113 printf("\n\n");
1114 printf("%d arc(s), %d function(s) (%d shown, %d hidden), %d library(ies)\n", fc_nb_list_of_arcs,
1115 fc_nb_list_of_functions, fc_nb_list_of_functions - nb_hide,
1116 nb_hide, fc_nb_list_of_lib);
1117 printf("\n\n");
1118 }
1119
1120 /** display flat profile **/
1121 if (!no_flat_profile)
1122 {
1123 printf(" total | local %s| total | local | # |function\n"
1124 " time | %% | time | %% %s| min | max | min | max | calls | name\n"
1125 "-------|-----|-------|-----%s|-------|-------|-------|-------|-------|--------\n",
1126 cumul ? " " : "",
1127 cumul ? "|cum %" : "",
1128 cumul ? "|-----" : "");
1129 for (i = 0; i < fc_nb_list_of_functions; i++)
1130 {
1131 if (!fc_list_of_functions[i].hide)
1132 {
1133 fc_convert_name(&(fc_list_of_functions[i]), temp, draw_details, use_basename);
1134 total_cumul += fc_list_of_functions[i].local_time;
1135 if (cumul)
1136 {
1137 sprintf(scum, "|%5.1f", (100. * ((total_cumul / 1000000.) /
1138 (total_time / 1000000.))));
1139 }
1140 printf("%7.2f|%5.1f|%7.2f|%5.1f%s|%7.2f|%7.2f|%7.2f|%7.2f|%7d| %s\n",
1141 fc_list_of_functions[i].total_time / 1000000.,
1142 (100. * ((fc_list_of_functions[i].total_time / 1000000.) /
1143 (total_time / 1000000.))),
1144 fc_list_of_functions[i].local_time / 1000000.,
1145 (100. * ((fc_list_of_functions[i].local_time / 1000000.) /
1146 (total_time / 1000000.))),
1147 cumul ? scum : "",
1148 fc_list_of_functions[i].min_time / 1000000.,
1149 fc_list_of_functions[i].max_time / 1000000.,
1150 fc_list_of_functions[i].min_ltime / 1000000.,
1151 fc_list_of_functions[i].max_ltime / 1000000.,
1152 fc_list_of_functions[i].calls,
1153 temp);
1154 }
1155 }
1156 printf("\n");
1157 }
1158
1159 /** display the call-graph **/
1160 if (!no_call_graph)
1161 {
1162 printf("\nCall-graph:\n\n");
1163
1164 /* for each function */
1165 for (i = 0; i < fc_nb_list_of_functions; i++)
1166 {
1167 if (!fc_list_of_functions[i].hide)
1168 {
1169 fc_convert_name(&(fc_list_of_functions[i]), temp, draw_details, use_basename);
1170 if (call_called)
1171 printf("'%s' called by:\n", temp);
1172 else
1173 printf("'%s' calls:\n", temp);
1174
1175 /* for each child */
1176 j = 0;
1177 rj = 0;
1178 if (fc_list_of_functions[i].node != NULL)
1179 {
1180 if (call_called)
1181 while (((FC_Node*) (fc_list_of_functions[i].node))->prevs[j] != NULL)
1182 {
1183 if (!(((FC_Node*) (fc_list_of_functions[i].node))->prevs[j]->function->hide))
1184 {
1185 fc_convert_name(((FC_Node*) (fc_list_of_functions[i].node))->prevs[j]->function,
1186 temp, draw_details, use_basename);
1187 printf(" (%d) %s", ((FC_Node*) (fc_list_of_functions[i].node))->nprevs[j], temp);
1188 rj++;
1189 }
1190 j++;
1191 }
1192 else
1193 while (((FC_Node*) (fc_list_of_functions[i].node))->nexts[j] != NULL)
1194 {
1195 if (!(((FC_Node*) (fc_list_of_functions[i].node))->nexts[j]->function->hide))
1196 {
1197 fc_convert_name(((FC_Node*) (fc_list_of_functions[i].node))->nexts[j]->function,
1198 temp, draw_details, use_basename);
1199 printf(" (%d) %s", ((FC_Node*) (fc_list_of_functions[i].node))->nnexts[j], temp);
1200 rj++;
1201 }
1202 j++;
1203 }
1204 if (rj == 0)
1205 {
1206 printf(" nobody\n");
1207 }
1208 else
1209 printf("\n");
1210 }
1211 else
1212 { /* argl! this function exists in the list of functions,
1213 but no arcs comes to it! don't know WHY it happends,
1214 but in some case it happends... so this test prevent crashes */
1215 printf(" this function is not in the call-graph!\n");
1216 printf(" this message is a protection against a known bug\n");
1217 }
1218 printf("\n");
1219 }
1220 }
1221 }
1222
1223 /** cycles **/
1224 if (!no_cycles)
1225 {
1226 printf("Detected cycle(s):\n\n");
1227 if (!fc_compute_cycles(0)) /* this '0' is an unused option flag */
1228 printf("No cycles.\n");
1229 printf("\n");
1230 }
1231
1232 /** memory informations **/
1233 if (!no_memory)
1234 {
1235 /** memory leaks **/
1236 if (!no_memory_leaks)
1237 {
1238 printf("Memory leaks detected:\n\n");
1239 for (i = 0; i < fc_nb_list_of_leaks; i++)
1240 {
1241 printf("Block %p of original size %u\n",
1242 fc_list_of_leaks[i].pointer,
1243 fc_list_of_leaks[i].size);
1244 printf(" allocated at %p\n", fc_list_of_leaks[i].alloc_place);
1245 if (fc_list_of_leaks[i].realloc_place != NULL)
1246 printf(" reallocated at %p\n",
1247 fc_list_of_leaks[i].realloc_place);
1248 printf(" allocation call-stack was:\n");
1249 printf(" ");
1250 fc_print_stack(fc_list_of_leaks[i].alloc_stack,
1251 fc_list_of_leaks[i].stack_name);
1252 printf(" was never freed.\n\n");
1253 }
1254 if (fc_nb_list_of_leaks == 0)
1255 printf("none.\n");
1256 printf("\n");
1257 }
1258
1259 /** invalid free **/
1260 if (!no_memory_free)
1261 {
1262 printf("Invalid free detected:\n\n");
1263 for (i = 0; i < fc_nb_list_of_free; i++)
1264 {
1265 printf("Call to 'free' with unreferenced pointer %p\n",
1266 fc_list_of_free[i].pointer);
1267 printf(" at %p\n", fc_list_of_free[i].free_place);
1268 printf(" free call-stack was:\n");
1269 printf(" ");
1270 fc_print_stack(fc_list_of_free[i].free_stack,
1271 fc_list_of_free[i].stack_name);
1272 printf("\n");
1273 }
1274 if (fc_nb_list_of_free == 0)
1275 printf("none.\n");
1276 printf("\n");
1277 }
1278
1279 /** invalid realloc **/
1280 if (!no_memory_realloc)
1281 {
1282 printf("Invalid realloc detected:\n\n");
1283 for (i = 0; i < fc_nb_list_of_realloc; i++)
1284 {
1285 printf("Call to 'realloc' with unreferenced pointer %p\n",
1286 fc_list_of_realloc[i].pointer);
1287 printf(" at %p\n", fc_list_of_realloc[i].realloc_place);
1288 printf(" realloc call-stack was:\n");
1289 printf(" ");
1290 fc_print_stack(fc_list_of_realloc[i].realloc_stack,
1291 fc_list_of_realloc[i].stack_name);
1292 printf("\n");
1293 }
1294 if (fc_nb_list_of_realloc == 0)
1295 printf("none.\n");
1296 printf("\n");
1297 }
1298 }
1299
1300 /** freed all data **/
1301 fc_debug("freeing data...");
1302 if (!no_call_graph)
1303 fc_graph_delete(fc_nb_list_of_arcs, fc_list_of_arcs,
1304 fc_nb_list_of_functions, fc_list_of_functions);
1305 if (fc_list_of_arcs != NULL)
1306 free(fc_list_of_arcs);
1307 if (fc_list_of_functions != NULL)
1308 free(fc_list_of_functions);
1309 if (fc_list_of_lib != NULL)
1310 free(fc_list_of_lib);
1311
1312 /* end */
1313 fc_debug("exit.");
1314 return (FC_ERR_OK);
1315 }