Updated Translations
[platform/upstream/binutils.git] / gprof / sym_ids.c
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 \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     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 PARAMS ((char *, Sym *));
50 static void parse_id PARAMS ((struct sym_id *));
51 static boolean match PARAMS ((Sym *, Sym *));
52 static void extend_match PARAMS ((struct match *, Sym *, Sym_Table *, boolean));
53
54
55 Sym_Table syms[NUM_TABLES];
56
57 #ifdef DEBUG
58 const char *table_name[] =
59 {
60   "INCL_GRAPH", "EXCL_GRAPH",
61   "INCL_ARCS", "EXCL_ARCS",
62   "INCL_FLAT", "EXCL_FLAT",
63   "INCL_TIME", "EXCL_TIME",
64   "INCL_ANNO", "EXCL_ANNO",
65   "INCL_EXEC", "EXCL_EXEC"
66 };
67 #endif /* DEBUG */
68
69 /* This is the table in which we keep all the syms that match
70    the right half of an arc id.  It is NOT sorted according
71    to the addresses, because it is accessed only through
72    the left half's CHILDREN pointers (so it's crucial not
73    to reorder this table once pointers into it exist).  */
74 static Sym_Table right_ids;
75
76 static Source_File non_existent_file =
77 {
78   0, "<non-existent-file>", 0, 0, 0, NULL
79 };
80
81
82 void
83 sym_id_add (spec, which_table)
84      const char *spec;
85      Table_Id which_table;
86 {
87   struct sym_id *id;
88   int len = strlen (spec);
89
90   id = (struct sym_id *) xmalloc (sizeof (*id) + len + 1);
91   memset (id, 0, sizeof (*id));
92
93   id->spec = (char *) id + sizeof (*id);
94   strcpy (id->spec, spec);
95   id->which_table = which_table;
96
97   id->next = id_list;
98   id_list = id;
99 }
100
101
102 /* A spec has the syntax FILENAME:(FUNCNAME|LINENUM).  As a convenience
103    to the user, a spec without a colon is interpreted as:
104
105         (i)   a FILENAME if it contains a dot
106         (ii)  a FUNCNAME if it starts with a non-digit character
107         (iii) a LINENUM if it starts with a digit
108
109    A FUNCNAME containing a dot can be specified by :FUNCNAME, a
110    FILENAME not containing a dot can be specified by FILENAME.  */
111
112 static void
113 parse_spec (spec, sym)
114      char *spec;
115      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 (id)
171      struct sym_id *id;
172 {
173   char *slash;
174
175   DBG (IDDEBUG, printf ("[parse_id] %s -> ", id->spec));
176
177   slash = strchr (id->spec, '/');
178   if (slash)
179     {
180       parse_spec (slash + 1, &id->right.sym);
181       *slash = '\0';
182       id->has_right = true;
183     }
184   parse_spec (id->spec, &id->left.sym);
185
186 #ifdef DEBUG
187   if (debug_level & IDDEBUG)
188     {
189       printf ("%s:", id->left.sym.file ? id->left.sym.file->name : "*");
190
191       if (id->left.sym.name)
192         printf ("%s", id->left.sym.name);
193       else if (id->left.sym.line_num)
194         printf ("%d", id->left.sym.line_num);
195       else
196         printf ("*");
197
198       if (id->has_right)
199         {
200           printf ("/%s:",
201                   id->right.sym.file ? id->right.sym.file->name : "*");
202
203           if (id->right.sym.name)
204             printf ("%s", id->right.sym.name);
205           else if (id->right.sym.line_num)
206             printf ("%d", id->right.sym.line_num);
207           else
208             printf ("*");
209         }
210
211       printf ("\n");
212     }
213 #endif
214 }
215
216
217 /* Return TRUE iff PATTERN matches SYM.  */
218
219 static boolean
220 match (pattern, sym)
221      Sym *pattern;
222      Sym *sym;
223 {
224   return (pattern->file ? pattern->file == sym->file : true)
225     && (pattern->line_num ? pattern->line_num == sym->line_num : true)
226     && (pattern->name
227         ? strcmp (pattern->name,
228                   sym->name+(discard_underscores && sym->name[0] == '_')) == 0
229         : true);
230 }
231
232
233 static void
234 extend_match (m, sym, tab, second_pass)
235      struct match *m;
236      Sym *sym;
237      Sym_Table *tab;
238      boolean second_pass;
239 {
240   if (m->prev_match != sym - 1)
241     {
242       /* Discontinuity: add new match to table.  */
243       if (second_pass)
244         {
245           tab->base[tab->len] = *sym;
246           m->prev_index = tab->len;
247
248           /* Link match into match's chain.  */
249           tab->base[tab->len].next = m->first_match;
250           m->first_match = &tab->base[tab->len];
251         }
252
253       ++tab->len;
254     }
255
256   /* Extend match to include this symbol.  */
257   if (second_pass)
258     tab->base[m->prev_index].end_addr = sym->end_addr;
259
260   m->prev_match = sym;
261 }
262
263
264 /* Go through sym_id list produced by option processing and fill
265    in the various symbol tables indicating what symbols should
266    be displayed or suppressed for the various kinds of outputs.
267
268    This can potentially produce huge tables and in particulars
269    tons of arcs, but this happens only if the user makes silly
270    requests---you get what you ask for!  */
271
272 void
273 sym_id_parse ()
274 {
275   Sym *sym, *left, *right;
276   struct sym_id *id;
277   Sym_Table *tab;
278
279   /* Convert symbol ids into Syms, so we can deal with them more easily.  */
280   for (id = id_list; id; id = id->next)
281     parse_id (id);
282
283   /* First determine size of each table.  */
284   for (sym = symtab.base; sym < symtab.limit; ++sym)
285     {
286       for (id = id_list; id; id = id->next)
287         {
288           if (match (&id->left.sym, sym))
289             extend_match (&id->left, sym, &syms[id->which_table], false);
290
291           if (id->has_right && match (&id->right.sym, sym))
292             extend_match (&id->right, sym, &right_ids, false);
293         }
294     }
295
296   /* Create tables of appropriate size and reset lengths.  */
297   for (tab = syms; tab < &syms[NUM_TABLES]; ++tab)
298     {
299       if (tab->len)
300         {
301           tab->base = (Sym *) xmalloc (tab->len * sizeof (Sym));
302           tab->limit = tab->base + tab->len;
303           tab->len = 0;
304         }
305     }
306
307   if (right_ids.len)
308     {
309       right_ids.base = (Sym *) xmalloc (right_ids.len * sizeof (Sym));
310       right_ids.limit = right_ids.base + right_ids.len;
311       right_ids.len = 0;
312     }
313
314   /* Make a second pass through symtab, creating syms as necessary.  */
315   for (sym = symtab.base; sym < symtab.limit; ++sym)
316     {
317       for (id = id_list; id; id = id->next)
318         {
319           if (match (&id->left.sym, sym))
320             extend_match (&id->left, sym, &syms[id->which_table], true);
321
322           if (id->has_right && match (&id->right.sym, sym))
323             extend_match (&id->right, sym, &right_ids, true);
324         }
325     }
326
327   /* Go through ids creating arcs as needed.  */
328   for (id = id_list; id; id = id->next)
329     {
330       if (id->has_right)
331         {
332           for (left = id->left.first_match; left; left = left->next)
333             {
334               for (right = id->right.first_match; right; right = right->next)
335                 {
336                   DBG (IDDEBUG,
337                        printf (
338                                 "[sym_id_parse]: arc %s:%s(%lx-%lx) -> %s:%s(%lx-%lx) to %s\n",
339                                 left->file ? left->file->name : "*",
340                                 left->name ? left->name : "*",
341                                 (unsigned long) left->addr,
342                                 (unsigned long) left->end_addr,
343                                 right->file ? right->file->name : "*",
344                                 right->name ? right->name : "*",
345                                 (unsigned long) right->addr,
346                                 (unsigned long) right->end_addr,
347                                 table_name[id->which_table]));
348
349                   arc_add (left, right, (unsigned long) 0);
350                 }
351             }
352         }
353     }
354
355   /* Finally, we can sort the tables and we're done.  */
356   for (tab = &syms[0]; tab < &syms[NUM_TABLES]; ++tab)
357     {
358       DBG (IDDEBUG, printf ("[sym_id_parse] syms[%s]:\n",
359                             table_name[tab - &syms[0]]));
360       symtab_finalize (tab);
361     }
362 }
363
364
365 /* Symbol tables storing the FROM symbols of arcs do not necessarily
366    have distinct address ranges.  For example, somebody might request
367    -k /_mcount to suppress any arcs into _mcount, while at the same
368    time requesting -k a/b.  Fortunately, those symbol tables don't get
369    very big (the user has to type them!), so a linear search is probably
370    tolerable.  */
371 boolean
372 sym_id_arc_is_present (sym_tab, from, to)
373      Sym_Table *sym_tab;
374      Sym *from;
375      Sym *to;
376 {
377   Sym *sym;
378
379   for (sym = sym_tab->base; sym < sym_tab->limit; ++sym)
380     {
381       if (from->addr >= sym->addr && from->addr <= sym->end_addr
382           && arc_lookup (sym, to))
383         return true;
384     }
385
386   return false;
387 }