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