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