"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(&not_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 }