xref: /dflybsd-src/contrib/binutils-2.34/libctf/ctf-hash.c (revision b52ef7118d1621abed722c5bbbd542210290ecef)
1*fae548d3Szrj /* Interface to hashtable implementations.
2*fae548d3Szrj    Copyright (C) 2006-2020 Free Software Foundation, Inc.
3*fae548d3Szrj 
4*fae548d3Szrj    This file is part of libctf.
5*fae548d3Szrj 
6*fae548d3Szrj    libctf is free software; you can redistribute it and/or modify it under
7*fae548d3Szrj    the terms of the GNU General Public License as published by the Free
8*fae548d3Szrj    Software Foundation; either version 3, or (at your option) any later
9*fae548d3Szrj    version.
10*fae548d3Szrj 
11*fae548d3Szrj    This program is distributed in the hope that it will be useful, but
12*fae548d3Szrj    WITHOUT ANY WARRANTY; without even the implied warranty of
13*fae548d3Szrj    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14*fae548d3Szrj    See the GNU General Public License for more details.
15*fae548d3Szrj 
16*fae548d3Szrj    You should have received a copy of the GNU General Public License
17*fae548d3Szrj    along with this program; see the file COPYING.  If not see
18*fae548d3Szrj    <http://www.gnu.org/licenses/>.  */
19*fae548d3Szrj 
20*fae548d3Szrj #include <ctf-impl.h>
21*fae548d3Szrj #include <string.h>
22*fae548d3Szrj #include "libiberty.h"
23*fae548d3Szrj #include "hashtab.h"
24*fae548d3Szrj 
25*fae548d3Szrj /* We have two hashtable implementations: one, ctf_dynhash_*(), is an interface to
26*fae548d3Szrj    a dynamically-expanding hash with unknown size that should support addition
27*fae548d3Szrj    of large numbers of items, and removal as well, and is used only at
28*fae548d3Szrj    type-insertion time; the other, ctf_dynhash_*(), is an interface to a
29*fae548d3Szrj    fixed-size hash from const char * -> ctf_id_t with number of elements
30*fae548d3Szrj    specified at creation time, that should support addition of items but need
31*fae548d3Szrj    not support removal.  These can be implemented by the same underlying hashmap
32*fae548d3Szrj    if you wish.  */
33*fae548d3Szrj 
34*fae548d3Szrj typedef struct ctf_helem
35*fae548d3Szrj {
36*fae548d3Szrj   void *key;			 /* Either a pointer, or a coerced ctf_id_t.  */
37*fae548d3Szrj   void *value;			 /* The value (possibly a coerced int).  */
38*fae548d3Szrj   ctf_hash_free_fun key_free;
39*fae548d3Szrj   ctf_hash_free_fun value_free;
40*fae548d3Szrj } ctf_helem_t;
41*fae548d3Szrj 
42*fae548d3Szrj struct ctf_dynhash
43*fae548d3Szrj {
44*fae548d3Szrj   struct htab *htab;
45*fae548d3Szrj   ctf_hash_free_fun key_free;
46*fae548d3Szrj   ctf_hash_free_fun value_free;
47*fae548d3Szrj };
48*fae548d3Szrj 
49*fae548d3Szrj /* Hash functions. */
50*fae548d3Szrj 
51*fae548d3Szrj unsigned int
ctf_hash_integer(const void * ptr)52*fae548d3Szrj ctf_hash_integer (const void *ptr)
53*fae548d3Szrj {
54*fae548d3Szrj   ctf_helem_t *hep = (ctf_helem_t *) ptr;
55*fae548d3Szrj 
56*fae548d3Szrj   return htab_hash_pointer (hep->key);
57*fae548d3Szrj }
58*fae548d3Szrj 
59*fae548d3Szrj int
ctf_hash_eq_integer(const void * a,const void * b)60*fae548d3Szrj ctf_hash_eq_integer (const void *a, const void *b)
61*fae548d3Szrj {
62*fae548d3Szrj   ctf_helem_t *hep_a = (ctf_helem_t *) a;
63*fae548d3Szrj   ctf_helem_t *hep_b = (ctf_helem_t *) b;
64*fae548d3Szrj 
65*fae548d3Szrj   return htab_eq_pointer (hep_a->key, hep_b->key);
66*fae548d3Szrj }
67*fae548d3Szrj 
68*fae548d3Szrj unsigned int
ctf_hash_string(const void * ptr)69*fae548d3Szrj ctf_hash_string (const void *ptr)
70*fae548d3Szrj {
71*fae548d3Szrj   ctf_helem_t *hep = (ctf_helem_t *) ptr;
72*fae548d3Szrj 
73*fae548d3Szrj   return htab_hash_string (hep->key);
74*fae548d3Szrj }
75*fae548d3Szrj 
76*fae548d3Szrj int
ctf_hash_eq_string(const void * a,const void * b)77*fae548d3Szrj ctf_hash_eq_string (const void *a, const void *b)
78*fae548d3Szrj {
79*fae548d3Szrj   ctf_helem_t *hep_a = (ctf_helem_t *) a;
80*fae548d3Szrj   ctf_helem_t *hep_b = (ctf_helem_t *) b;
81*fae548d3Szrj 
82*fae548d3Szrj   return !strcmp((const char *) hep_a->key, (const char *) hep_b->key);
83*fae548d3Szrj }
84*fae548d3Szrj 
85*fae548d3Szrj /* Hash a type_mapping_key.  */
86*fae548d3Szrj unsigned int
ctf_hash_type_mapping_key(const void * ptr)87*fae548d3Szrj ctf_hash_type_mapping_key (const void *ptr)
88*fae548d3Szrj {
89*fae548d3Szrj   ctf_helem_t *hep = (ctf_helem_t *) ptr;
90*fae548d3Szrj   ctf_link_type_mapping_key_t *k = (ctf_link_type_mapping_key_t *) hep->key;
91*fae548d3Szrj 
92*fae548d3Szrj   return htab_hash_pointer (k->cltm_fp) + 59 * htab_hash_pointer ((void *) k->cltm_idx);
93*fae548d3Szrj }
94*fae548d3Szrj 
95*fae548d3Szrj int
ctf_hash_eq_type_mapping_key(const void * a,const void * b)96*fae548d3Szrj ctf_hash_eq_type_mapping_key (const void *a, const void *b)
97*fae548d3Szrj {
98*fae548d3Szrj   ctf_helem_t *hep_a = (ctf_helem_t *) a;
99*fae548d3Szrj   ctf_helem_t *hep_b = (ctf_helem_t *) b;
100*fae548d3Szrj   ctf_link_type_mapping_key_t *key_a = (ctf_link_type_mapping_key_t *) hep_a->key;
101*fae548d3Szrj   ctf_link_type_mapping_key_t *key_b = (ctf_link_type_mapping_key_t *) hep_b->key;
102*fae548d3Szrj 
103*fae548d3Szrj   return (key_a->cltm_fp == key_b->cltm_fp)
104*fae548d3Szrj     && (key_a->cltm_idx == key_b->cltm_idx);
105*fae548d3Szrj }
106*fae548d3Szrj 
107*fae548d3Szrj /* The dynhash, used for hashes whose size is not known at creation time. */
108*fae548d3Szrj 
109*fae548d3Szrj /* Free a single ctf_helem.  */
110*fae548d3Szrj 
111*fae548d3Szrj static void
ctf_dynhash_item_free(void * item)112*fae548d3Szrj ctf_dynhash_item_free (void *item)
113*fae548d3Szrj {
114*fae548d3Szrj   ctf_helem_t *helem = item;
115*fae548d3Szrj 
116*fae548d3Szrj   if (helem->key_free && helem->key)
117*fae548d3Szrj     helem->key_free (helem->key);
118*fae548d3Szrj   if (helem->value_free && helem->value)
119*fae548d3Szrj     helem->value_free (helem->value);
120*fae548d3Szrj   free (helem);
121*fae548d3Szrj }
122*fae548d3Szrj 
123*fae548d3Szrj ctf_dynhash_t *
ctf_dynhash_create(ctf_hash_fun hash_fun,ctf_hash_eq_fun eq_fun,ctf_hash_free_fun key_free,ctf_hash_free_fun value_free)124*fae548d3Szrj ctf_dynhash_create (ctf_hash_fun hash_fun, ctf_hash_eq_fun eq_fun,
125*fae548d3Szrj                     ctf_hash_free_fun key_free, ctf_hash_free_fun value_free)
126*fae548d3Szrj {
127*fae548d3Szrj   ctf_dynhash_t *dynhash;
128*fae548d3Szrj 
129*fae548d3Szrj   dynhash = malloc (sizeof (ctf_dynhash_t));
130*fae548d3Szrj   if (!dynhash)
131*fae548d3Szrj     return NULL;
132*fae548d3Szrj 
133*fae548d3Szrj   /* 7 is arbitrary and untested for now..  */
134*fae548d3Szrj   if ((dynhash->htab = htab_create_alloc (7, (htab_hash) hash_fun, eq_fun,
135*fae548d3Szrj                                           ctf_dynhash_item_free, xcalloc, free)) == NULL)
136*fae548d3Szrj     {
137*fae548d3Szrj       free (dynhash);
138*fae548d3Szrj       return NULL;
139*fae548d3Szrj     }
140*fae548d3Szrj 
141*fae548d3Szrj   dynhash->key_free = key_free;
142*fae548d3Szrj   dynhash->value_free = value_free;
143*fae548d3Szrj 
144*fae548d3Szrj   return dynhash;
145*fae548d3Szrj }
146*fae548d3Szrj 
147*fae548d3Szrj static ctf_helem_t **
ctf_hashtab_lookup(struct htab * htab,const void * key,enum insert_option insert)148*fae548d3Szrj ctf_hashtab_lookup (struct htab *htab, const void *key, enum insert_option insert)
149*fae548d3Szrj {
150*fae548d3Szrj   ctf_helem_t tmp = { .key = (void *) key };
151*fae548d3Szrj   return (ctf_helem_t **) htab_find_slot (htab, &tmp, insert);
152*fae548d3Szrj }
153*fae548d3Szrj 
154*fae548d3Szrj static ctf_helem_t *
ctf_hashtab_insert(struct htab * htab,void * key,void * value,ctf_hash_free_fun key_free,ctf_hash_free_fun value_free)155*fae548d3Szrj ctf_hashtab_insert (struct htab *htab, void *key, void *value,
156*fae548d3Szrj 		    ctf_hash_free_fun key_free,
157*fae548d3Szrj 		    ctf_hash_free_fun value_free)
158*fae548d3Szrj {
159*fae548d3Szrj   ctf_helem_t **slot;
160*fae548d3Szrj 
161*fae548d3Szrj   slot = ctf_hashtab_lookup (htab, key, INSERT);
162*fae548d3Szrj 
163*fae548d3Szrj   if (!slot)
164*fae548d3Szrj     {
165*fae548d3Szrj       errno = -ENOMEM;
166*fae548d3Szrj       return NULL;
167*fae548d3Szrj     }
168*fae548d3Szrj 
169*fae548d3Szrj   if (!*slot)
170*fae548d3Szrj     {
171*fae548d3Szrj       *slot = malloc (sizeof (ctf_helem_t));
172*fae548d3Szrj       if (!*slot)
173*fae548d3Szrj 	return NULL;
174*fae548d3Szrj     }
175*fae548d3Szrj   else
176*fae548d3Szrj     {
177*fae548d3Szrj       if (key_free)
178*fae548d3Szrj 	  key_free ((*slot)->key);
179*fae548d3Szrj       if (value_free)
180*fae548d3Szrj 	  value_free ((*slot)->value);
181*fae548d3Szrj     }
182*fae548d3Szrj   (*slot)->key = key;
183*fae548d3Szrj   (*slot)->value = value;
184*fae548d3Szrj   return *slot;
185*fae548d3Szrj }
186*fae548d3Szrj 
187*fae548d3Szrj int
ctf_dynhash_insert(ctf_dynhash_t * hp,void * key,void * value)188*fae548d3Szrj ctf_dynhash_insert (ctf_dynhash_t *hp, void *key, void *value)
189*fae548d3Szrj {
190*fae548d3Szrj   ctf_helem_t *slot;
191*fae548d3Szrj 
192*fae548d3Szrj   slot = ctf_hashtab_insert (hp->htab, key, value,
193*fae548d3Szrj 			     hp->key_free, hp->value_free);
194*fae548d3Szrj 
195*fae548d3Szrj   if (!slot)
196*fae548d3Szrj     return errno;
197*fae548d3Szrj 
198*fae548d3Szrj   /* We need to keep the key_free and value_free around in each item because the
199*fae548d3Szrj      del function has no visibility into the hash as a whole, only into the
200*fae548d3Szrj      individual items.  */
201*fae548d3Szrj 
202*fae548d3Szrj   slot->key_free = hp->key_free;
203*fae548d3Szrj   slot->value_free = hp->value_free;
204*fae548d3Szrj 
205*fae548d3Szrj   return 0;
206*fae548d3Szrj }
207*fae548d3Szrj 
208*fae548d3Szrj void
ctf_dynhash_remove(ctf_dynhash_t * hp,const void * key)209*fae548d3Szrj ctf_dynhash_remove (ctf_dynhash_t *hp, const void *key)
210*fae548d3Szrj {
211*fae548d3Szrj   ctf_helem_t hep = { (void *) key, NULL, NULL, NULL };
212*fae548d3Szrj   htab_remove_elt (hp->htab, &hep);
213*fae548d3Szrj }
214*fae548d3Szrj 
215*fae548d3Szrj void
ctf_dynhash_empty(ctf_dynhash_t * hp)216*fae548d3Szrj ctf_dynhash_empty (ctf_dynhash_t *hp)
217*fae548d3Szrj {
218*fae548d3Szrj   htab_empty (hp->htab);
219*fae548d3Szrj }
220*fae548d3Szrj 
221*fae548d3Szrj void *
ctf_dynhash_lookup(ctf_dynhash_t * hp,const void * key)222*fae548d3Szrj ctf_dynhash_lookup (ctf_dynhash_t *hp, const void *key)
223*fae548d3Szrj {
224*fae548d3Szrj   ctf_helem_t **slot;
225*fae548d3Szrj 
226*fae548d3Szrj   slot = ctf_hashtab_lookup (hp->htab, key, NO_INSERT);
227*fae548d3Szrj 
228*fae548d3Szrj   if (slot)
229*fae548d3Szrj     return (*slot)->value;
230*fae548d3Szrj 
231*fae548d3Szrj   return NULL;
232*fae548d3Szrj }
233*fae548d3Szrj 
234*fae548d3Szrj typedef struct ctf_traverse_cb_arg
235*fae548d3Szrj {
236*fae548d3Szrj   ctf_hash_iter_f fun;
237*fae548d3Szrj   void *arg;
238*fae548d3Szrj } ctf_traverse_cb_arg_t;
239*fae548d3Szrj 
240*fae548d3Szrj static int
ctf_hashtab_traverse(void ** slot,void * arg_)241*fae548d3Szrj ctf_hashtab_traverse (void **slot, void *arg_)
242*fae548d3Szrj {
243*fae548d3Szrj   ctf_helem_t *helem = *((ctf_helem_t **) slot);
244*fae548d3Szrj   ctf_traverse_cb_arg_t *arg = (ctf_traverse_cb_arg_t *) arg_;
245*fae548d3Szrj 
246*fae548d3Szrj   arg->fun (helem->key, helem->value, arg->arg);
247*fae548d3Szrj   return 1;
248*fae548d3Szrj }
249*fae548d3Szrj 
250*fae548d3Szrj void
ctf_dynhash_iter(ctf_dynhash_t * hp,ctf_hash_iter_f fun,void * arg_)251*fae548d3Szrj ctf_dynhash_iter (ctf_dynhash_t *hp, ctf_hash_iter_f fun, void *arg_)
252*fae548d3Szrj {
253*fae548d3Szrj   ctf_traverse_cb_arg_t arg = { fun, arg_ };
254*fae548d3Szrj   htab_traverse (hp->htab, ctf_hashtab_traverse, &arg);
255*fae548d3Szrj }
256*fae548d3Szrj 
257*fae548d3Szrj typedef struct ctf_traverse_remove_cb_arg
258*fae548d3Szrj {
259*fae548d3Szrj   struct htab *htab;
260*fae548d3Szrj   ctf_hash_iter_remove_f fun;
261*fae548d3Szrj   void *arg;
262*fae548d3Szrj } ctf_traverse_remove_cb_arg_t;
263*fae548d3Szrj 
264*fae548d3Szrj static int
ctf_hashtab_traverse_remove(void ** slot,void * arg_)265*fae548d3Szrj ctf_hashtab_traverse_remove (void **slot, void *arg_)
266*fae548d3Szrj {
267*fae548d3Szrj   ctf_helem_t *helem = *((ctf_helem_t **) slot);
268*fae548d3Szrj   ctf_traverse_remove_cb_arg_t *arg = (ctf_traverse_remove_cb_arg_t *) arg_;
269*fae548d3Szrj 
270*fae548d3Szrj   if (arg->fun (helem->key, helem->value, arg->arg))
271*fae548d3Szrj     htab_clear_slot (arg->htab, slot);
272*fae548d3Szrj   return 1;
273*fae548d3Szrj }
274*fae548d3Szrj 
275*fae548d3Szrj void
ctf_dynhash_iter_remove(ctf_dynhash_t * hp,ctf_hash_iter_remove_f fun,void * arg_)276*fae548d3Szrj ctf_dynhash_iter_remove (ctf_dynhash_t *hp, ctf_hash_iter_remove_f fun,
277*fae548d3Szrj                          void *arg_)
278*fae548d3Szrj {
279*fae548d3Szrj   ctf_traverse_remove_cb_arg_t arg = { hp->htab, fun, arg_ };
280*fae548d3Szrj   htab_traverse (hp->htab, ctf_hashtab_traverse_remove, &arg);
281*fae548d3Szrj }
282*fae548d3Szrj 
283*fae548d3Szrj void
ctf_dynhash_destroy(ctf_dynhash_t * hp)284*fae548d3Szrj ctf_dynhash_destroy (ctf_dynhash_t *hp)
285*fae548d3Szrj {
286*fae548d3Szrj   if (hp != NULL)
287*fae548d3Szrj     htab_delete (hp->htab);
288*fae548d3Szrj   free (hp);
289*fae548d3Szrj }
290*fae548d3Szrj 
291*fae548d3Szrj /* ctf_hash, used for fixed-size maps from const char * -> ctf_id_t without
292*fae548d3Szrj    removal.  This is a straight cast of a hashtab.  */
293*fae548d3Szrj 
294*fae548d3Szrj ctf_hash_t *
ctf_hash_create(unsigned long nelems,ctf_hash_fun hash_fun,ctf_hash_eq_fun eq_fun)295*fae548d3Szrj ctf_hash_create (unsigned long nelems, ctf_hash_fun hash_fun,
296*fae548d3Szrj 		 ctf_hash_eq_fun eq_fun)
297*fae548d3Szrj {
298*fae548d3Szrj   return (ctf_hash_t *) htab_create_alloc (nelems, (htab_hash) hash_fun,
299*fae548d3Szrj 					   eq_fun, free, xcalloc, free);
300*fae548d3Szrj }
301*fae548d3Szrj 
302*fae548d3Szrj uint32_t
ctf_hash_size(const ctf_hash_t * hp)303*fae548d3Szrj ctf_hash_size (const ctf_hash_t *hp)
304*fae548d3Szrj {
305*fae548d3Szrj   return htab_elements ((struct htab *) hp);
306*fae548d3Szrj }
307*fae548d3Szrj 
308*fae548d3Szrj int
ctf_hash_insert_type(ctf_hash_t * hp,ctf_file_t * fp,uint32_t type,uint32_t name)309*fae548d3Szrj ctf_hash_insert_type (ctf_hash_t *hp, ctf_file_t *fp, uint32_t type,
310*fae548d3Szrj 		      uint32_t name)
311*fae548d3Szrj {
312*fae548d3Szrj   const char *str = ctf_strraw (fp, name);
313*fae548d3Szrj 
314*fae548d3Szrj   if (type == 0)
315*fae548d3Szrj     return EINVAL;
316*fae548d3Szrj 
317*fae548d3Szrj   if (str == NULL
318*fae548d3Szrj       && CTF_NAME_STID (name) == CTF_STRTAB_1
319*fae548d3Szrj       && fp->ctf_syn_ext_strtab == NULL
320*fae548d3Szrj       && fp->ctf_str[CTF_NAME_STID (name)].cts_strs == NULL)
321*fae548d3Szrj     return ECTF_STRTAB;
322*fae548d3Szrj 
323*fae548d3Szrj   if (str == NULL)
324*fae548d3Szrj     return ECTF_BADNAME;
325*fae548d3Szrj 
326*fae548d3Szrj   if (str[0] == '\0')
327*fae548d3Szrj     return 0;		   /* Just ignore empty strings on behalf of caller.  */
328*fae548d3Szrj 
329*fae548d3Szrj   if (ctf_hashtab_insert ((struct htab *) hp, (char *) str,
330*fae548d3Szrj 			  (void *) (ptrdiff_t) type, NULL, NULL) != NULL)
331*fae548d3Szrj     return 0;
332*fae548d3Szrj   return errno;
333*fae548d3Szrj }
334*fae548d3Szrj 
335*fae548d3Szrj /* if the key is already in the hash, override the previous definition with
336*fae548d3Szrj    this new official definition. If the key is not present, then call
337*fae548d3Szrj    ctf_hash_insert_type() and hash it in.  */
338*fae548d3Szrj int
ctf_hash_define_type(ctf_hash_t * hp,ctf_file_t * fp,uint32_t type,uint32_t name)339*fae548d3Szrj ctf_hash_define_type (ctf_hash_t *hp, ctf_file_t *fp, uint32_t type,
340*fae548d3Szrj                       uint32_t name)
341*fae548d3Szrj {
342*fae548d3Szrj   /* This matches the semantics of ctf_hash_insert_type() in this
343*fae548d3Szrj      implementation anyway.  */
344*fae548d3Szrj 
345*fae548d3Szrj   return ctf_hash_insert_type (hp, fp, type, name);
346*fae548d3Szrj }
347*fae548d3Szrj 
348*fae548d3Szrj ctf_id_t
ctf_hash_lookup_type(ctf_hash_t * hp,ctf_file_t * fp,const char * key)349*fae548d3Szrj ctf_hash_lookup_type (ctf_hash_t *hp, ctf_file_t *fp __attribute__ ((__unused__)),
350*fae548d3Szrj 		      const char *key)
351*fae548d3Szrj {
352*fae548d3Szrj   ctf_helem_t **slot;
353*fae548d3Szrj 
354*fae548d3Szrj   slot = ctf_hashtab_lookup ((struct htab *) hp, key, NO_INSERT);
355*fae548d3Szrj 
356*fae548d3Szrj   if (slot)
357*fae548d3Szrj     return (ctf_id_t) ((*slot)->value);
358*fae548d3Szrj 
359*fae548d3Szrj   return 0;
360*fae548d3Szrj }
361*fae548d3Szrj 
362*fae548d3Szrj void
ctf_hash_destroy(ctf_hash_t * hp)363*fae548d3Szrj ctf_hash_destroy (ctf_hash_t *hp)
364*fae548d3Szrj {
365*fae548d3Szrj   if (hp != NULL)
366*fae548d3Szrj     htab_delete ((struct htab *) hp);
367*fae548d3Szrj }
368