"Fossies" - the Fresh Open Source Software Archive

Member "FunctionCheck-3.2.0/src/fcdump/fc_names.c" (26 May 2012, 16685 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_names.c:  **/
   20 
   21 #include <stdio.h>
   22 #include <stdlib.h>
   23 #include <string.h>
   24 #include "demangle.h"
   25 #include "fc_names.h"
   26 
   27 /** static string to prevent 'null' names **/
   28 #define FC_INVALID_NAME  "<error>"
   29 
   30 /** symbol list for low-level access to BFD data (local) **/
   31 typedef struct
   32 {
   33   char *name;
   34   void *addr;
   35   int flag;  /* an exported function */
   36 } FC_Sym;
   37 
   38 /* local table to treat symbols */
   39 FC_Sym *fc_syms = NULL;
   40 int fc_nb_syms  = 0;
   41 
   42 /* open a binary object using BFD */
   43 int fc_open_bfd_file(char *name, bfd **core_bfd, int *core_num_syms,
   44                      asection **core_text_sect, asymbol ***core_syms,
   45              int *core_min_insn_size, int *core_offset_to_code)
   46 {
   47     *core_bfd = bfd_openr(name, 0);
   48     if (!(*core_bfd))
   49     {
   50         fc_message("cannot open file %s", name);
   51         return 0;
   52     }
   53 
   54     /* check format */
   55     if (!bfd_check_format(*core_bfd, bfd_object))
   56     {
   57         fc_message("file '%s' is not an object", name);
   58         return 0;
   59     }
   60 
   61     /* get TEXT section */ /* ".text" */
   62     *core_text_sect = bfd_get_section_by_name(*core_bfd, ".text");
   63     if (!(*core_text_sect))
   64     {
   65         fc_message("BFD: trying $CODE$ section instead of .text");
   66         *core_text_sect = bfd_get_section_by_name(*core_bfd, "$CODE$");
   67         if (!(*core_text_sect))
   68         {
   69             fc_message("no TEXT section in object '%s'", name);
   70             return 0;
   71         }
   72     }
   73 
   74     /* read symbol table */
   75     *core_num_syms = bfd_get_symtab_upper_bound(*core_bfd);
   76     if (*core_num_syms < 0)
   77     {
   78         fc_message("bfd error: %s", bfd_errmsg(bfd_get_error()));
   79         return 0;
   80     }
   81 
   82     *core_syms = (asymbol **) malloc(sizeof (asymbol*)*(*core_num_syms));
   83     if (*core_syms == NULL)
   84     {
   85         fc_message("cannot allocate %d bytes for symbols", (int) sizeof (asymbol*)*(*core_num_syms));
   86         fc_message_fatal(FC_ERR_MEM, "treatments aborted");
   87     }
   88 
   89     *core_num_syms = bfd_canonicalize_symtab(*core_bfd, *core_syms);
   90     if (*core_num_syms < 0)
   91     {
   92         free(*core_syms);
   93         fc_message("bfd error: %s", bfd_errmsg(bfd_get_error()));
   94         return 0;
   95     }
   96 
   97     *core_min_insn_size = 1;
   98     *core_offset_to_code = 0;
   99     switch (bfd_get_arch(*core_bfd))
  100     {
  101         case bfd_arch_vax:
  102         case bfd_arch_tahoe:
  103             *core_offset_to_code = 2;
  104             break;
  105         case bfd_arch_alpha:
  106             *core_min_insn_size = 4;
  107             break;
  108         default:
  109             break;
  110     }
  111 
  112     /* ok */
  113     return 1;
  114 }
  115 
  116 /* close a binary object open with BFD */
  117 int fc_close_bfd_file(bfd *core_bfd, int core_num_syms,
  118                      asection *core_text_sect, asymbol **core_syms,
  119              int core_min_insn_size, int core_offset_to_code)
  120 {
  121     bfd_close(core_bfd);
  122     free(core_syms);
  123 
  124     return 1;
  125 }
  126 
  127 
  128 /* sort  sym. table by address */
  129 int fc_compare_pointers(const void *e1, const void *e2)
  130 {
  131     if (((FC_Sym*) e1)->addr > ((FC_Sym*) e2)->addr)
  132         return 1;
  133     if (((FC_Sym*) e1)->addr < ((FC_Sym*) e2)->addr)
  134         return -1;
  135     return 0;
  136 }
  137 
  138 /* init symbol table from BFD data */
  139 int fc_init_extract_dynamic(int core_num_syms, asymbol **core_syms)
  140 {
  141     int i, dest;
  142 
  143     if ((fc_syms = malloc(sizeof (FC_Sym) * core_num_syms)) == NULL)
  144     {
  145         fc_message("cannot allocate local symbol table");
  146         return 0;
  147     }
  148 
  149     /* put addr/names in table */
  150     dest = 0;
  151     for (i = 0; i < core_num_syms; i++)
  152     {
  153         /* only functions */
  154         if (core_syms[i]->flags & BSF_FUNCTION)
  155         {
  156             fc_syms[dest].name = (char*) bfd_asymbol_name(core_syms[i]);
  157             fc_syms[dest].addr = (void*) bfd_asymbol_value(core_syms[i]);
  158             if ((core_syms[i]->flags & BSF_GLOBAL) || (core_syms[i]->flags & BSF_EXPORT))
  159                 fc_syms[dest].flag = 1;
  160             else
  161                 fc_syms[dest].flag = 0;
  162             dest++;
  163         }
  164     }
  165 
  166     fc_nb_syms = dest;
  167 
  168     /* empty table */
  169     if (fc_nb_syms == 0)
  170     {
  171         return 0;
  172     }
  173 
  174     /* sort it by pointer value */
  175     qsort(fc_syms, fc_nb_syms, sizeof (FC_Sym), fc_compare_pointers);
  176 
  177     return 1;
  178 }
  179 
  180 /* freed the local sym. table */
  181 int fc_fini_extract_dynamic()
  182 {
  183     if (fc_syms != NULL)
  184         free(fc_syms);
  185     fc_syms = NULL;
  186     fc_nb_syms = 0;
  187 
  188     return 1;
  189 }
  190 
  191 /* returns a name (char* to duplicate) from an address */
  192 /* valid is true if it is a local name */
  193 char *fc_extract_dynamic(void *addr, int *valid)
  194 {
  195     int i;
  196     char tmp[1024], *buffer = tmp;
  197 
  198     *valid = 0;
  199     if (fc_syms == NULL)
  200         return ("<err0>");
  201 
  202     if (addr < fc_syms[0].addr)
  203     {
  204         sprintf(buffer, "<lo-%p>", addr);
  205         return ((char*) buffer); /* before first symbol */
  206     }
  207 
  208     if (addr > fc_syms[fc_nb_syms - 1].addr)
  209     {
  210         sprintf(buffer, "<hi-%p>", addr);
  211         return ((char*) buffer); /* after last symbol */
  212     }
  213 
  214     /* I may use a better search method :o) */
  215     for (i = 0; i < fc_nb_syms; i++)
  216     {
  217         /* only check EXACT addresses */
  218         if (addr == fc_syms[i].addr)
  219         {
  220             *valid = fc_syms[i].flag;
  221             return (fc_syms[i].name);
  222         }
  223     }
  224 
  225     /* the exact entry does not exist */
  226     return NULL;
  227 }
  228 
  229 /* return true if 'name' is present in the sym-table AND
  230    is exported. Gives the corresponding address for get_nearest_line */
  231 int fc_find_symbol_by_name(char *name, void **addr, int demangle, int style)
  232 {
  233     int i;
  234     char *ntemp;
  235 
  236     *addr = NULL;
  237 
  238     if (name == NULL)
  239         return 0;
  240 
  241     /* loop for this name */
  242     for (i = 0; i < fc_nb_syms; i++)
  243     {
  244         /* demangle it if needed (for a coherent strcmp) */
  245         if (demangle)
  246         {
  247             ntemp = cplus_demangle(fc_syms[i].name, style);
  248             if (ntemp == NULL)
  249                 ntemp = fc_syms[i].name; /* use the basic name else */
  250         }
  251         else
  252         {
  253             ntemp = fc_syms[i].name; /* no demangle, use the basic name */
  254         }
  255 
  256         if ((ntemp[0] == name[0]) && (strcmp(ntemp, name) == 0))
  257         {/* found. check for the export status */
  258             if (fc_syms[i].flag)
  259             {/* ok */
  260                 *addr = fc_syms[i].addr;
  261                 return 1;
  262             }
  263             else
  264             {/* exit. it is not possible to get the same name twice (really?) */
  265                 return 0;
  266             }
  267         }
  268     }
  269     /* no match at all */
  270     return 0;
  271 }
  272 
  273 /* returns the function pointer from a pointer inside the function */
  274 void *fc_extract_dynamic_base(void *addr)
  275 {
  276     int i;
  277 
  278     /* !?! */
  279     if (fc_syms == NULL)
  280         return NULL;
  281 
  282     /* out of the bounds */
  283     if ((addr < fc_syms[0].addr) || (addr > fc_syms[fc_nb_syms - 1].addr))
  284     {/* no changes */
  285         return addr;
  286     }
  287 
  288     /* I may use a better search method :o) */
  289     for (i = 0; i < fc_nb_syms - 1; i++)
  290     {
  291         if ((addr >= fc_syms[i].addr) && (addr < fc_syms[i + 1].addr))
  292         {
  293             return (fc_syms[i].addr);
  294         }
  295     }
  296 
  297     /* may not occur */
  298     return addr;
  299 }
  300 
  301 /* return the symbol address of the given function */
  302 void *fc_search_function_by_name(char *name, int nbf, FC_Function *fncs)
  303 {
  304     int i;
  305 
  306     for (i = 0; i < nbf; i++)
  307     {
  308         if ((fncs[i].name.name != NULL) && (fncs[i].name.name[0] == name[0]) &&
  309                 (strcmp(fncs[i].name.name, name) == 0))
  310         {
  311             return (fncs[i].symbol);
  312         }
  313     }
  314 
  315     /* not found */
  316     return NULL;
  317 }
  318 
  319 /* return true if the given address exist */
  320 int fc_check_address(void *addr, int nbf, FC_Function *fncs)
  321 {
  322     int i;
  323 
  324     for (i = 0; i < nbf; i++)
  325     {
  326         if (fncs[i].symbol == addr)
  327             return 1;
  328     }
  329     /* not found */
  330     return 0;
  331 }
  332 
  333 int fc_names_solve(int force_names,
  334                    int nb_fnc, FC_Function *fncs,
  335                    int nb_lib, FC_LDyn *dyns,
  336                    int nb_arcs, FC_Arc *arcs,
  337                    char *exec_name, int demangle, int style,
  338                    FC_NSym *lonly, int nb_only,
  339                    FC_NSym *lnot, int nb_not,
  340                    int nb_leaks, FC_MLeak *leaks,
  341                    int nb_free, FC_MFree *free,
  342                    int nb_realloc, FC_MRealloc *realloc)
  343 {
  344     /* BFD data for exec */
  345     bfd *core_bfd;
  346     int core_min_insn_size;
  347     int core_offset_to_code;
  348     asection *core_text_sect;
  349     int core_num_syms;
  350     asymbol **core_syms;
  351     /* various variables */
  352     int i, j, valid;
  353     char *tname, *_tname, *tobj, *ttt;
  354     int tline;
  355     int missing = 0;
  356     void *addr;
  357 
  358     fc_debug("Solving names...");
  359 
  360     /* first init the list of functions names */
  361     for (i = 0; i < nb_fnc; i++)
  362     {
  363         fncs[i].name.name = NULL;
  364         fncs[i].name.object = NULL;
  365         fncs[i].name.line = 0;
  366         fncs[i].name.ok = FC_OK_NDEF;
  367     }
  368 
  369     /* open the executable */
  370     fc_debug("  opening executable '%s'", exec_name);
  371     if (!fc_open_bfd_file(exec_name, &core_bfd, &core_num_syms,
  372             &core_text_sect, &core_syms,
  373             &core_min_insn_size, &core_offset_to_code))
  374     {
  375         fc_message("The executable name given (%s) is not a valid object.", exec_name);
  376         if (!force_names)
  377         {
  378             fc_message_fatal(FC_ERR_ARGS, "Please check your parameters (try '--help' option)");
  379         }
  380         else
  381         {
  382             fc_message("Names will not be available (check your parameters)");
  383         }
  384         return 0;
  385     }
  386 
  387     if (!fc_init_extract_dynamic(core_num_syms, core_syms))
  388     {
  389         fc_message("names treatments aborted."); /* close bfd object */
  390         fc_close_bfd_file(core_bfd, core_num_syms,
  391                 core_text_sect, core_syms,
  392                 core_min_insn_size, core_offset_to_code);
  393         return 0;
  394     }
  395 
  396     /* for each arc replace call-site by the corresponding function */
  397     fc_debug("  cleaning arcs..");
  398     for (i = 0; i < nb_arcs; i++)
  399     {
  400         arcs[i].from = fc_extract_dynamic_base(arcs[i].from);
  401     }
  402 
  403     /* for each entry try to extract data */
  404     fc_debug("  extracting names...");
  405     for (i = 0; i < nb_fnc; i++)
  406     {
  407         /* get the name with our method: this is due to the fact
  408              that get_nearest_line failed to extract the name of a
  409          function that comes from a dynamic object */
  410         tname = fc_extract_dynamic(fncs[i].symbol, &valid);
  411 
  412         /* if the name is local, try to get file:line */
  413         if (valid)
  414         {
  415             /* get name/file/line using BFD */
  416             bfd_find_nearest_line(core_bfd, core_text_sect, core_syms,
  417                     (bfd_vma) fncs[i].symbol - core_text_sect->vma,
  418                     (const char**) &tobj,
  419                     (const char**) &_tname,
  420                     (unsigned int *) &tline);
  421         }
  422         else
  423         {
  424             tobj = NULL;
  425             tline = 0;
  426         }
  427 
  428         fncs[i].name.object = tobj;
  429         fncs[i].name.line = tline;
  430         if (valid)
  431         {
  432             fncs[i].name.ok = FC_OK_OK;
  433         }
  434         else
  435         {
  436             fncs[i].name.ok = FC_OK_NDEF;
  437             missing = 1;
  438         }
  439 
  440         if (tname == NULL)
  441         {
  442             ttt = NULL;
  443         }
  444         else
  445         {
  446             if (demangle)
  447             {
  448                 ttt = cplus_demangle(tname, style);
  449                 if (ttt == NULL)
  450                     ttt = strdup(tname);
  451                 else
  452                 {
  453                     tname = strdup(ttt);
  454                     ttt = tname;
  455                 }
  456             }
  457             else
  458             {
  459                 ttt = strdup(tname);
  460             }
  461         }
  462 
  463         fncs[i].name.name = (ttt == NULL ? FC_INVALID_NAME : ttt);
  464         if (ttt == NULL)
  465         {
  466             fncs[i].name.ok = FC_OK_BAD; /* mem error: not ok but not solvable */
  467         }
  468     }
  469 
  470     /* close our special treatments */
  471     fc_fini_extract_dynamic();
  472 
  473     /* close bfd object */
  474     fc_close_bfd_file(core_bfd, core_num_syms,
  475             core_text_sect, core_syms,
  476             core_min_insn_size, core_offset_to_code);
  477 
  478     /* now try to extract informations from dynamic libraries
  479        if some details are missing */
  480     if (missing)
  481     {
  482         fc_debug("  still missing details");
  483         for (i = 0; i < nb_lib; i++)
  484         {
  485             /* open the ith lib */
  486             fc_debug("  trying object '%s'", dyns[i].name);
  487             if (!fc_open_bfd_file(dyns[i].name, &core_bfd, &core_num_syms,
  488                     &core_text_sect, &core_syms,
  489                     &core_min_insn_size, &core_offset_to_code))
  490             {
  491                 fc_debug("  skipping library '%s' (bfd open error)", dyns[i].name);
  492                 continue;
  493             }
  494 
  495             if (!fc_init_extract_dynamic(core_num_syms, core_syms))
  496             {
  497                 /* close the BFD file */
  498                 fc_close_bfd_file(core_bfd, core_num_syms,
  499                         core_text_sect, core_syms,
  500                         core_min_insn_size, core_offset_to_code);
  501                 fc_debug("  skipping library '%s' (empty symbol table)", dyns[i].name);
  502                 continue;
  503             }
  504 
  505             /* for each invalid symbol, try to extract it in this lib */
  506             for (j = 0; j < nb_fnc; j++)
  507             {
  508                 if (fncs[j].name.ok == FC_OK_NDEF)
  509                 {
  510                     /* check if this symbol is here and exported */
  511                     if (fc_find_symbol_by_name(fncs[j].name.name, &addr, demangle, style))
  512                     {
  513                         /* get file/line using BFD */
  514                         bfd_find_nearest_line(core_bfd, core_text_sect, core_syms,
  515                                 (bfd_vma) addr - core_text_sect->vma,
  516                                 (const char**) &tobj,
  517                                 (const char**) &_tname,
  518                                 (unsigned int *) &tline);
  519                         /* add this information in the symbol */
  520                         fncs[j].name.object = strdup(tobj);
  521                         fncs[j].name.line = tline;
  522                         fncs[j].name.ok = FC_OK_OK;
  523                     }
  524                     else
  525                     {/* still some job to do */
  526                         missing = 1;
  527                     }
  528                 }
  529             }
  530 
  531             fc_fini_extract_dynamic();
  532             /* close the BFD file */
  533             fc_close_bfd_file(core_bfd, core_num_syms,
  534                     core_text_sect, core_syms,
  535                     core_min_insn_size, core_offset_to_code);
  536 
  537             /* no more ? */
  538             if (!missing)
  539                 break;
  540         }
  541     }
  542 
  543     /* if any, parse not/only lists to convert names to addresses */
  544     for (i = 0; i < nb_only; i++)
  545     {
  546         if ((lonly[i].addr == NULL) && (lonly[i].name != NULL))
  547         {
  548             lonly[i].addr = fc_search_function_by_name(lonly[i].name, nb_fnc, fncs);
  549             if (lnot[i].addr == NULL)
  550             {
  551                 fc_message("function '%s' not found. discarded.", lnot[i].name);
  552             }
  553         }
  554         else
  555             if (lnot[i].addr != NULL)
  556         {
  557             if (!fc_check_address(lnot[i].addr, nb_fnc, fncs))
  558             {
  559                 fc_message("address %p not found. discarded.", lnot[i].addr);
  560                 lnot[i].addr = NULL;
  561             }
  562         }
  563     }
  564 
  565     for (i = 0; i < nb_not; i++)
  566     {
  567         if ((lnot[i].addr == NULL) && (lnot[i].name != NULL))
  568         {
  569             lnot[i].addr = fc_search_function_by_name(lnot[i].name, nb_fnc, fncs);
  570             if (lnot[i].addr == NULL)
  571             {
  572                 fc_message("function '%s' not found. discarded.", lnot[i].name);
  573             }
  574         }
  575         else
  576             if (lnot[i].addr != NULL)
  577         {
  578             if (!fc_check_address(lnot[i].addr, nb_fnc, fncs))
  579             {
  580                 fc_message("address %p not found. discarded.", lnot[i].addr);
  581                 lnot[i].addr = NULL;
  582             }
  583         }
  584     }
  585 
  586     fc_debug("End of name extraction.");
  587     return 1;
  588 }
  589