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., 51 Franklin Street - Fifth Floor, Boston, MA 20 02110-1301, USA. */ 21 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 static 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 static 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 } 378