Back to index

cell-binutils  2.17cvs20070401
sym_ids.c
Go to the documentation of this file.
00001 /* sym_ids.c
00002 
00003    Copyright 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
00004 
00005    This file is part of GNU Binutils.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
00020    02110-1301, USA.  */
00021 
00022 #include "libiberty.h"
00023 #include "safe-ctype.h"
00024 #include "gprof.h"
00025 #include "search_list.h"
00026 #include "source.h"
00027 #include "symtab.h"
00028 #include "cg_arcs.h"
00029 #include "sym_ids.h"
00030 
00031 static struct sym_id
00032   {
00033     struct sym_id *next;
00034     char *spec;                    /* Parsing modifies this.  */
00035     Table_Id which_table;
00036     bfd_boolean has_right;
00037 
00038     struct match
00039       {
00040        int prev_index;             /* Index of prev match.  */
00041        Sym *prev_match;     /* Previous match.  */
00042        Sym *first_match;    /* Chain of all matches.  */
00043        Sym sym;
00044       }
00045     left, right;
00046   }
00047  *id_list;
00048 
00049 static void parse_spec
00050   (char *, Sym *);
00051 static void parse_id
00052   (struct sym_id *);
00053 static bfd_boolean match
00054   (Sym *, Sym *);
00055 static void extend_match
00056   (struct match *, Sym *, Sym_Table *, bfd_boolean);
00057 
00058 
00059 Sym_Table syms[NUM_TABLES];
00060 
00061 #ifdef DEBUG
00062 static const char *table_name[] =
00063 {
00064   "INCL_GRAPH", "EXCL_GRAPH",
00065   "INCL_ARCS", "EXCL_ARCS",
00066   "INCL_FLAT", "EXCL_FLAT",
00067   "INCL_TIME", "EXCL_TIME",
00068   "INCL_ANNO", "EXCL_ANNO",
00069   "INCL_EXEC", "EXCL_EXEC"
00070 };
00071 #endif /* DEBUG */
00072 
00073 /* This is the table in which we keep all the syms that match
00074    the right half of an arc id.  It is NOT sorted according
00075    to the addresses, because it is accessed only through
00076    the left half's CHILDREN pointers (so it's crucial not
00077    to reorder this table once pointers into it exist).  */
00078 static Sym_Table right_ids;
00079 
00080 static Source_File non_existent_file =
00081 {
00082   0, "<non-existent-file>", 0, 0, 0, NULL
00083 };
00084 
00085 
00086 void
00087 sym_id_add (const char *spec, Table_Id which_table)
00088 {
00089   struct sym_id *id;
00090   int len = strlen (spec);
00091 
00092   id = (struct sym_id *) xmalloc (sizeof (*id) + len + 1);
00093   memset (id, 0, sizeof (*id));
00094 
00095   id->spec = (char *) id + sizeof (*id);
00096   strcpy (id->spec, spec);
00097   id->which_table = which_table;
00098 
00099   id->next = id_list;
00100   id_list = id;
00101 }
00102 
00103 
00104 /* A spec has the syntax FILENAME:(FUNCNAME|LINENUM).  As a convenience
00105    to the user, a spec without a colon is interpreted as:
00106 
00107        (i)   a FILENAME if it contains a dot
00108        (ii)  a FUNCNAME if it starts with a non-digit character
00109        (iii) a LINENUM if it starts with a digit
00110 
00111    A FUNCNAME containing a dot can be specified by :FUNCNAME, a
00112    FILENAME not containing a dot can be specified by FILENAME.  */
00113 
00114 static void
00115 parse_spec (char *spec, Sym *sym)
00116 {
00117   char *colon;
00118 
00119   sym_init (sym);
00120   colon = strrchr (spec, ':');
00121 
00122   if (colon)
00123     {
00124       *colon = '\0';
00125 
00126       if (colon > spec)
00127        {
00128          sym->file = source_file_lookup_name (spec);
00129 
00130          if (!sym->file)
00131            sym->file = &non_existent_file;
00132        }
00133 
00134       spec = colon + 1;
00135 
00136       if (strlen (spec))
00137        {
00138          if (ISDIGIT (spec[0]))
00139            sym->line_num = atoi (spec);
00140          else
00141            sym->name = spec;
00142        }
00143     }
00144   else if (strlen (spec))
00145     {
00146       /* No colon: spec is a filename if it contains a dot.  */
00147       if (strchr (spec, '.'))
00148        {
00149          sym->file = source_file_lookup_name (spec);
00150 
00151          if (!sym->file)
00152            sym->file = &non_existent_file;
00153        }
00154       else if (ISDIGIT (*spec))
00155        {
00156          sym->line_num = atoi (spec);
00157        }
00158       else if (strlen (spec))
00159        {
00160          sym->name = spec;
00161        }
00162     }
00163 }
00164 
00165 
00166 /* A symbol id has the syntax SPEC[/SPEC], where SPEC is is defined
00167    by parse_spec().  */
00168 
00169 static void
00170 parse_id (struct sym_id *id)
00171 {
00172   char *slash;
00173 
00174   DBG (IDDEBUG, printf ("[parse_id] %s -> ", id->spec));
00175 
00176   slash = strchr (id->spec, '/');
00177   if (slash)
00178     {
00179       parse_spec (slash + 1, &id->right.sym);
00180       *slash = '\0';
00181       id->has_right = TRUE;
00182     }
00183   parse_spec (id->spec, &id->left.sym);
00184 
00185 #ifdef DEBUG
00186   if (debug_level & IDDEBUG)
00187     {
00188       printf ("%s:", id->left.sym.file ? id->left.sym.file->name : "*");
00189 
00190       if (id->left.sym.name)
00191        printf ("%s", id->left.sym.name);
00192       else if (id->left.sym.line_num)
00193        printf ("%d", id->left.sym.line_num);
00194       else
00195        printf ("*");
00196 
00197       if (id->has_right)
00198        {
00199          printf ("/%s:",
00200                 id->right.sym.file ? id->right.sym.file->name : "*");
00201 
00202          if (id->right.sym.name)
00203            printf ("%s", id->right.sym.name);
00204          else if (id->right.sym.line_num)
00205            printf ("%d", id->right.sym.line_num);
00206          else
00207            printf ("*");
00208        }
00209 
00210       printf ("\n");
00211     }
00212 #endif
00213 }
00214 
00215 
00216 /* Return TRUE iff PATTERN matches SYM.  */
00217 
00218 static bfd_boolean
00219 match (Sym *pattern, Sym *sym)
00220 {
00221   return (pattern->file ? pattern->file == sym->file : TRUE)
00222     && (pattern->line_num ? pattern->line_num == sym->line_num : TRUE)
00223     && (pattern->name
00224        ? strcmp (pattern->name,
00225                 sym->name+(discard_underscores && sym->name[0] == '_')) == 0
00226        : TRUE);
00227 }
00228 
00229 
00230 static void
00231 extend_match (struct match *m, Sym *sym, Sym_Table *tab, bfd_boolean second_pass)
00232 {
00233   if (m->prev_match != sym - 1)
00234     {
00235       /* Discontinuity: add new match to table.  */
00236       if (second_pass)
00237        {
00238          tab->base[tab->len] = *sym;
00239          m->prev_index = tab->len;
00240 
00241          /* Link match into match's chain.  */
00242          tab->base[tab->len].next = m->first_match;
00243          m->first_match = &tab->base[tab->len];
00244        }
00245 
00246       ++tab->len;
00247     }
00248 
00249   /* Extend match to include this symbol.  */
00250   if (second_pass)
00251     tab->base[m->prev_index].end_addr = sym->end_addr;
00252 
00253   m->prev_match = sym;
00254 }
00255 
00256 
00257 /* Go through sym_id list produced by option processing and fill
00258    in the various symbol tables indicating what symbols should
00259    be displayed or suppressed for the various kinds of outputs.
00260 
00261    This can potentially produce huge tables and in particulars
00262    tons of arcs, but this happens only if the user makes silly
00263    requests---you get what you ask for!  */
00264 
00265 void
00266 sym_id_parse ()
00267 {
00268   Sym *sym, *left, *right;
00269   struct sym_id *id;
00270   Sym_Table *tab;
00271 
00272   /* Convert symbol ids into Syms, so we can deal with them more easily.  */
00273   for (id = id_list; id; id = id->next)
00274     parse_id (id);
00275 
00276   /* First determine size of each table.  */
00277   for (sym = symtab.base; sym < symtab.limit; ++sym)
00278     {
00279       for (id = id_list; id; id = id->next)
00280        {
00281          if (match (&id->left.sym, sym))
00282            extend_match (&id->left, sym, &syms[id->which_table], FALSE);
00283 
00284          if (id->has_right && match (&id->right.sym, sym))
00285            extend_match (&id->right, sym, &right_ids, FALSE);
00286        }
00287     }
00288 
00289   /* Create tables of appropriate size and reset lengths.  */
00290   for (tab = syms; tab < &syms[NUM_TABLES]; ++tab)
00291     {
00292       if (tab->len)
00293        {
00294          tab->base = (Sym *) xmalloc (tab->len * sizeof (Sym));
00295          tab->limit = tab->base + tab->len;
00296          tab->len = 0;
00297        }
00298     }
00299 
00300   if (right_ids.len)
00301     {
00302       right_ids.base = (Sym *) xmalloc (right_ids.len * sizeof (Sym));
00303       right_ids.limit = right_ids.base + right_ids.len;
00304       right_ids.len = 0;
00305     }
00306 
00307   /* Make a second pass through symtab, creating syms as necessary.  */
00308   for (sym = symtab.base; sym < symtab.limit; ++sym)
00309     {
00310       for (id = id_list; id; id = id->next)
00311        {
00312          if (match (&id->left.sym, sym))
00313            extend_match (&id->left, sym, &syms[id->which_table], TRUE);
00314 
00315          if (id->has_right && match (&id->right.sym, sym))
00316            extend_match (&id->right, sym, &right_ids, TRUE);
00317        }
00318     }
00319 
00320   /* Go through ids creating arcs as needed.  */
00321   for (id = id_list; id; id = id->next)
00322     {
00323       if (id->has_right)
00324        {
00325          for (left = id->left.first_match; left; left = left->next)
00326            {
00327              for (right = id->right.first_match; right; right = right->next)
00328               {
00329                 DBG (IDDEBUG,
00330                      printf (
00331                             "[sym_id_parse]: arc %s:%s(%lx-%lx) -> %s:%s(%lx-%lx) to %s\n",
00332                             left->file ? left->file->name : "*",
00333                             left->name ? left->name : "*",
00334                             (unsigned long) left->addr,
00335                             (unsigned long) left->end_addr,
00336                             right->file ? right->file->name : "*",
00337                             right->name ? right->name : "*",
00338                             (unsigned long) right->addr,
00339                             (unsigned long) right->end_addr,
00340                             table_name[id->which_table]));
00341 
00342                 arc_add (left, right, (unsigned long) 0);
00343               }
00344            }
00345        }
00346     }
00347 
00348   /* Finally, we can sort the tables and we're done.  */
00349   for (tab = &syms[0]; tab < &syms[NUM_TABLES]; ++tab)
00350     {
00351       DBG (IDDEBUG, printf ("[sym_id_parse] syms[%s]:\n",
00352                          table_name[tab - &syms[0]]));
00353       symtab_finalize (tab);
00354     }
00355 }
00356 
00357 
00358 /* Symbol tables storing the FROM symbols of arcs do not necessarily
00359    have distinct address ranges.  For example, somebody might request
00360    -k /_mcount to suppress any arcs into _mcount, while at the same
00361    time requesting -k a/b.  Fortunately, those symbol tables don't get
00362    very big (the user has to type them!), so a linear search is probably
00363    tolerable.  */
00364 bfd_boolean
00365 sym_id_arc_is_present (Sym_Table *sym_tab, Sym *from, Sym *to)
00366 {
00367   Sym *sym;
00368 
00369   for (sym = sym_tab->base; sym < sym_tab->limit; ++sym)
00370     {
00371       if (from->addr >= sym->addr && from->addr <= sym->end_addr
00372          && arc_lookup (sym, to))
00373        return TRUE;
00374     }
00375 
00376   return FALSE;
00377 }