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