1 /* This file is part of GNU cflow
2    Copyright (C) 1997-2019 Sergey Poznyakoff
3 
4    GNU cflow is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8 
9    GNU cflow is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16 
17 #include <cflow.h>
18 #include <parser.h>
19 #include <hash.h>
20 
21 static Hash_table *symbol_table;
22 
23 static struct linked_list *static_symbol_list;
24 static struct linked_list *auto_symbol_list;
25 static struct linked_list *static_func_list;
26 static struct linked_list *unit_local_list;
27 
28 static void
append_symbol(struct linked_list ** plist,Symbol * sp)29 append_symbol(struct linked_list **plist, Symbol *sp)
30 {
31      if (sp->entry) {
32 	  linked_list_unlink(sp->entry->list, sp->entry);
33 	  sp->entry = NULL;
34      }
35      if (!data_in_list(sp, *plist)) {
36 	  linked_list_append(plist, sp);
37 	  sp->entry = (*plist)->tail;
38      }
39 }
40 
41 struct table_entry {
42      Symbol *sym;
43 };
44 
45 /* Calculate the hash of a string.  */
46 static size_t
hash_symbol_hasher(void const * data,size_t n_buckets)47 hash_symbol_hasher(void const *data, size_t n_buckets)
48 {
49      struct table_entry const *t = data;
50      if (!t->sym)
51 	  return ((size_t) data) % n_buckets;
52      return hash_string(t->sym->name, n_buckets);
53 }
54 
55 /* Compare two strings for equality.  */
56 static bool
hash_symbol_compare(void const * data1,void const * data2)57 hash_symbol_compare(void const *data1, void const *data2)
58 {
59      struct table_entry const *t1 = data1;
60      struct table_entry const *t2 = data2;
61      return t1->sym && t2->sym && strcmp(t1->sym->name, t2->sym->name) == 0;
62 }
63 
64 Symbol *
lookup(const char * name)65 lookup(const char *name)
66 {
67      Symbol s, *sym;
68      struct table_entry t, *tp;
69 
70      if (!symbol_table)
71 	  return NULL;
72      s.name = (char*) name;
73      t.sym = &s;
74      tp = hash_lookup(symbol_table, &t);
75      if (tp) {
76 	  sym = tp->sym;
77 	  while (sym->type == SymToken && sym->flag == symbol_alias)
78 	       sym = sym->alias;
79      } else
80 	  sym = NULL;
81      return sym;
82 }
83 
84 /* Install a new symbol `NAME'.  If UNIT_LOCAL is set, this symbol can
85    be local to the current compilation unit. */
86 Symbol *
install(char * name,int flags)87 install(char *name, int flags)
88 {
89      Symbol *sym;
90      struct table_entry *tp, *ret;
91 
92      sym = xmalloc(sizeof(*sym));
93      memset(sym, 0, sizeof(*sym));
94      sym->type = SymUndefined;
95      sym->name = name;
96 
97      tp = xmalloc(sizeof(*tp));
98      tp->sym = sym;
99 
100      if (((flags & INSTALL_CHECK_LOCAL) &&
101 	  canonical_filename && strcmp(filename, canonical_filename)) ||
102 	 (flags & INSTALL_UNIT_LOCAL)) {
103 	  sym->flag = symbol_local;
104 	  append_symbol(&static_symbol_list, sym);
105      } else
106 	  sym->flag = symbol_none;
107 
108      if (! ((symbol_table
109 	     || (symbol_table = hash_initialize (0, 0,
110 						 hash_symbol_hasher,
111 						 hash_symbol_compare, 0)))
112 	    && (ret = hash_insert (symbol_table, tp))))
113 	  xalloc_die ();
114 
115      if (ret != tp) {
116 	  if (flags & INSTALL_OVERWRITE) {
117 	       free(sym);
118 	       free(tp);
119 	       return ret->sym;
120 	  }
121 	  if (ret->sym->type != SymUndefined)
122 	       sym->next = ret->sym;
123 	  ret->sym = sym;
124 	  free(tp);
125      }
126      sym->owner = ret;
127      return sym;
128 }
129 
130 void
ident_change_storage(Symbol * sp,enum storage storage)131 ident_change_storage(Symbol *sp, enum storage storage)
132 {
133      if (sp->storage == storage)
134 	  return;
135      if (sp->storage == StaticStorage)
136 	  /* FIXME */;
137 
138      switch (storage) {
139      case StaticStorage:
140 	  append_symbol(&static_symbol_list, sp);
141 	  break;
142      case AutoStorage:
143 	  append_symbol(&auto_symbol_list, sp);
144 	  break;
145      default:
146 	  break;
147      }
148      sp->storage = storage;
149 }
150 
151 Symbol *
install_ident(char * name,enum storage storage)152 install_ident(char *name, enum storage storage)
153 {
154      Symbol *sp;
155 
156      sp = install(name,
157                   storage != AutoStorage ?
158                      INSTALL_CHECK_LOCAL : INSTALL_DEFAULT);
159      sp->type = SymIdentifier;
160      sp->arity = -1;
161      sp->storage = ExternStorage;
162      sp->decl = NULL;
163      sp->source = NULL;
164      sp->def_line = -1;
165      sp->ref_line = NULL;
166      sp->caller = sp->callee = NULL;
167      sp->level = -1;
168      ident_change_storage(sp, storage);
169      return sp;
170 }
171 
172 /* Unlink the symbol from the table entry */
173 static void
unlink_symbol(Symbol * sym)174 unlink_symbol(Symbol *sym)
175 {
176      Symbol *s, *prev = NULL;
177      struct table_entry *tp = sym->owner;
178      for (s = tp->sym; s; ) {
179 	  Symbol *next = s->next;
180 	  if (s == sym) {
181 	       if (prev)
182 		    prev->next = next;
183 	       else
184 		    tp->sym = next;
185 	       break;
186 	  } else
187 	       prev = s;
188 	  s = next;
189      }
190 
191      sym->owner = NULL;
192 }
193 
194 /* Unlink and free the first symbol from the table entry */
195 static void
delete_symbol(Symbol * sym)196 delete_symbol(Symbol *sym)
197 {
198      unlink_symbol(sym);
199      /* The symbol could have been referenced even if it is static
200 	in -i^s mode. See tests/static.at for details. */
201      if (sym->ref_line == NULL && !(reverse_tree && sym->callee)) {
202 	  linked_list_destroy(&sym->ref_line);
203 	  linked_list_destroy(&sym->caller);
204 	  linked_list_destroy(&sym->callee);
205 	  free(sym);
206      }
207 }
208 
209 /* Delete from the symbol table all static symbols defined in the current
210    source.
211    If the user requested static symbols in the listing, the symbol is
212    not deleted, as it may have been referenced by other symbols. Instead,
213    it is unlinked from its table entry.
214    NOTE: This takes advantage of the fact that install() uses LIFO strategy,
215    so we don't have to check the name of the source where the symbol was
216    defined. */
217 
218 static void
static_free(void * data)219 static_free(void *data)
220 {
221      Symbol *sym = data;
222      struct table_entry *t = sym->owner;
223 
224      if (!t)
225 	  return;
226      if (sym->flag == symbol_local) {
227 	  /* In xref mode, eligible unit-local symbols are retained in
228 	     unit_local_list for further processing.
229 	     Otherwise, they are deleted. */
230 	  if (print_option == PRINT_XREF && include_symbol(sym)) {
231 	       unlink_symbol(sym);
232 	       linked_list_append(&unit_local_list, sym);
233 	  } else {
234 	       delete_symbol(sym);
235 	  }
236      } else {
237 	  unlink_symbol(sym);
238 	  if (symbol_is_function(sym))
239 	       linked_list_append(&static_func_list, sym);
240      }
241 }
242 
243 void
delete_statics()244 delete_statics()
245 {
246      if (static_symbol_list) {
247 	  static_symbol_list->free_data = static_free;
248 	  linked_list_destroy(&static_symbol_list);
249      }
250 }
251 
252 /* See NOTE above */
253 
254 /* Delete from the symbol table all auto variables with given nesting
255    level. */
256 int
delete_level_autos(void * data,void * call_data)257 delete_level_autos(void *data, void *call_data)
258 {
259      int level = *(int*)call_data;
260      Symbol *s = data;
261      if (s->level == level) {
262 	  delete_symbol(s);
263 	  return 1;
264      }
265      return 0;
266 }
267 
268 int
delete_level_statics(void * data,void * call_data)269 delete_level_statics(void *data, void *call_data)
270 {
271      int level = *(int*)call_data;
272      Symbol *s = data;
273      if (s->level == level) {
274 	  unlink_symbol(s);
275 	  return 1;
276      }
277      return 0;
278 }
279 
280 void
delete_autos(int level)281 delete_autos(int level)
282 {
283      linked_list_iterate(&auto_symbol_list, delete_level_autos, &level);
284      linked_list_iterate(&static_symbol_list, delete_level_statics, &level);
285 }
286 
287 struct collect_data {
288      Symbol **sym;
289      int (*sel)(Symbol *p);
290      size_t index;
291 };
292 
293 static bool
collect_processor(void * data,void * proc_data)294 collect_processor(void *data, void *proc_data)
295 {
296      struct table_entry *t = data;
297      struct collect_data *cd = proc_data;
298      Symbol *s;
299      for (s = t->sym; s; s = s->next) {
300 	  if (cd->sel(s)) {
301 	       if (cd->sym)
302 		    cd->sym[cd->index] = s;
303 	       cd->index++;
304 	  }
305      }
306      return true;
307 }
308 
309 static int
collect_list_entry(void * item,void * proc_data)310 collect_list_entry(void *item, void *proc_data)
311 {
312      Symbol *s = item;
313      struct collect_data *cd = proc_data;
314      if (cd->sel(s)) {
315 	  cd->sym[cd->index] = s;
316 	  cd->index++;
317      }
318      return 0;
319 }
320 
321 size_t
collect_symbols(Symbol *** return_sym,int (* sel)(Symbol * p),size_t reserved_slots)322 collect_symbols(Symbol ***return_sym, int (*sel)(Symbol *p),
323 		size_t reserved_slots)
324 {
325      struct collect_data cdata;
326      size_t size;
327 
328      size = hash_get_n_entries(symbol_table)
329 	     + linked_list_size(static_func_list)
330 	     + linked_list_size(unit_local_list);
331      cdata.sym = xcalloc(size + reserved_slots, sizeof(*cdata.sym));
332      cdata.index = 0;
333      cdata.sel = sel;
334      hash_do_for_each(symbol_table, collect_processor, &cdata);
335      linked_list_iterate(&static_func_list, collect_list_entry, &cdata);
336      linked_list_iterate(&unit_local_list, collect_list_entry, &cdata);
337 
338      cdata.sym = xrealloc(cdata.sym,
339 			  (cdata.index + reserved_slots) * sizeof(*cdata.sym));
340      *return_sym = cdata.sym;
341      return cdata.index;
342 }
343 
344 size_t
collect_functions(Symbol *** return_sym)345 collect_functions(Symbol ***return_sym)
346 {
347      Symbol **symbols;
348      size_t num, snum;
349      struct linked_list_entry *p;
350 
351      /* Count static functions */
352      snum = linked_list_size(static_func_list);
353 
354      /* Collect global functions */
355      num = collect_symbols(&symbols, symbol_is_function, snum);
356 
357      /* Collect static functions */
358      if (snum)
359 	  for (p = linked_list_head(static_func_list); p; p = p->next)
360 	       symbols[num++] = p->data;
361      *return_sym = symbols;
362      return num;
363 }
364 
365 
366 
367 /* Special handling for function parameters */
368 
369 int
delete_parms_itr(void * data,void * call_data)370 delete_parms_itr(void *data, void *call_data)
371 {
372      int level = *(int*)call_data;
373      Symbol *s = data;
374      struct table_entry *t = s->owner;
375 
376      if (!t)
377 	  return 1;
378      if (s->type == SymIdentifier && s->storage == AutoStorage
379 	 && s->flag == symbol_parm && s->level > level) {
380 	  delete_symbol(s);
381 	  return 1;
382      }
383      return 0;
384 }
385 
386 /* Delete all parameters with parameter nesting level greater than LEVEL */
387 void
delete_parms(int level)388 delete_parms(int level)
389 {
390      linked_list_iterate(&auto_symbol_list, delete_parms_itr, &level);
391 }
392 
393 /* Redeclare all saved parameters as automatic variables with the
394    given nesting level */
395 void
move_parms(int level)396 move_parms(int level)
397 {
398      struct linked_list_entry *p;
399 
400      for (p = linked_list_head(auto_symbol_list); p; p = p->next) {
401 	  Symbol *s = p->data;
402 
403 	  if (s->type == SymIdentifier && s->storage == AutoStorage
404 	      && s->flag == symbol_parm) {
405 	       s->level = level;
406 	       s->flag = symbol_none;
407 	  }
408      }
409 }
410 
411