update copyright dates
[deliverable/binutils-gdb.git] / gprof / sym_ids.c
1 /* sym_ids.c
2
3 Copyright 1999, 2000, 2001, 2002, 2004 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 2 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., 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
21 \f
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"
30
31 struct sym_id
32 {
33 struct sym_id *next;
34 char *spec; /* Parsing modifies this. */
35 Table_Id which_table;
36 bfd_boolean has_right;
37
38 struct match
39 {
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;
44 }
45 left, right;
46 }
47 *id_list;
48
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);
57
58
59 Sym_Table syms[NUM_TABLES];
60
61 #ifdef DEBUG
62 const char *table_name[] =
63 {
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"
70 };
71 #endif /* DEBUG */
72
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;
79
80 static Source_File non_existent_file =
81 {
82 0, "<non-existent-file>", 0, 0, 0, NULL
83 };
84
85
86 void
87 sym_id_add (const char *spec, Table_Id which_table)
88 {
89 struct sym_id *id;
90 int len = strlen (spec);
91
92 id = (struct sym_id *) xmalloc (sizeof (*id) + len + 1);
93 memset (id, 0, sizeof (*id));
94
95 id->spec = (char *) id + sizeof (*id);
96 strcpy (id->spec, spec);
97 id->which_table = which_table;
98
99 id->next = id_list;
100 id_list = id;
101 }
102
103
104 /* A spec has the syntax FILENAME:(FUNCNAME|LINENUM). As a convenience
105 to the user, a spec without a colon is interpreted as:
106
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
110
111 A FUNCNAME containing a dot can be specified by :FUNCNAME, a
112 FILENAME not containing a dot can be specified by FILENAME. */
113
114 static void
115 parse_spec (char *spec, Sym *sym)
116 {
117 char *colon;
118
119 sym_init (sym);
120 colon = strrchr (spec, ':');
121
122 if (colon)
123 {
124 *colon = '\0';
125
126 if (colon > spec)
127 {
128 sym->file = source_file_lookup_name (spec);
129
130 if (!sym->file)
131 sym->file = &non_existent_file;
132 }
133
134 spec = colon + 1;
135
136 if (strlen (spec))
137 {
138 if (ISDIGIT (spec[0]))
139 sym->line_num = atoi (spec);
140 else
141 sym->name = spec;
142 }
143 }
144 else if (strlen (spec))
145 {
146 /* No colon: spec is a filename if it contains a dot. */
147 if (strchr (spec, '.'))
148 {
149 sym->file = source_file_lookup_name (spec);
150
151 if (!sym->file)
152 sym->file = &non_existent_file;
153 }
154 else if (ISDIGIT (*spec))
155 {
156 sym->line_num = atoi (spec);
157 }
158 else if (strlen (spec))
159 {
160 sym->name = spec;
161 }
162 }
163 }
164
165
166 /* A symbol id has the syntax SPEC[/SPEC], where SPEC is is defined
167 by parse_spec(). */
168
169 static void
170 parse_id (struct sym_id *id)
171 {
172 char *slash;
173
174 DBG (IDDEBUG, printf ("[parse_id] %s -> ", id->spec));
175
176 slash = strchr (id->spec, '/');
177 if (slash)
178 {
179 parse_spec (slash + 1, &id->right.sym);
180 *slash = '\0';
181 id->has_right = TRUE;
182 }
183 parse_spec (id->spec, &id->left.sym);
184
185 #ifdef DEBUG
186 if (debug_level & IDDEBUG)
187 {
188 printf ("%s:", id->left.sym.file ? id->left.sym.file->name : "*");
189
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 ("*");
196
197 if (id->has_right)
198 {
199 printf ("/%s:",
200 id->right.sym.file ? id->right.sym.file->name : "*");
201
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 ("*");
208 }
209
210 printf ("\n");
211 }
212 #endif
213 }
214
215
216 /* Return TRUE iff PATTERN matches SYM. */
217
218 static bfd_boolean
219 match (Sym *pattern, Sym *sym)
220 {
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);
227 }
228
229
230 static void
231 extend_match (struct match *m, Sym *sym, Sym_Table *tab, bfd_boolean second_pass)
232 {
233 if (m->prev_match != sym - 1)
234 {
235 /* Discontinuity: add new match to table. */
236 if (second_pass)
237 {
238 tab->base[tab->len] = *sym;
239 m->prev_index = tab->len;
240
241 /* Link match into match's chain. */
242 tab->base[tab->len].next = m->first_match;
243 m->first_match = &tab->base[tab->len];
244 }
245
246 ++tab->len;
247 }
248
249 /* Extend match to include this symbol. */
250 if (second_pass)
251 tab->base[m->prev_index].end_addr = sym->end_addr;
252
253 m->prev_match = sym;
254 }
255
256
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.
260
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! */
264
265 void
266 sym_id_parse ()
267 {
268 Sym *sym, *left, *right;
269 struct sym_id *id;
270 Sym_Table *tab;
271
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);
275
276 /* First determine size of each table. */
277 for (sym = symtab.base; sym < symtab.limit; ++sym)
278 {
279 for (id = id_list; id; id = id->next)
280 {
281 if (match (&id->left.sym, sym))
282 extend_match (&id->left, sym, &syms[id->which_table], FALSE);
283
284 if (id->has_right && match (&id->right.sym, sym))
285 extend_match (&id->right, sym, &right_ids, FALSE);
286 }
287 }
288
289 /* Create tables of appropriate size and reset lengths. */
290 for (tab = syms; tab < &syms[NUM_TABLES]; ++tab)
291 {
292 if (tab->len)
293 {
294 tab->base = (Sym *) xmalloc (tab->len * sizeof (Sym));
295 tab->limit = tab->base + tab->len;
296 tab->len = 0;
297 }
298 }
299
300 if (right_ids.len)
301 {
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;
305 }
306
307 /* Make a second pass through symtab, creating syms as necessary. */
308 for (sym = symtab.base; sym < symtab.limit; ++sym)
309 {
310 for (id = id_list; id; id = id->next)
311 {
312 if (match (&id->left.sym, sym))
313 extend_match (&id->left, sym, &syms[id->which_table], TRUE);
314
315 if (id->has_right && match (&id->right.sym, sym))
316 extend_match (&id->right, sym, &right_ids, TRUE);
317 }
318 }
319
320 /* Go through ids creating arcs as needed. */
321 for (id = id_list; id; id = id->next)
322 {
323 if (id->has_right)
324 {
325 for (left = id->left.first_match; left; left = left->next)
326 {
327 for (right = id->right.first_match; right; right = right->next)
328 {
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]));
341
342 arc_add (left, right, (unsigned long) 0);
343 }
344 }
345 }
346 }
347
348 /* Finally, we can sort the tables and we're done. */
349 for (tab = &syms[0]; tab < &syms[NUM_TABLES]; ++tab)
350 {
351 DBG (IDDEBUG, printf ("[sym_id_parse] syms[%s]:\n",
352 table_name[tab - &syms[0]]));
353 symtab_finalize (tab);
354 }
355 }
356
357
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)
366 {
367 Sym *sym;
368
369 for (sym = sym_tab->base; sym < sym_tab->limit; ++sym)
370 {
371 if (from->addr >= sym->addr && from->addr <= sym->end_addr
372 && arc_lookup (sym, to))
373 return TRUE;
374 }
375
376 return FALSE;
377 }
This page took 0.038973 seconds and 5 git commands to generate.