update copyright dates
[platform/upstream/binutils.git] / gprof / sym_ids.c
1 /* sym_ids.c
2
3    Copyright 1999, 2000, 2001, 2002, 2004, 2007 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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA
20    02110-1301, USA.  */
21 \f
22 #include "gprof.h"
23 #include "libiberty.h"
24 #include "safe-ctype.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 #include "corefile.h"
31
32 static struct 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
50 static void parse_spec
51   (char *, Sym *);
52 static void parse_id
53   (struct sym_id *);
54 static bfd_boolean match
55   (Sym *, Sym *);
56 static void extend_match
57   (struct match *, Sym *, Sym_Table *, bfd_boolean);
58
59
60 Sym_Table syms[NUM_TABLES];
61
62 #ifdef DEBUG
63 static const 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).  */
79 static Sym_Table right_ids;
80
81 static Source_File non_existent_file =
82 {
83   0, "<non-existent-file>", 0, 0, 0, NULL
84 };
85
86
87 void
88 sym_id_add (const char *spec, Table_Id which_table)
89 {
90   struct sym_id *id;
91   int len = strlen (spec);
92
93   id = (struct sym_id *) xmalloc (sizeof (*id) + len + 1);
94   memset (id, 0, sizeof (*id));
95
96   id->spec = (char *) id + sizeof (*id);
97   strcpy (id->spec, spec);
98   id->which_table = which_table;
99
100   id->next = id_list;
101   id_list = id;
102 }
103
104
105 /* A spec has the syntax FILENAME:(FUNCNAME|LINENUM).  As a convenience
106    to the user, a spec without a colon is interpreted as:
107
108         (i)   a FILENAME if it contains a dot
109         (ii)  a FUNCNAME if it starts with a non-digit character
110         (iii) a LINENUM if it starts with a digit
111
112    A FUNCNAME containing a dot can be specified by :FUNCNAME, a
113    FILENAME not containing a dot can be specified by FILENAME.  */
114
115 static void
116 parse_spec (char *spec, Sym *sym)
117 {
118   char *colon;
119
120   sym_init (sym);
121   colon = strrchr (spec, ':');
122
123   if (colon)
124     {
125       *colon = '\0';
126
127       if (colon > spec)
128         {
129           sym->file = source_file_lookup_name (spec);
130
131           if (!sym->file)
132             sym->file = &non_existent_file;
133         }
134
135       spec = colon + 1;
136
137       if (strlen (spec))
138         {
139           if (ISDIGIT (spec[0]))
140             sym->line_num = atoi (spec);
141           else
142             sym->name = spec;
143         }
144     }
145   else if (strlen (spec))
146     {
147       /* No colon: spec is a filename if it contains a dot.  */
148       if (strchr (spec, '.'))
149         {
150           sym->file = source_file_lookup_name (spec);
151
152           if (!sym->file)
153             sym->file = &non_existent_file;
154         }
155       else if (ISDIGIT (*spec))
156         {
157           sym->line_num = atoi (spec);
158         }
159       else if (strlen (spec))
160         {
161           sym->name = spec;
162         }
163     }
164 }
165
166
167 /* A symbol id has the syntax SPEC[/SPEC], where SPEC is is defined
168    by parse_spec().  */
169
170 static void
171 parse_id (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 bfd_boolean
220 match (Sym *pattern, Sym *sym)
221 {
222   if (pattern->file && pattern->file != sym->file)
223     return FALSE;
224   if (pattern->line_num && pattern->line_num != sym->line_num)
225     return FALSE;
226   if (pattern->name)
227     {
228       const char *sym_name = sym->name;
229       if (*sym_name && bfd_get_symbol_leading_char (core_bfd) == *sym_name)
230         sym_name++;
231       if (strcmp (pattern->name, sym_name) != 0)
232         return FALSE;
233     }
234   return TRUE;
235 }
236
237
238 static void
239 extend_match (struct match *m, Sym *sym, Sym_Table *tab, bfd_boolean second_pass)
240 {
241   if (m->prev_match != sym - 1)
242     {
243       /* Discontinuity: add new match to table.  */
244       if (second_pass)
245         {
246           tab->base[tab->len] = *sym;
247           m->prev_index = tab->len;
248
249           /* Link match into match's chain.  */
250           tab->base[tab->len].next = m->first_match;
251           m->first_match = &tab->base[tab->len];
252         }
253
254       ++tab->len;
255     }
256
257   /* Extend match to include this symbol.  */
258   if (second_pass)
259     tab->base[m->prev_index].end_addr = sym->end_addr;
260
261   m->prev_match = sym;
262 }
263
264
265 /* Go through sym_id list produced by option processing and fill
266    in the various symbol tables indicating what symbols should
267    be displayed or suppressed for the various kinds of outputs.
268
269    This can potentially produce huge tables and in particulars
270    tons of arcs, but this happens only if the user makes silly
271    requests---you get what you ask for!  */
272
273 void
274 sym_id_parse ()
275 {
276   Sym *sym, *left, *right;
277   struct sym_id *id;
278   Sym_Table *tab;
279
280   /* Convert symbol ids into Syms, so we can deal with them more easily.  */
281   for (id = id_list; id; id = id->next)
282     parse_id (id);
283
284   /* First determine size of each table.  */
285   for (sym = symtab.base; sym < symtab.limit; ++sym)
286     {
287       for (id = id_list; id; id = id->next)
288         {
289           if (match (&id->left.sym, sym))
290             extend_match (&id->left, sym, &syms[id->which_table], FALSE);
291
292           if (id->has_right && match (&id->right.sym, sym))
293             extend_match (&id->right, sym, &right_ids, FALSE);
294         }
295     }
296
297   /* Create tables of appropriate size and reset lengths.  */
298   for (tab = syms; tab < &syms[NUM_TABLES]; ++tab)
299     {
300       if (tab->len)
301         {
302           tab->base = (Sym *) xmalloc (tab->len * sizeof (Sym));
303           tab->limit = tab->base + tab->len;
304           tab->len = 0;
305         }
306     }
307
308   if (right_ids.len)
309     {
310       right_ids.base = (Sym *) xmalloc (right_ids.len * sizeof (Sym));
311       right_ids.limit = right_ids.base + right_ids.len;
312       right_ids.len = 0;
313     }
314
315   /* Make a second pass through symtab, creating syms as necessary.  */
316   for (sym = symtab.base; sym < symtab.limit; ++sym)
317     {
318       for (id = id_list; id; id = id->next)
319         {
320           if (match (&id->left.sym, sym))
321             extend_match (&id->left, sym, &syms[id->which_table], TRUE);
322
323           if (id->has_right && match (&id->right.sym, sym))
324             extend_match (&id->right, sym, &right_ids, TRUE);
325         }
326     }
327
328   /* Go through ids creating arcs as needed.  */
329   for (id = id_list; id; id = id->next)
330     {
331       if (id->has_right)
332         {
333           for (left = id->left.first_match; left; left = left->next)
334             {
335               for (right = id->right.first_match; right; right = right->next)
336                 {
337                   DBG (IDDEBUG,
338                        printf (
339                                 "[sym_id_parse]: arc %s:%s(%lx-%lx) -> %s:%s(%lx-%lx) to %s\n",
340                                 left->file ? left->file->name : "*",
341                                 left->name ? left->name : "*",
342                                 (unsigned long) left->addr,
343                                 (unsigned long) left->end_addr,
344                                 right->file ? right->file->name : "*",
345                                 right->name ? right->name : "*",
346                                 (unsigned long) right->addr,
347                                 (unsigned long) right->end_addr,
348                                 table_name[id->which_table]));
349
350                   arc_add (left, right, (unsigned long) 0);
351                 }
352             }
353         }
354     }
355
356   /* Finally, we can sort the tables and we're done.  */
357   for (tab = &syms[0]; tab < &syms[NUM_TABLES]; ++tab)
358     {
359       DBG (IDDEBUG, printf ("[sym_id_parse] syms[%s]:\n",
360                             table_name[tab - &syms[0]]));
361       symtab_finalize (tab);
362     }
363 }
364
365
366 /* Symbol tables storing the FROM symbols of arcs do not necessarily
367    have distinct address ranges.  For example, somebody might request
368    -k /_mcount to suppress any arcs into _mcount, while at the same
369    time requesting -k a/b.  Fortunately, those symbol tables don't get
370    very big (the user has to type them!), so a linear search is probably
371    tolerable.  */
372 bfd_boolean
373 sym_id_arc_is_present (Sym_Table *sym_tab, Sym *from, Sym *to)
374 {
375   Sym *sym;
376
377   for (sym = sym_tab->base; sym < sym_tab->limit; ++sym)
378     {
379       if (from->addr >= sym->addr && from->addr <= sym->end_addr
380           && arc_lookup (sym, to))
381         return TRUE;
382     }
383
384   return FALSE;
385 }