source: branches/libc-0.6/src/binutils/gprof/sym_ids.c

Last change on this file was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 9.2 KB
Line 
1/* sym_ids.c
2
3 Copyright 2000, 2001, 2002 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
22
23#include "libiberty.h"
24#include "safe-ctype.h"
25#include "gprof.h"
26#include "search_list.h"
27#include "source.h"
28#include "symtab.h"
29#include "cg_arcs.h"
30#include "sym_ids.h"
31
32struct sym_id
33 {
34 struct sym_id *next;
35 char *spec; /* Parsing modifies this. */
36 Table_Id which_table;
37 bfd_boolean has_right;
38
39 struct match
40 {
41 int prev_index; /* Index of prev match. */
42 Sym *prev_match; /* Previous match. */
43 Sym *first_match; /* Chain of all matches. */
44 Sym sym;
45 }
46 left, right;
47 }
48 *id_list;
49
50static void parse_spec
51 PARAMS ((char *, Sym *));
52static void parse_id
53 PARAMS ((struct sym_id *));
54static bfd_boolean match
55 PARAMS ((Sym *, Sym *));
56static void extend_match
57 PARAMS ((struct match *, Sym *, Sym_Table *, bfd_boolean));
58
59
60Sym_Table syms[NUM_TABLES];
61
62#ifdef DEBUG
63const char *table_name[] =
64{
65 "INCL_GRAPH", "EXCL_GRAPH",
66 "INCL_ARCS", "EXCL_ARCS",
67 "INCL_FLAT", "EXCL_FLAT",
68 "INCL_TIME", "EXCL_TIME",
69 "INCL_ANNO", "EXCL_ANNO",
70 "INCL_EXEC", "EXCL_EXEC"
71};
72#endif /* DEBUG */
73
74/* This is the table in which we keep all the syms that match
75 the right half of an arc id. It is NOT sorted according
76 to the addresses, because it is accessed only through
77 the left half's CHILDREN pointers (so it's crucial not
78 to reorder this table once pointers into it exist). */
79static Sym_Table right_ids;
80
81static Source_File non_existent_file =
82{
83 0, "<non-existent-file>", 0, 0, 0, NULL
84};
85
86
87void
88sym_id_add (spec, which_table)
89 const char *spec;
90 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
117static void
118parse_spec (spec, sym)
119 char *spec;
120 Sym *sym;
121{
122 char *colon;
123
124 sym_init (sym);
125 colon = strrchr (spec, ':');
126
127 if (colon)
128 {
129 *colon = '\0';
130
131 if (colon > spec)
132 {
133 sym->file = source_file_lookup_name (spec);
134
135 if (!sym->file)
136 sym->file = &non_existent_file;
137 }
138
139 spec = colon + 1;
140
141 if (strlen (spec))
142 {
143 if (ISDIGIT (spec[0]))
144 sym->line_num = atoi (spec);
145 else
146 sym->name = spec;
147 }
148 }
149 else if (strlen (spec))
150 {
151 /* No colon: spec is a filename if it contains a dot. */
152 if (strchr (spec, '.'))
153 {
154 sym->file = source_file_lookup_name (spec);
155
156 if (!sym->file)
157 sym->file = &non_existent_file;
158 }
159 else if (ISDIGIT (*spec))
160 {
161 sym->line_num = atoi (spec);
162 }
163 else if (strlen (spec))
164 {
165 sym->name = spec;
166 }
167 }
168}
169
170
171/* A symbol id has the syntax SPEC[/SPEC], where SPEC is is defined
172 by parse_spec(). */
173
174static void
175parse_id (id)
176 struct sym_id *id;
177{
178 char *slash;
179
180 DBG (IDDEBUG, printf ("[parse_id] %s -> ", id->spec));
181
182 slash = strchr (id->spec, '/');
183 if (slash)
184 {
185 parse_spec (slash + 1, &id->right.sym);
186 *slash = '\0';
187 id->has_right = TRUE;
188 }
189 parse_spec (id->spec, &id->left.sym);
190
191#ifdef DEBUG
192 if (debug_level & IDDEBUG)
193 {
194 printf ("%s:", id->left.sym.file ? id->left.sym.file->name : "*");
195
196 if (id->left.sym.name)
197 printf ("%s", id->left.sym.name);
198 else if (id->left.sym.line_num)
199 printf ("%d", id->left.sym.line_num);
200 else
201 printf ("*");
202
203 if (id->has_right)
204 {
205 printf ("/%s:",
206 id->right.sym.file ? id->right.sym.file->name : "*");
207
208 if (id->right.sym.name)
209 printf ("%s", id->right.sym.name);
210 else if (id->right.sym.line_num)
211 printf ("%d", id->right.sym.line_num);
212 else
213 printf ("*");
214 }
215
216 printf ("\n");
217 }
218#endif
219}
220
221
222/* Return TRUE iff PATTERN matches SYM. */
223
224static bfd_boolean
225match (pattern, sym)
226 Sym *pattern;
227 Sym *sym;
228{
229 return (pattern->file ? pattern->file == sym->file : TRUE)
230 && (pattern->line_num ? pattern->line_num == sym->line_num : TRUE)
231 && (pattern->name
232 ? strcmp (pattern->name,
233 sym->name+(discard_underscores && sym->name[0] == '_')) == 0
234 : TRUE);
235}
236
237
238static void
239extend_match (m, sym, tab, second_pass)
240 struct match *m;
241 Sym *sym;
242 Sym_Table *tab;
243 bfd_boolean second_pass;
244{
245 if (m->prev_match != sym - 1)
246 {
247 /* Discontinuity: add new match to table. */
248 if (second_pass)
249 {
250 tab->base[tab->len] = *sym;
251 m->prev_index = tab->len;
252
253 /* Link match into match's chain. */
254 tab->base[tab->len].next = m->first_match;
255 m->first_match = &tab->base[tab->len];
256 }
257
258 ++tab->len;
259 }
260
261 /* Extend match to include this symbol. */
262 if (second_pass)
263 tab->base[m->prev_index].end_addr = sym->end_addr;
264
265 m->prev_match = sym;
266}
267
268
269/* Go through sym_id list produced by option processing and fill
270 in the various symbol tables indicating what symbols should
271 be displayed or suppressed for the various kinds of outputs.
272
273 This can potentially produce huge tables and in particulars
274 tons of arcs, but this happens only if the user makes silly
275 requests---you get what you ask for! */
276
277void
278sym_id_parse ()
279{
280 Sym *sym, *left, *right;
281 struct sym_id *id;
282 Sym_Table *tab;
283
284 /* Convert symbol ids into Syms, so we can deal with them more easily. */
285 for (id = id_list; id; id = id->next)
286 parse_id (id);
287
288 /* First determine size of each table. */
289 for (sym = symtab.base; sym < symtab.limit; ++sym)
290 {
291 for (id = id_list; id; id = id->next)
292 {
293 if (match (&id->left.sym, sym))
294 extend_match (&id->left, sym, &syms[id->which_table], FALSE);
295
296 if (id->has_right && match (&id->right.sym, sym))
297 extend_match (&id->right, sym, &right_ids, FALSE);
298 }
299 }
300
301 /* Create tables of appropriate size and reset lengths. */
302 for (tab = syms; tab < &syms[NUM_TABLES]; ++tab)
303 {
304 if (tab->len)
305 {
306 tab->base = (Sym *) xmalloc (tab->len * sizeof (Sym));
307 tab->limit = tab->base + tab->len;
308 tab->len = 0;
309 }
310 }
311
312 if (right_ids.len)
313 {
314 right_ids.base = (Sym *) xmalloc (right_ids.len * sizeof (Sym));
315 right_ids.limit = right_ids.base + right_ids.len;
316 right_ids.len = 0;
317 }
318
319 /* Make a second pass through symtab, creating syms as necessary. */
320 for (sym = symtab.base; sym < symtab.limit; ++sym)
321 {
322 for (id = id_list; id; id = id->next)
323 {
324 if (match (&id->left.sym, sym))
325 extend_match (&id->left, sym, &syms[id->which_table], TRUE);
326
327 if (id->has_right && match (&id->right.sym, sym))
328 extend_match (&id->right, sym, &right_ids, TRUE);
329 }
330 }
331
332 /* Go through ids creating arcs as needed. */
333 for (id = id_list; id; id = id->next)
334 {
335 if (id->has_right)
336 {
337 for (left = id->left.first_match; left; left = left->next)
338 {
339 for (right = id->right.first_match; right; right = right->next)
340 {
341 DBG (IDDEBUG,
342 printf (
343 "[sym_id_parse]: arc %s:%s(%lx-%lx) -> %s:%s(%lx-%lx) to %s\n",
344 left->file ? left->file->name : "*",
345 left->name ? left->name : "*",
346 (unsigned long) left->addr,
347 (unsigned long) left->end_addr,
348 right->file ? right->file->name : "*",
349 right->name ? right->name : "*",
350 (unsigned long) right->addr,
351 (unsigned long) right->end_addr,
352 table_name[id->which_table]));
353
354 arc_add (left, right, (unsigned long) 0);
355 }
356 }
357 }
358 }
359
360 /* Finally, we can sort the tables and we're done. */
361 for (tab = &syms[0]; tab < &syms[NUM_TABLES]; ++tab)
362 {
363 DBG (IDDEBUG, printf ("[sym_id_parse] syms[%s]:\n",
364 table_name[tab - &syms[0]]));
365 symtab_finalize (tab);
366 }
367}
368
369
370/* Symbol tables storing the FROM symbols of arcs do not necessarily
371 have distinct address ranges. For example, somebody might request
372 -k /_mcount to suppress any arcs into _mcount, while at the same
373 time requesting -k a/b. Fortunately, those symbol tables don't get
374 very big (the user has to type them!), so a linear search is probably
375 tolerable. */
376bfd_boolean
377sym_id_arc_is_present (sym_tab, from, to)
378 Sym_Table *sym_tab;
379 Sym *from;
380 Sym *to;
381{
382 Sym *sym;
383
384 for (sym = sym_tab->base; sym < sym_tab->limit; ++sym)
385 {
386 if (from->addr >= sym->addr && from->addr <= sym->end_addr
387 && arc_lookup (sym, to))
388 return TRUE;
389 }
390
391 return FALSE;
392}
Note: See TracBrowser for help on using the repository browser.