2005-05-20 Paolo Bonzini <bonzini@gnu.org>
[binutils.git] / gprof / sym_ids.c
blobd41a716b78e5c6c4657cf60ef276f4652c77c2b1
1 /* sym_ids.c
3 Copyright 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
5 This file is part of GNU Binutils.
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 2 of the License, or
10 (at your option) any later version.
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.
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. */
22 #include "libiberty.h"
23 #include "safe-ctype.h"
24 #include "gprof.h"
25 #include "search_list.h"
26 #include "source.h"
27 #include "symtab.h"
28 #include "cg_arcs.h"
29 #include "sym_ids.h"
31 static struct sym_id
33 struct sym_id *next;
34 char *spec; /* Parsing modifies this. */
35 Table_Id which_table;
36 bfd_boolean has_right;
38 struct match
40 int prev_index; /* Index of prev match. */
41 Sym *prev_match; /* Previous match. */
42 Sym *first_match; /* Chain of all matches. */
43 Sym sym;
45 left, right;
47 *id_list;
49 static void parse_spec
50 (char *, Sym *);
51 static void parse_id
52 (struct sym_id *);
53 static bfd_boolean match
54 (Sym *, Sym *);
55 static void extend_match
56 (struct match *, Sym *, Sym_Table *, bfd_boolean);
59 Sym_Table syms[NUM_TABLES];
61 #ifdef DEBUG
62 static const char *table_name[] =
64 "INCL_GRAPH", "EXCL_GRAPH",
65 "INCL_ARCS", "EXCL_ARCS",
66 "INCL_FLAT", "EXCL_FLAT",
67 "INCL_TIME", "EXCL_TIME",
68 "INCL_ANNO", "EXCL_ANNO",
69 "INCL_EXEC", "EXCL_EXEC"
71 #endif /* DEBUG */
73 /* This is the table in which we keep all the syms that match
74 the right half of an arc id. It is NOT sorted according
75 to the addresses, because it is accessed only through
76 the left half's CHILDREN pointers (so it's crucial not
77 to reorder this table once pointers into it exist). */
78 static Sym_Table right_ids;
80 static Source_File non_existent_file =
82 0, "<non-existent-file>", 0, 0, 0, NULL
86 void
87 sym_id_add (const char *spec, Table_Id which_table)
89 struct sym_id *id;
90 int len = strlen (spec);
92 id = (struct sym_id *) xmalloc (sizeof (*id) + len + 1);
93 memset (id, 0, sizeof (*id));
95 id->spec = (char *) id + sizeof (*id);
96 strcpy (id->spec, spec);
97 id->which_table = which_table;
99 id->next = id_list;
100 id_list = id;
104 /* A spec has the syntax FILENAME:(FUNCNAME|LINENUM). As a convenience
105 to the user, a spec without a colon is interpreted as:
107 (i) a FILENAME if it contains a dot
108 (ii) a FUNCNAME if it starts with a non-digit character
109 (iii) a LINENUM if it starts with a digit
111 A FUNCNAME containing a dot can be specified by :FUNCNAME, a
112 FILENAME not containing a dot can be specified by FILENAME. */
114 static void
115 parse_spec (char *spec, Sym *sym)
117 char *colon;
119 sym_init (sym);
120 colon = strrchr (spec, ':');
122 if (colon)
124 *colon = '\0';
126 if (colon > spec)
128 sym->file = source_file_lookup_name (spec);
130 if (!sym->file)
131 sym->file = &non_existent_file;
134 spec = colon + 1;
136 if (strlen (spec))
138 if (ISDIGIT (spec[0]))
139 sym->line_num = atoi (spec);
140 else
141 sym->name = spec;
144 else if (strlen (spec))
146 /* No colon: spec is a filename if it contains a dot. */
147 if (strchr (spec, '.'))
149 sym->file = source_file_lookup_name (spec);
151 if (!sym->file)
152 sym->file = &non_existent_file;
154 else if (ISDIGIT (*spec))
156 sym->line_num = atoi (spec);
158 else if (strlen (spec))
160 sym->name = spec;
166 /* A symbol id has the syntax SPEC[/SPEC], where SPEC is is defined
167 by parse_spec(). */
169 static void
170 parse_id (struct sym_id *id)
172 char *slash;
174 DBG (IDDEBUG, printf ("[parse_id] %s -> ", id->spec));
176 slash = strchr (id->spec, '/');
177 if (slash)
179 parse_spec (slash + 1, &id->right.sym);
180 *slash = '\0';
181 id->has_right = TRUE;
183 parse_spec (id->spec, &id->left.sym);
185 #ifdef DEBUG
186 if (debug_level & IDDEBUG)
188 printf ("%s:", id->left.sym.file ? id->left.sym.file->name : "*");
190 if (id->left.sym.name)
191 printf ("%s", id->left.sym.name);
192 else if (id->left.sym.line_num)
193 printf ("%d", id->left.sym.line_num);
194 else
195 printf ("*");
197 if (id->has_right)
199 printf ("/%s:",
200 id->right.sym.file ? id->right.sym.file->name : "*");
202 if (id->right.sym.name)
203 printf ("%s", id->right.sym.name);
204 else if (id->right.sym.line_num)
205 printf ("%d", id->right.sym.line_num);
206 else
207 printf ("*");
210 printf ("\n");
212 #endif
216 /* Return TRUE iff PATTERN matches SYM. */
218 static bfd_boolean
219 match (Sym *pattern, Sym *sym)
221 return (pattern->file ? pattern->file == sym->file : TRUE)
222 && (pattern->line_num ? pattern->line_num == sym->line_num : TRUE)
223 && (pattern->name
224 ? strcmp (pattern->name,
225 sym->name+(discard_underscores && sym->name[0] == '_')) == 0
226 : TRUE);
230 static void
231 extend_match (struct match *m, Sym *sym, Sym_Table *tab, bfd_boolean second_pass)
233 if (m->prev_match != sym - 1)
235 /* Discontinuity: add new match to table. */
236 if (second_pass)
238 tab->base[tab->len] = *sym;
239 m->prev_index = tab->len;
241 /* Link match into match's chain. */
242 tab->base[tab->len].next = m->first_match;
243 m->first_match = &tab->base[tab->len];
246 ++tab->len;
249 /* Extend match to include this symbol. */
250 if (second_pass)
251 tab->base[m->prev_index].end_addr = sym->end_addr;
253 m->prev_match = sym;
257 /* Go through sym_id list produced by option processing and fill
258 in the various symbol tables indicating what symbols should
259 be displayed or suppressed for the various kinds of outputs.
261 This can potentially produce huge tables and in particulars
262 tons of arcs, but this happens only if the user makes silly
263 requests---you get what you ask for! */
265 void
266 sym_id_parse ()
268 Sym *sym, *left, *right;
269 struct sym_id *id;
270 Sym_Table *tab;
272 /* Convert symbol ids into Syms, so we can deal with them more easily. */
273 for (id = id_list; id; id = id->next)
274 parse_id (id);
276 /* First determine size of each table. */
277 for (sym = symtab.base; sym < symtab.limit; ++sym)
279 for (id = id_list; id; id = id->next)
281 if (match (&id->left.sym, sym))
282 extend_match (&id->left, sym, &syms[id->which_table], FALSE);
284 if (id->has_right && match (&id->right.sym, sym))
285 extend_match (&id->right, sym, &right_ids, FALSE);
289 /* Create tables of appropriate size and reset lengths. */
290 for (tab = syms; tab < &syms[NUM_TABLES]; ++tab)
292 if (tab->len)
294 tab->base = (Sym *) xmalloc (tab->len * sizeof (Sym));
295 tab->limit = tab->base + tab->len;
296 tab->len = 0;
300 if (right_ids.len)
302 right_ids.base = (Sym *) xmalloc (right_ids.len * sizeof (Sym));
303 right_ids.limit = right_ids.base + right_ids.len;
304 right_ids.len = 0;
307 /* Make a second pass through symtab, creating syms as necessary. */
308 for (sym = symtab.base; sym < symtab.limit; ++sym)
310 for (id = id_list; id; id = id->next)
312 if (match (&id->left.sym, sym))
313 extend_match (&id->left, sym, &syms[id->which_table], TRUE);
315 if (id->has_right && match (&id->right.sym, sym))
316 extend_match (&id->right, sym, &right_ids, TRUE);
320 /* Go through ids creating arcs as needed. */
321 for (id = id_list; id; id = id->next)
323 if (id->has_right)
325 for (left = id->left.first_match; left; left = left->next)
327 for (right = id->right.first_match; right; right = right->next)
329 DBG (IDDEBUG,
330 printf (
331 "[sym_id_parse]: arc %s:%s(%lx-%lx) -> %s:%s(%lx-%lx) to %s\n",
332 left->file ? left->file->name : "*",
333 left->name ? left->name : "*",
334 (unsigned long) left->addr,
335 (unsigned long) left->end_addr,
336 right->file ? right->file->name : "*",
337 right->name ? right->name : "*",
338 (unsigned long) right->addr,
339 (unsigned long) right->end_addr,
340 table_name[id->which_table]));
342 arc_add (left, right, (unsigned long) 0);
348 /* Finally, we can sort the tables and we're done. */
349 for (tab = &syms[0]; tab < &syms[NUM_TABLES]; ++tab)
351 DBG (IDDEBUG, printf ("[sym_id_parse] syms[%s]:\n",
352 table_name[tab - &syms[0]]));
353 symtab_finalize (tab);
358 /* Symbol tables storing the FROM symbols of arcs do not necessarily
359 have distinct address ranges. For example, somebody might request
360 -k /_mcount to suppress any arcs into _mcount, while at the same
361 time requesting -k a/b. Fortunately, those symbol tables don't get
362 very big (the user has to type them!), so a linear search is probably
363 tolerable. */
364 bfd_boolean
365 sym_id_arc_is_present (Sym_Table *sym_tab, Sym *from, Sym *to)
367 Sym *sym;
369 for (sym = sym_tab->base; sym < sym_tab->limit; ++sym)
371 if (from->addr >= sym->addr && from->addr <= sym->end_addr
372 && arc_lookup (sym, to))
373 return TRUE;
376 return FALSE;