Home | History | Annotate | Line # | Download | only in gprof
sym_ids.c revision 1.7
      1  1.1  christos /* sym_ids.c
      2  1.1  christos 
      3  1.7  christos    Copyright (C) 1999-2020 Free Software Foundation, Inc.
      4  1.1  christos 
      5  1.1  christos    This file is part of GNU Binutils.
      6  1.1  christos 
      7  1.1  christos    This program is free software; you can redistribute it and/or modify
      8  1.1  christos    it under the terms of the GNU General Public License as published by
      9  1.1  christos    the Free Software Foundation; either version 3 of the License, or
     10  1.1  christos    (at your option) any later version.
     11  1.1  christos 
     12  1.1  christos    This program is distributed in the hope that it will be useful,
     13  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  1.1  christos    GNU General Public License for more details.
     16  1.1  christos 
     17  1.1  christos    You should have received a copy of the GNU General Public License
     18  1.1  christos    along with this program; if not, write to the Free Software
     19  1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
     20  1.1  christos    02110-1301, USA.  */
     21  1.1  christos 
     22  1.1  christos #include "gprof.h"
     24  1.1  christos #include "libiberty.h"
     25  1.1  christos #include "safe-ctype.h"
     26  1.1  christos #include "search_list.h"
     27  1.1  christos #include "source.h"
     28  1.1  christos #include "symtab.h"
     29  1.1  christos #include "cg_arcs.h"
     30  1.1  christos #include "sym_ids.h"
     31  1.1  christos #include "corefile.h"
     32  1.1  christos 
     33  1.1  christos struct match
     34  1.1  christos   {
     35  1.1  christos     int prev_index;	/* Index of prev match.  */
     36  1.1  christos     Sym *prev_match;	/* Previous match.  */
     37  1.1  christos     Sym *first_match;	/* Chain of all matches.  */
     38  1.1  christos     Sym sym;
     39  1.1  christos   };
     40  1.1  christos 
     41  1.1  christos struct sym_id
     42  1.1  christos   {
     43  1.1  christos     struct sym_id *next;
     44  1.1  christos     char *spec;			/* Parsing modifies this.  */
     45  1.1  christos     Table_Id which_table;
     46  1.1  christos     bfd_boolean has_right;
     47  1.1  christos 
     48  1.1  christos     struct match left, right;
     49  1.1  christos   };
     50  1.1  christos 
     51  1.1  christos static struct sym_id  *id_list;
     52  1.1  christos 
     53  1.1  christos static void parse_spec
     54  1.1  christos   (char *, Sym *);
     55  1.1  christos static void parse_id
     56  1.1  christos   (struct sym_id *);
     57  1.1  christos static bfd_boolean match
     58  1.1  christos   (Sym *, Sym *);
     59  1.1  christos static void extend_match
     60  1.1  christos   (struct match *, Sym *, Sym_Table *, bfd_boolean);
     61  1.1  christos 
     62  1.1  christos 
     63  1.1  christos Sym_Table syms[NUM_TABLES];
     64  1.1  christos 
     65  1.1  christos #ifdef DEBUG
     66  1.1  christos static const char *table_name[] =
     67  1.1  christos {
     68  1.1  christos   "INCL_GRAPH", "EXCL_GRAPH",
     69  1.1  christos   "INCL_ARCS", "EXCL_ARCS",
     70  1.1  christos   "INCL_FLAT", "EXCL_FLAT",
     71  1.1  christos   "INCL_TIME", "EXCL_TIME",
     72  1.1  christos   "INCL_ANNO", "EXCL_ANNO",
     73  1.1  christos   "INCL_EXEC", "EXCL_EXEC"
     74  1.1  christos };
     75  1.1  christos #endif /* DEBUG */
     76  1.1  christos 
     77  1.1  christos /* This is the table in which we keep all the syms that match
     78  1.1  christos    the right half of an arc id.  It is NOT sorted according
     79  1.1  christos    to the addresses, because it is accessed only through
     80  1.1  christos    the left half's CHILDREN pointers (so it's crucial not
     81  1.1  christos    to reorder this table once pointers into it exist).  */
     82  1.1  christos static Sym_Table right_ids;
     83  1.1  christos 
     84  1.1  christos static Source_File non_existent_file =
     85  1.1  christos {
     86  1.1  christos   0, "<non-existent-file>", 0, 0, 0, NULL
     87  1.1  christos };
     88  1.1  christos 
     89  1.1  christos 
     90  1.1  christos void
     91  1.1  christos sym_id_add (const char *spec, Table_Id which_table)
     92  1.1  christos {
     93  1.1  christos   struct sym_id *id;
     94  1.1  christos   int len = strlen (spec);
     95  1.1  christos 
     96  1.1  christos   id = (struct sym_id *) xmalloc (sizeof (*id) + len + 1);
     97  1.1  christos   memset (id, 0, sizeof (*id));
     98  1.1  christos 
     99  1.1  christos   id->spec = (char *) id + sizeof (*id);
    100  1.1  christos   strcpy (id->spec, spec);
    101  1.1  christos   id->which_table = which_table;
    102  1.1  christos 
    103  1.1  christos   id->next = id_list;
    104  1.1  christos   id_list = id;
    105  1.1  christos }
    106  1.1  christos 
    107  1.1  christos 
    108  1.1  christos /* A spec has the syntax FILENAME:(FUNCNAME|LINENUM).  As a convenience
    109  1.1  christos    to the user, a spec without a colon is interpreted as:
    110  1.1  christos 
    111  1.1  christos 	(i)   a FILENAME if it contains a dot
    112  1.1  christos 	(ii)  a FUNCNAME if it starts with a non-digit character
    113  1.1  christos 	(iii) a LINENUM if it starts with a digit
    114  1.1  christos 
    115  1.1  christos    A FUNCNAME containing a dot can be specified by :FUNCNAME, a
    116  1.1  christos    FILENAME not containing a dot can be specified by FILENAME.  */
    117  1.1  christos 
    118  1.1  christos static void
    119  1.1  christos parse_spec (char *spec, Sym *sym)
    120  1.1  christos {
    121  1.1  christos   char *colon;
    122  1.1  christos 
    123  1.1  christos   sym_init (sym);
    124  1.1  christos   colon = strrchr (spec, ':');
    125  1.1  christos 
    126  1.1  christos   if (colon)
    127  1.1  christos     {
    128  1.1  christos       *colon = '\0';
    129  1.1  christos 
    130  1.1  christos       if (colon > spec)
    131  1.1  christos 	{
    132  1.1  christos 	  sym->file = source_file_lookup_name (spec);
    133  1.1  christos 
    134  1.1  christos 	  if (!sym->file)
    135  1.1  christos 	    sym->file = &non_existent_file;
    136  1.1  christos 	}
    137  1.1  christos 
    138  1.1  christos       spec = colon + 1;
    139  1.1  christos 
    140  1.1  christos       if (strlen (spec))
    141  1.1  christos 	{
    142  1.1  christos 	  if (ISDIGIT (spec[0]))
    143  1.1  christos 	    sym->line_num = atoi (spec);
    144  1.1  christos 	  else
    145  1.1  christos 	    sym->name = spec;
    146  1.1  christos 	}
    147  1.1  christos     }
    148  1.1  christos   else if (strlen (spec))
    149  1.1  christos     {
    150  1.1  christos       /* No colon: spec is a filename if it contains a dot.  */
    151  1.1  christos       if (strchr (spec, '.'))
    152  1.1  christos 	{
    153  1.1  christos 	  sym->file = source_file_lookup_name (spec);
    154  1.1  christos 
    155  1.1  christos 	  if (!sym->file)
    156  1.1  christos 	    sym->file = &non_existent_file;
    157  1.1  christos 	}
    158  1.1  christos       else if (ISDIGIT (*spec))
    159  1.1  christos 	{
    160  1.1  christos 	  sym->line_num = atoi (spec);
    161  1.1  christos 	}
    162  1.1  christos       else if (strlen (spec))
    163  1.1  christos 	{
    164  1.1  christos 	  sym->name = spec;
    165  1.1  christos 	}
    166  1.1  christos     }
    167  1.1  christos }
    168  1.1  christos 
    169  1.1  christos 
    170  1.1  christos /* A symbol id has the syntax SPEC[/SPEC], where SPEC is is defined
    171  1.1  christos    by parse_spec().  */
    172  1.1  christos 
    173  1.1  christos static void
    174  1.1  christos parse_id (struct sym_id *id)
    175  1.1  christos {
    176  1.1  christos   char *slash;
    177  1.1  christos 
    178  1.1  christos   DBG (IDDEBUG, printf ("[parse_id] %s -> ", id->spec));
    179  1.1  christos 
    180  1.1  christos   slash = strchr (id->spec, '/');
    181  1.1  christos   if (slash)
    182  1.1  christos     {
    183  1.1  christos       parse_spec (slash + 1, &id->right.sym);
    184  1.1  christos       *slash = '\0';
    185  1.1  christos       id->has_right = TRUE;
    186  1.1  christos     }
    187  1.1  christos   parse_spec (id->spec, &id->left.sym);
    188  1.1  christos 
    189  1.1  christos #ifdef DEBUG
    190  1.1  christos   if (debug_level & IDDEBUG)
    191  1.1  christos     {
    192  1.1  christos       printf ("%s:", id->left.sym.file ? id->left.sym.file->name : "*");
    193  1.1  christos 
    194  1.1  christos       if (id->left.sym.name)
    195  1.1  christos 	printf ("%s", id->left.sym.name);
    196  1.1  christos       else if (id->left.sym.line_num)
    197  1.1  christos 	printf ("%d", id->left.sym.line_num);
    198  1.1  christos       else
    199  1.1  christos 	printf ("*");
    200  1.1  christos 
    201  1.1  christos       if (id->has_right)
    202  1.1  christos 	{
    203  1.1  christos 	  printf ("/%s:",
    204  1.1  christos 		  id->right.sym.file ? id->right.sym.file->name : "*");
    205  1.1  christos 
    206  1.1  christos 	  if (id->right.sym.name)
    207  1.1  christos 	    printf ("%s", id->right.sym.name);
    208  1.1  christos 	  else if (id->right.sym.line_num)
    209  1.1  christos 	    printf ("%d", id->right.sym.line_num);
    210  1.1  christos 	  else
    211  1.1  christos 	    printf ("*");
    212  1.1  christos 	}
    213  1.1  christos 
    214  1.1  christos       printf ("\n");
    215  1.1  christos     }
    216  1.1  christos #endif
    217  1.1  christos }
    218  1.1  christos 
    219  1.1  christos 
    220  1.1  christos /* Return TRUE iff PATTERN matches SYM.  */
    221  1.1  christos 
    222  1.1  christos static bfd_boolean
    223  1.1  christos match (Sym *pattern, Sym *sym)
    224  1.1  christos {
    225  1.1  christos   if (pattern->file && pattern->file != sym->file)
    226  1.1  christos     return FALSE;
    227  1.1  christos   if (pattern->line_num && pattern->line_num != sym->line_num)
    228  1.1  christos     return FALSE;
    229  1.1  christos   if (pattern->name)
    230  1.1  christos     {
    231  1.1  christos       const char *sym_name = sym->name;
    232  1.1  christos       if (*sym_name && bfd_get_symbol_leading_char (core_bfd) == *sym_name)
    233  1.1  christos 	sym_name++;
    234  1.1  christos       if (strcmp (pattern->name, sym_name) != 0)
    235  1.1  christos 	return FALSE;
    236  1.1  christos     }
    237  1.1  christos   return TRUE;
    238  1.1  christos }
    239  1.1  christos 
    240  1.1  christos 
    241  1.1  christos static void
    242  1.1  christos extend_match (struct match *m, Sym *sym, Sym_Table *tab, bfd_boolean second_pass)
    243  1.1  christos {
    244  1.1  christos   if (m->prev_match != sym - 1)
    245  1.1  christos     {
    246  1.1  christos       /* Discontinuity: add new match to table.  */
    247  1.1  christos       if (second_pass)
    248  1.1  christos 	{
    249  1.1  christos 	  tab->base[tab->len] = *sym;
    250  1.1  christos 	  m->prev_index = tab->len;
    251  1.1  christos 
    252  1.1  christos 	  /* Link match into match's chain.  */
    253  1.1  christos 	  tab->base[tab->len].next = m->first_match;
    254  1.1  christos 	  m->first_match = &tab->base[tab->len];
    255  1.1  christos 	}
    256  1.1  christos 
    257  1.1  christos       ++tab->len;
    258  1.1  christos     }
    259  1.1  christos 
    260  1.1  christos   /* Extend match to include this symbol.  */
    261  1.1  christos   if (second_pass)
    262  1.1  christos     tab->base[m->prev_index].end_addr = sym->end_addr;
    263  1.1  christos 
    264  1.1  christos   m->prev_match = sym;
    265  1.1  christos }
    266  1.1  christos 
    267  1.1  christos 
    268  1.1  christos /* Go through sym_id list produced by option processing and fill
    269  1.1  christos    in the various symbol tables indicating what symbols should
    270  1.1  christos    be displayed or suppressed for the various kinds of outputs.
    271  1.1  christos 
    272  1.1  christos    This can potentially produce huge tables and in particulars
    273  1.1  christos    tons of arcs, but this happens only if the user makes silly
    274  1.1  christos    requests---you get what you ask for!  */
    275  1.1  christos 
    276  1.5  christos void
    277  1.1  christos sym_id_parse (void)
    278  1.1  christos {
    279  1.1  christos   Sym *sym, *left, *right;
    280  1.1  christos   struct sym_id *id;
    281  1.1  christos   Sym_Table *tab;
    282  1.1  christos 
    283  1.1  christos   /* Convert symbol ids into Syms, so we can deal with them more easily.  */
    284  1.1  christos   for (id = id_list; id; id = id->next)
    285  1.1  christos     parse_id (id);
    286  1.1  christos 
    287  1.1  christos   /* First determine size of each table.  */
    288  1.1  christos   for (sym = symtab.base; sym < symtab.limit; ++sym)
    289  1.1  christos     {
    290  1.1  christos       for (id = id_list; id; id = id->next)
    291  1.1  christos 	{
    292  1.1  christos 	  if (match (&id->left.sym, sym))
    293  1.1  christos 	    extend_match (&id->left, sym, &syms[id->which_table], FALSE);
    294  1.1  christos 
    295  1.1  christos 	  if (id->has_right && match (&id->right.sym, sym))
    296  1.1  christos 	    extend_match (&id->right, sym, &right_ids, FALSE);
    297  1.1  christos 	}
    298  1.1  christos     }
    299  1.1  christos 
    300  1.1  christos   /* Create tables of appropriate size and reset lengths.  */
    301  1.1  christos   for (tab = syms; tab < &syms[NUM_TABLES]; ++tab)
    302  1.1  christos     {
    303  1.1  christos       if (tab->len)
    304  1.1  christos 	{
    305  1.1  christos 	  tab->base = (Sym *) xmalloc (tab->len * sizeof (Sym));
    306  1.1  christos 	  tab->limit = tab->base + tab->len;
    307  1.1  christos 	  tab->len = 0;
    308  1.1  christos 	}
    309  1.1  christos     }
    310  1.1  christos 
    311  1.1  christos   if (right_ids.len)
    312  1.1  christos     {
    313  1.1  christos       right_ids.base = (Sym *) xmalloc (right_ids.len * sizeof (Sym));
    314  1.1  christos       right_ids.limit = right_ids.base + right_ids.len;
    315  1.1  christos       right_ids.len = 0;
    316  1.1  christos     }
    317  1.1  christos 
    318  1.1  christos   /* Make a second pass through symtab, creating syms as necessary.  */
    319  1.1  christos   for (sym = symtab.base; sym < symtab.limit; ++sym)
    320  1.1  christos     {
    321  1.1  christos       for (id = id_list; id; id = id->next)
    322  1.1  christos 	{
    323  1.1  christos 	  if (match (&id->left.sym, sym))
    324  1.1  christos 	    extend_match (&id->left, sym, &syms[id->which_table], TRUE);
    325  1.1  christos 
    326  1.1  christos 	  if (id->has_right && match (&id->right.sym, sym))
    327  1.1  christos 	    extend_match (&id->right, sym, &right_ids, TRUE);
    328  1.1  christos 	}
    329  1.1  christos     }
    330  1.1  christos 
    331  1.1  christos   /* Go through ids creating arcs as needed.  */
    332  1.1  christos   for (id = id_list; id; id = id->next)
    333  1.1  christos     {
    334  1.1  christos       if (id->has_right)
    335  1.1  christos 	{
    336  1.1  christos 	  for (left = id->left.first_match; left; left = left->next)
    337  1.1  christos 	    {
    338  1.1  christos 	      for (right = id->right.first_match; right; right = right->next)
    339  1.1  christos 		{
    340  1.1  christos 		  DBG (IDDEBUG,
    341  1.1  christos 		       printf (
    342  1.1  christos 				"[sym_id_parse]: arc %s:%s(%lx-%lx) -> %s:%s(%lx-%lx) to %s\n",
    343  1.1  christos 				left->file ? left->file->name : "*",
    344  1.1  christos 				left->name ? left->name : "*",
    345  1.1  christos 				(unsigned long) left->addr,
    346  1.1  christos 				(unsigned long) left->end_addr,
    347  1.1  christos 				right->file ? right->file->name : "*",
    348  1.1  christos 				right->name ? right->name : "*",
    349  1.1  christos 				(unsigned long) right->addr,
    350  1.1  christos 				(unsigned long) right->end_addr,
    351  1.1  christos 				table_name[id->which_table]));
    352  1.1  christos 
    353  1.1  christos 		  arc_add (left, right, (unsigned long) 0);
    354  1.1  christos 		}
    355  1.1  christos 	    }
    356  1.1  christos 	}
    357  1.1  christos     }
    358  1.1  christos 
    359  1.1  christos   /* Finally, we can sort the tables and we're done.  */
    360  1.1  christos   for (tab = &syms[0]; tab < &syms[NUM_TABLES]; ++tab)
    361  1.1  christos     {
    362  1.1  christos       DBG (IDDEBUG, printf ("[sym_id_parse] syms[%s]:\n",
    363  1.1  christos 			    table_name[tab - &syms[0]]));
    364  1.1  christos       symtab_finalize (tab);
    365  1.1  christos     }
    366  1.1  christos }
    367  1.1  christos 
    368  1.1  christos 
    369  1.1  christos /* Symbol tables storing the FROM symbols of arcs do not necessarily
    370  1.1  christos    have distinct address ranges.  For example, somebody might request
    371  1.1  christos    -k /_mcount to suppress any arcs into _mcount, while at the same
    372  1.1  christos    time requesting -k a/b.  Fortunately, those symbol tables don't get
    373  1.1  christos    very big (the user has to type them!), so a linear search is probably
    374  1.1  christos    tolerable.  */
    375  1.1  christos bfd_boolean
    376  1.1  christos sym_id_arc_is_present (Sym_Table *sym_tab, Sym *from, Sym *to)
    377  1.1  christos {
    378  1.1  christos   Sym *sym;
    379  1.1  christos 
    380  1.1  christos   for (sym = sym_tab->base; sym < sym_tab->limit; ++sym)
    381  1.1  christos     {
    382  1.1  christos       if (from->addr >= sym->addr && from->addr <= sym->end_addr
    383  1.1  christos 	  && arc_lookup (sym, to))
    384  1.1  christos 	return TRUE;
    385  1.1  christos     }
    386  1.1  christos 
    387  1.1  christos   return FALSE;
    388                }
    389