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