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