xref: /onnv-gate/usr/src/cmd/abi/spectrans/spec2map/bucket.c (revision 2775:892d346f56a9)
1*2775Sraf /*
2*2775Sraf  * CDDL HEADER START
3*2775Sraf  *
4*2775Sraf  * The contents of this file are subject to the terms of the
5*2775Sraf  * Common Development and Distribution License, Version 1.0 only
6*2775Sraf  * (the "License").  You may not use this file except in compliance
7*2775Sraf  * with the License.
8*2775Sraf  *
9*2775Sraf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*2775Sraf  * or http://www.opensolaris.org/os/licensing.
11*2775Sraf  * See the License for the specific language governing permissions
12*2775Sraf  * and limitations under the License.
13*2775Sraf  *
14*2775Sraf  * When distributing Covered Code, include this CDDL HEADER in each
15*2775Sraf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*2775Sraf  * If applicable, add the following below this CDDL HEADER, with the
17*2775Sraf  * fields enclosed by brackets "[]" replaced with your own identifying
18*2775Sraf  * information: Portions Copyright [yyyy] [name of copyright owner]
19*2775Sraf  *
20*2775Sraf  * CDDL HEADER END
21*2775Sraf  */
22*2775Sraf /*
23*2775Sraf  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*2775Sraf  * Use is subject to license terms.
25*2775Sraf  */
26*2775Sraf 
27*2775Sraf #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*2775Sraf 
29*2775Sraf #include <stdio.h>
30*2775Sraf #include <malloc.h>
31*2775Sraf #include <stdlib.h>
32*2775Sraf #include <errno.h>
33*2775Sraf #include <string.h>
34*2775Sraf #include "xlator.h"
35*2775Sraf #include "util.h"
36*2775Sraf #include "bucket.h"
37*2775Sraf #include "errlog.h"
38*2775Sraf 
39*2775Sraf /* Statics: */
40*2775Sraf #define	TRUE	1
41*2775Sraf #define	FALSE	0
42*2775Sraf #define	NLISTS	50
43*2775Sraf #define	NPAR	25
44*2775Sraf 
45*2775Sraf static bucket_t **Buckethead;
46*2775Sraf static int N_lists;
47*2775Sraf 
48*2775Sraf static int Bc = -1; /* For iterators. */
49*2775Sraf static bucket_t *Bp;
50*2775Sraf 
51*2775Sraf static void start_new_list(const bucket_t *);
52*2775Sraf static void grow_lists(void);
53*2775Sraf static bucket_t *new_bucket(const char *, int);
54*2775Sraf static void print_iface(const Interface *);
55*2775Sraf static void new_hashmap(void);
56*2775Sraf static int add_to_hashmap(const char *, const bucket_t *);
57*2775Sraf static bucket_t *find_in_hashmap(const char *);
58*2775Sraf /*
59*2775Sraf  * initialization interfaces.
60*2775Sraf  */
61*2775Sraf 
62*2775Sraf /*
63*2775Sraf  * create_lists -- initialize the bucket list and hash map.
64*2775Sraf  */
65*2775Sraf void
create_lists(void)66*2775Sraf create_lists(void)
67*2775Sraf {
68*2775Sraf 
69*2775Sraf 	errlog(BEGIN, "create_lists() {");
70*2775Sraf 	new_hashmap();
71*2775Sraf 	if ((Buckethead = calloc(sizeof (bucket_t *), NLISTS)) == NULL) {
72*2775Sraf 		errlog(FATAL, "out of memory creating initial "
73*2775Sraf 			"list of versions");
74*2775Sraf 
75*2775Sraf 	}
76*2775Sraf 	N_lists = NLISTS;
77*2775Sraf 	errlog(END, "}");
78*2775Sraf }
79*2775Sraf 
80*2775Sraf 
81*2775Sraf /*
82*2775Sraf  * data-loading interfaces -- adding buckets to lists and
83*2775Sraf  *	interfaces to buckets.
84*2775Sraf  */
85*2775Sraf 
86*2775Sraf /*
87*2775Sraf  * add_parent -- add a parent node. Returns TRUE or FALSE.
88*2775Sraf  *
89*2775Sraf  * 	if *version == NULL, then
90*2775Sraf  * 		the bucket version (eg, SUNW_1.1) hasn't
91*2775Sraf  * 		been parsed correctly.  Die.
92*2775Sraf  * 	if *after == NULL, then this is the ``initial case'',
93*2775Sraf  * 		where no predecessor (child) exists.  We start a new
94*2775Sraf  * 		tree of buckets.
95*2775Sraf  * 	if *after != NULL, we have the normal case, and
96*2775Sraf  * 		add to an existing tree.
97*2775Sraf  * 	if *after is not a version name found among the buckets,
98*2775Sraf  * 		then something got misparsed or the versions file is
99*2775Sraf  * 		malformed. Function will print problem and
100*2775Sraf  * 		return 0 so caller can report location of error.
101*2775Sraf  *      If either version or after is NULL, it's a programmer error.
102*2775Sraf  */
103*2775Sraf int
add_parent(const char * version,const char * after,int weak)104*2775Sraf add_parent(const char *version, const char *after, int weak)
105*2775Sraf {
106*2775Sraf 	bucket_t *new, *child;
107*2775Sraf 
108*2775Sraf 	/* Sanity-check parameters. */
109*2775Sraf 	assert(version != NULL, "passed a null version to add_parent");
110*2775Sraf 	assert(after != NULL, "passed a null after to add_parent");
111*2775Sraf 	errlog(BEGIN, "add_parent(%s,%s,%d) {", version, after, weak);
112*2775Sraf 	if ((new = find_in_hashmap(version)) == NULL) {
113*2775Sraf 		/* We don't have one have one yet. */
114*2775Sraf 		new = new_bucket(version, weak);
115*2775Sraf 	}
116*2775Sraf 	new->b_weak = weak;
117*2775Sraf 	if (*after == '\0') {
118*2775Sraf 		/*
119*2775Sraf 		 * This is the ``initial case'', where no
120*2775Sraf 		 * child exists.  We start a new tree of buckets.
121*2775Sraf 		 */
122*2775Sraf 		(void) add_to_hashmap(version, new);
123*2775Sraf 		start_new_list(new);
124*2775Sraf 	} else {
125*2775Sraf 		if ((child = find_in_hashmap(after)) == NULL) {
126*2775Sraf 			/*
127*2775Sraf 			 * The version in the spec doesn't appear in the
128*2775Sraf 			 * versions file.  One or the other is lying.
129*2775Sraf 			 */
130*2775Sraf 			errlog(WARNING, "set file: can't find version \"%s\","
131*2775Sraf 			    "therefor can't add it's parent, \"%s\"",
132*2775Sraf 			    after, version);
133*2775Sraf 			errlog(END, "} /* add_parent */");
134*2775Sraf 			return (FALSE);
135*2775Sraf 		}
136*2775Sraf 		(void) add_to_hashmap(version, new);
137*2775Sraf 		child->b_parent = new;
138*2775Sraf 	}
139*2775Sraf 	errlog(END, "} /* add_parent */");
140*2775Sraf 	return (TRUE);
141*2775Sraf }
142*2775Sraf 
143*2775Sraf /*
144*2775Sraf  * add_uncle -- adds an uncle node
145*2775Sraf  */
146*2775Sraf int
add_uncle(const char * version,const char * after,int weak)147*2775Sraf add_uncle(const char *version, const char *after, int weak)
148*2775Sraf {
149*2775Sraf 	bucket_t *new, *child;
150*2775Sraf 	struct bucketlist *uncle;
151*2775Sraf 
152*2775Sraf 	/* Sanity-check parameters. */
153*2775Sraf 	assert(version != NULL, "passed a null version to add_uncle");
154*2775Sraf 	assert(after != NULL, "passed a null after to add_uncle");
155*2775Sraf 	errlog(BEGIN, "add_uncle(%s,%s,%d) {", version, after, weak);
156*2775Sraf 	if ((new = find_in_hashmap(version)) == NULL) {
157*2775Sraf 		/* We don't have one have one yet. */
158*2775Sraf 		new = new_bucket(version, weak);
159*2775Sraf 	}
160*2775Sraf 	if (*after == '\0') {
161*2775Sraf 		/*
162*2775Sraf 		 * This is the ``initial case'', where no
163*2775Sraf 		 * child exists.  We start a new tree of buckets.
164*2775Sraf 		 */
165*2775Sraf 		(void) add_to_hashmap(version, new);
166*2775Sraf 		start_new_list(new);
167*2775Sraf 	} else {
168*2775Sraf 		if ((child = find_in_hashmap(after)) == NULL) {
169*2775Sraf 			/*
170*2775Sraf 			 * The version in the spec doesn't appear in the
171*2775Sraf 			 * versions file.  One or the other is lying.
172*2775Sraf 			 */
173*2775Sraf 			errlog(WARNING, "set file: can't find version \"%s\","
174*2775Sraf 			    "therefor can't add it's uncle, \"%s\"",
175*2775Sraf 			    after, version);
176*2775Sraf 			errlog(END, "}");
177*2775Sraf 			return (FALSE);
178*2775Sraf 		}
179*2775Sraf 		(void) add_to_hashmap(version, new);
180*2775Sraf 		uncle =	malloc(sizeof (struct bucketlist));
181*2775Sraf 		uncle->bl_next = child->b_uncles;
182*2775Sraf 		uncle->bl_bucket = new;
183*2775Sraf 		child->b_uncles = uncle;
184*2775Sraf 	}
185*2775Sraf 	errlog(END, "}");
186*2775Sraf 	return (TRUE);
187*2775Sraf }
188*2775Sraf 
189*2775Sraf /*
190*2775Sraf  * set_weak -- set a version to be a weak version
191*2775Sraf  */
192*2775Sraf void
set_weak(const char * version,int weak)193*2775Sraf set_weak(const char *version, int weak)
194*2775Sraf {
195*2775Sraf 	bucket_t *v;
196*2775Sraf 	if ((v = find_in_hashmap(version)) == NULL) {
197*2775Sraf 		/* We don't have one have one yet. */
198*2775Sraf 		errlog(ERROR|FATAL, "Unable to set weak. Version not found");
199*2775Sraf 	}
200*2775Sraf 	v->b_weak = weak;
201*2775Sraf }
202*2775Sraf 
203*2775Sraf /*
204*2775Sraf  * add_by_name -- look up bucket and add an interface to it.
205*2775Sraf  *      Returns 0 for success or an errno.h value for failure.
206*2775Sraf  *
207*2775Sraf  * 	if *version is not among the buckets, then the
208*2775Sraf  * 		version in the spec doesn't appear in the
209*2775Sraf  * 		set file.  One or the other is lying. Function will
210*2775Sraf  * 		report the problem and return ENOENT
211*2775Sraf  * 		so the front end can report and exit (or
212*2775Sraf  * 		continue if it wants).
213*2775Sraf  * 	if interface ore version is NULL, then
214*2775Sraf  * 		the begin line code should
215*2775Sraf  * 		have caught it long before, to avoid passing
216*2775Sraf  * 		a null pointer around. Die.
217*2775Sraf  *
218*2775Sraf  */
219*2775Sraf #define	ADD_EQUALS(str)	if (strchr(str, '=') == NULL) (void) strcat(str, " =")
220*2775Sraf 
221*2775Sraf int
add_by_name(const char * version,const Interface * interface)222*2775Sraf add_by_name(const char *version, const Interface *interface)
223*2775Sraf {
224*2775Sraf 	bucket_t *b;
225*2775Sraf 	char buffer[1024];
226*2775Sraf 
227*2775Sraf 	assert(version != NULL, "passed a null version to add_by_name");
228*2775Sraf 	assert(interface != NULL, "passed a null interface to add_by_name");
229*2775Sraf 
230*2775Sraf 	errlog(BEGIN, "add_by_name(%s,", version);
231*2775Sraf 	print_iface(interface);
232*2775Sraf 	errlog(TRACING, ");");
233*2775Sraf 
234*2775Sraf 	/* Sanity-check the parameters. */
235*2775Sraf 	if ((b = find_in_hashmap(version)) == NULL) {
236*2775Sraf 		/*
237*2775Sraf 		 * The version in the spec doesn't appear in the
238*2775Sraf 		 * versions file. Alas, this isn't an error.  It can
239*2775Sraf 		 * happen whenever doing just sparc, just i386
240*2775Sraf 		 * or the like.
241*2775Sraf 		 */
242*2775Sraf 		errlog(END, "}");
243*2775Sraf 		return (ENOENT);
244*2775Sraf 	}
245*2775Sraf 	/*
246*2775Sraf 	 * Add to bucket.
247*2775Sraf 	 */
248*2775Sraf 	(void) snprintf(buffer, sizeof (buffer), "%s", interface->IF_name);
249*2775Sraf 
250*2775Sraf 	if (interface->IF_filter && interface->IF_auxiliary) {
251*2775Sraf 		errlog(FATAL, "Error: cannot set both FILTER and AUXILIARY "
252*2775Sraf 		    "for an interface: %s", interface->IF_name);
253*2775Sraf 	}
254*2775Sraf 
255*2775Sraf 	if (interface->IF_filter) {
256*2775Sraf 		ADD_EQUALS(buffer);
257*2775Sraf 		if (interface->IF_type == FUNCTION) {
258*2775Sraf 			(void) strcat(buffer, " FUNCTION");
259*2775Sraf 		} else if (interface->IF_type == DATA) {
260*2775Sraf 			(void) strcat(buffer, " DATA");
261*2775Sraf 		}
262*2775Sraf 		(void) strcat(buffer, " FILTER ");
263*2775Sraf 		(void) strcat(buffer, interface->IF_filter);
264*2775Sraf 	} else if (interface->IF_auxiliary) {
265*2775Sraf 		ADD_EQUALS(buffer);
266*2775Sraf 		(void) strcat(buffer, " AUXILIARY ");
267*2775Sraf 		(void) strcat(buffer, interface->IF_auxiliary);
268*2775Sraf 	} else if (IsFilterLib) {
269*2775Sraf 		/*
270*2775Sraf 		 * For DATA types it is currently assumed that they are
271*2775Sraf 		 * handled via a minimal C file, e.g. 'data.c', in the
272*2775Sraf 		 * library's build.  Hence, we do not append '= DATA' here.
273*2775Sraf 		 */
274*2775Sraf 		if (interface->IF_type == FUNCTION) {
275*2775Sraf 			ADD_EQUALS(buffer);
276*2775Sraf 			(void) strcat(buffer, " FUNCTION");
277*2775Sraf 		}
278*2775Sraf 	}
279*2775Sraf 
280*2775Sraf 	switch (interface->IF_binding) {
281*2775Sraf 	case DIRECT:
282*2775Sraf 		ADD_EQUALS(buffer);
283*2775Sraf 		(void) strcat(buffer, " DIRECT");
284*2775Sraf 		break;
285*2775Sraf 	case NODIRECT:
286*2775Sraf 		ADD_EQUALS(buffer);
287*2775Sraf 		(void) strcat(buffer, " NODIRECT");
288*2775Sraf 		break;
289*2775Sraf 	}
290*2775Sraf 
291*2775Sraf 	if (interface->IF_binding == PROTECTED) {
292*2775Sraf 		/* Assign in case of realloc. */
293*2775Sraf 		b->b_protected_table =
294*2775Sraf 		    add_to_stringtable(b->b_protected_table, buffer);
295*2775Sraf 		b->b_has_protecteds = 1;
296*2775Sraf 		errlog(VERBOSE, "set has_protecteds on bucket 0x%p", b);
297*2775Sraf 	} else {
298*2775Sraf 		/* Assign in case of realloc. */
299*2775Sraf 		b->b_global_table = add_to_stringtable(b->b_global_table,
300*2775Sraf 			buffer);
301*2775Sraf 	}
302*2775Sraf 	errlog(END, "}");
303*2775Sraf 	return (0);
304*2775Sraf }
305*2775Sraf 
306*2775Sraf 
307*2775Sraf /*
308*2775Sraf  * Processing interfaces
309*2775Sraf  */
310*2775Sraf 
311*2775Sraf /*
312*2775Sraf  * sort_buckets -- sort the interfaces within the buckets into
313*2775Sraf  *      alphabetical order.
314*2775Sraf  */
315*2775Sraf void
sort_buckets(void)316*2775Sraf sort_buckets(void)
317*2775Sraf {
318*2775Sraf 	bucket_t *l, *b;
319*2775Sraf 
320*2775Sraf 	errlog(BEGIN, "sort_buckets() {");
321*2775Sraf 	for (l = first_list(); l != NULL; l = next_list()) {
322*2775Sraf 		errlog(VERBOSE, "l-bucket: %s", l->b_name);
323*2775Sraf 		for (b = first_from_list(l); b != NULL; b = next_from_list()) {
324*2775Sraf 			errlog(VERBOSE, "   b-bkt: %s", b->b_name);
325*2775Sraf 			sort_stringtable(b->b_global_table);
326*2775Sraf 			sort_stringtable(b->b_protected_table);
327*2775Sraf 			if (b->b_uncles) {
328*2775Sraf 
329*2775Sraf 				if (b->b_uncles->bl_bucket) {
330*2775Sraf 		sort_stringtable(b->b_uncles->bl_bucket->b_global_table);
331*2775Sraf 		sort_stringtable(b->b_uncles->bl_bucket->b_protected_table);
332*2775Sraf 				}
333*2775Sraf 			}
334*2775Sraf 		}
335*2775Sraf 	}
336*2775Sraf 	errlog(END, "}");
337*2775Sraf }
338*2775Sraf 
339*2775Sraf 
340*2775Sraf /*
341*2775Sraf  * add_local -- set the local flag on the logically first bucket.
342*2775Sraf  *     This decision may belong in the caller, as it is about
343*2775Sraf  *     mapfiles, not inherent ordering or bucket contents...
344*2775Sraf  */
345*2775Sraf void
add_local(void)346*2775Sraf add_local(void)
347*2775Sraf {
348*2775Sraf 	bucket_t *b, *list;
349*2775Sraf 	int	done = 0;
350*2775Sraf 
351*2775Sraf 	errlog(BEGIN, "add_local() {");
352*2775Sraf 	/* Iterate across lists of buckets */
353*2775Sraf 	for (list = first_list(); list != NULL; list = next_list()) {
354*2775Sraf 		/* Traverse the list found. */
355*2775Sraf 		for (b = list; b != NULL; b = b->b_parent) {
356*2775Sraf 			if (b->b_weak != 1) {
357*2775Sraf 				/* We've found the first non-weak. */
358*2775Sraf 				b->b_has_locals = done = 1;
359*2775Sraf 				errlog(VERBOSE,
360*2775Sraf 				    "set has_locals on bucket 0x%p", b);
361*2775Sraf 				break;
362*2775Sraf 			}
363*2775Sraf 		}
364*2775Sraf 		if (b != NULL && b->b_has_locals == 1)
365*2775Sraf 			break;
366*2775Sraf 	}
367*2775Sraf 	if (done == 0) {
368*2775Sraf 		errlog(WARNING, "has_locals never set");
369*2775Sraf 	}
370*2775Sraf 	errlog(END, "}");
371*2775Sraf }
372*2775Sraf 
373*2775Sraf 
374*2775Sraf /*
375*2775Sraf  * Output interfaces, mostly iterators
376*2775Sraf  */
377*2775Sraf 
378*2775Sraf 
379*2775Sraf /*
380*2775Sraf  * parents_of -- return a list of all parents.
381*2775Sraf  */
382*2775Sraf char **
parents_of(const bucket_t * start)383*2775Sraf parents_of(const bucket_t *start)
384*2775Sraf {
385*2775Sraf 	static char *a[NPAR] = {NULL};
386*2775Sraf 	const bucket_t *b = start;
387*2775Sraf 	char **p = &a[0];
388*2775Sraf 
389*2775Sraf 	assert(start != NULL, "passed a null start to parents_of");
390*2775Sraf 	errlog(BEGIN, "parents_of() {");
391*2775Sraf 	a[0] = '\0';
392*2775Sraf 
393*2775Sraf 	/* Go to parent, print it and all its uncle. */
394*2775Sraf 	if (b->b_parent == NULL) {
395*2775Sraf 		errlog(TRACING, "returning empty string");
396*2775Sraf 		errlog(END, "}");
397*2775Sraf 		return (a);
398*2775Sraf 	}
399*2775Sraf 	b = b->b_parent;
400*2775Sraf 	*p++ = b->b_name;
401*2775Sraf 	*p = '\0';
402*2775Sraf 
403*2775Sraf 	assert(p < &a[NPAR], "p fell off the end of a in parents_of");
404*2775Sraf 	errlog(END, "}");
405*2775Sraf 	return (a);
406*2775Sraf }
407*2775Sraf 
408*2775Sraf /*
409*2775Sraf  * first, next_from_bucket --iterators for bucket contents. Serially
410*2775Sraf  *      reusable only.
411*2775Sraf  */
412*2775Sraf int Ic = -1;
413*2775Sraf 
414*2775Sraf /*
415*2775Sraf  * debugging interfaces
416*2775Sraf  */
417*2775Sraf void
print_bucket(const bucket_t * b)418*2775Sraf print_bucket(const bucket_t *b)
419*2775Sraf {
420*2775Sraf 
421*2775Sraf 	errlog(TRACING, "bucket_t at 0x%p {", (void *)b);
422*2775Sraf 	errlog(TRACING, "    char   *b_name = \"%s\";", b->b_name);
423*2775Sraf 	errlog(TRACING, "    struct bucket_t *b_parent = 0x%p;",
424*2775Sraf 		(void *)b->b_parent);
425*2775Sraf 	errlog(TRACING, "    struct bucketlist *b_uncles = 0x%p;",
426*2775Sraf 		(void *)b->b_uncles);
427*2775Sraf 	errlog(TRACING, "    struct bucket_t *b_thread = 0x%p;",
428*2775Sraf 		(void *)b->b_thread);
429*2775Sraf 	errlog(TRACING, "    int	b_has_locals = %d;",
430*2775Sraf 		b->b_has_locals);
431*2775Sraf 	errlog(TRACING, "    int	b_has_protecteds = %d;",
432*2775Sraf 		b->b_has_protecteds);
433*2775Sraf 	errlog(TRACING, "    int        b_was_printed = %d;",
434*2775Sraf 		b->b_was_printed);
435*2775Sraf 	errlog(TRACING, "    int        b_weak = %d;",
436*2775Sraf 		b->b_weak);
437*2775Sraf 	errlog(TRACING, "    table_t  *b_global_table = 0x%p;",
438*2775Sraf 		(void *)b->b_global_table);
439*2775Sraf 	errlog(TRACING, "    table_t  *b_protected_table = 0x%p;",
440*2775Sraf 		(void *)b->b_protected_table);
441*2775Sraf 	errlog(TRACING, "}");
442*2775Sraf }
443*2775Sraf 
444*2775Sraf void
print_all_buckets(void)445*2775Sraf print_all_buckets(void)
446*2775Sraf {
447*2775Sraf 	bucket_t *l, *b;
448*2775Sraf 	int i = 0, j = 0;
449*2775Sraf 	char **p;
450*2775Sraf 
451*2775Sraf 	for (i = 0, l = first_list(); l != NULL; l = next_list(), ++i) {
452*2775Sraf 		errlog(TRACING, "list %d", i);
453*2775Sraf 		for (j = 0, b = first_from_list(l);
454*2775Sraf 		    b != NULL; b = next_from_list(), ++j) {
455*2775Sraf 			errlog(TRACING, "bucket %d", j);
456*2775Sraf 			print_bucket(b);
457*2775Sraf 			errlog(TRACING, "global interfaces = {");
458*2775Sraf 			print_stringtable(b->b_global_table);
459*2775Sraf 			errlog(TRACING, "}");
460*2775Sraf 			errlog(TRACING, "protected interfaces = {");
461*2775Sraf 			print_stringtable(b->b_protected_table);
462*2775Sraf 			errlog(TRACING, "}");
463*2775Sraf 
464*2775Sraf 			for (p = parents_of(b); p != NULL && *p != NULL; ++p) {
465*2775Sraf 				errlog(TRACING, " %s", *p);
466*2775Sraf 			}
467*2775Sraf 			errlog(TRACING, ";");
468*2775Sraf 
469*2775Sraf 			if (b->b_uncles) {
470*2775Sraf 				errlog(TRACING, " uncle bucket %d.1", j);
471*2775Sraf 				print_bucket(b->b_uncles->bl_bucket);
472*2775Sraf 				errlog(TRACING, "global interfaces = {");
473*2775Sraf 				print_stringtable(
474*2775Sraf 				    b->b_uncles->bl_bucket->b_global_table);
475*2775Sraf 				errlog(TRACING, "}");
476*2775Sraf 				errlog(TRACING, "protected interfaces = {");
477*2775Sraf 				print_stringtable(
478*2775Sraf 				    b->b_uncles->bl_bucket->b_protected_table);
479*2775Sraf 				errlog(TRACING, "}");
480*2775Sraf 			}
481*2775Sraf 		}
482*2775Sraf 	}
483*2775Sraf }
484*2775Sraf 
485*2775Sraf 
486*2775Sraf /*
487*2775Sraf  * lower-level functions, not visible outside the file.
488*2775Sraf  */
489*2775Sraf 
490*2775Sraf /*
491*2775Sraf  * new_bucket -- create a bucket for a given version. Must not fail.
492*2775Sraf  */
493*2775Sraf static bucket_t *
new_bucket(const char * name,int weak)494*2775Sraf new_bucket(const char *name, int weak)
495*2775Sraf {
496*2775Sraf 	bucket_t *b;
497*2775Sraf 
498*2775Sraf 	if ((b = (bucket_t *)calloc(1, sizeof (bucket_t))) == NULL) {
499*2775Sraf 		errlog(FATAL, "out of memory creating a bucket "
500*2775Sraf 			"to store interfaces in");
501*2775Sraf 	}
502*2775Sraf 	if ((b->b_name = strdup(name)) == NULL) {
503*2775Sraf 		errlog(FATAL, "out of memory storing an interface "
504*2775Sraf 			"in a version bucket");
505*2775Sraf 	}
506*2775Sraf 	b->b_uncles = NULL;
507*2775Sraf 	b->b_global_table = create_stringtable(TABLE_INITIAL);
508*2775Sraf 	b->b_protected_table = create_stringtable(TABLE_INITIAL);
509*2775Sraf 	b->b_weak = weak;
510*2775Sraf 	return (b);
511*2775Sraf }
512*2775Sraf 
513*2775Sraf 
514*2775Sraf /*
515*2775Sraf  * start_new_list -- start a list of buckets.
516*2775Sraf  */
517*2775Sraf static void
start_new_list(const bucket_t * b)518*2775Sraf start_new_list(const bucket_t *b)
519*2775Sraf {
520*2775Sraf 	int i;
521*2775Sraf 
522*2775Sraf 	errlog(BEGIN, "start_new_list() {");
523*2775Sraf 	assert(Buckethead != NULL, "Buckethead null in start_new_list");
524*2775Sraf 	for (i = 0; Buckethead[i] != NULL && i < N_lists; ++i)
525*2775Sraf 		continue;
526*2775Sraf 	if (i >= N_lists) {
527*2775Sraf 		grow_lists();
528*2775Sraf 	}
529*2775Sraf 	Buckethead[i] = (bucket_t *)b;
530*2775Sraf 	errlog(END, "}");
531*2775Sraf }
532*2775Sraf 
533*2775Sraf /*
534*2775Sraf  * grow_list -- make more lists.  This should never occur...
535*2775Sraf  */
536*2775Sraf static void
grow_lists(void)537*2775Sraf grow_lists(void)
538*2775Sraf {
539*2775Sraf 	int i = N_lists;
540*2775Sraf 
541*2775Sraf 	errlog(BEGIN, "grow_lists() {");
542*2775Sraf 	errlog(WARNING, "Warning: more than %d version lists "
543*2775Sraf 	    "required (< %d is normal). Check sets file "
544*2775Sraf 	    "to see why so many lines appear.",
545*2775Sraf 	    N_lists, NLISTS);
546*2775Sraf 
547*2775Sraf 	N_lists *= 2;
548*2775Sraf 	if ((Buckethead = realloc(Buckethead, sizeof (bucket_t *) * N_lists))
549*2775Sraf 		== NULL) {
550*2775Sraf 		errlog(FATAL, "out of memory growing list of "
551*2775Sraf 			"version buckets");
552*2775Sraf 	}
553*2775Sraf 	for (; i < N_lists; ++i) {
554*2775Sraf 		Buckethead[i] = NULL;
555*2775Sraf 	}
556*2775Sraf }
557*2775Sraf 
558*2775Sraf /*
559*2775Sraf  * delete_lists -- clean up afterwards.
560*2775Sraf  */
561*2775Sraf void
delete_lists(void)562*2775Sraf delete_lists(void)
563*2775Sraf {
564*2775Sraf 	N_lists = 0;
565*2775Sraf 	free(Buckethead);
566*2775Sraf 	Buckethead = 0;
567*2775Sraf }
568*2775Sraf 
569*2775Sraf /*
570*2775Sraf  * first_list, next_list -- an iterator for lists themselves.  Serially
571*2775Sraf  *      reusable only.
572*2775Sraf  */
573*2775Sraf bucket_t *
first_list(void)574*2775Sraf first_list(void)
575*2775Sraf {
576*2775Sraf 	Bc = 0;
577*2775Sraf 	return (Buckethead[Bc]);
578*2775Sraf }
579*2775Sraf 
580*2775Sraf bucket_t *
next_list(void)581*2775Sraf next_list(void)
582*2775Sraf {
583*2775Sraf 	return (Buckethead[++Bc]);
584*2775Sraf }
585*2775Sraf 
586*2775Sraf 
587*2775Sraf /*
588*2775Sraf  * first, next, last_from_list -- iterators for individual lists. Serially
589*2775Sraf  *      reusable only.
590*2775Sraf  */
591*2775Sraf bucket_t *
first_from_list(const bucket_t * l)592*2775Sraf first_from_list(const bucket_t *l)
593*2775Sraf {
594*2775Sraf 	return (Bp = (bucket_t *)l);
595*2775Sraf }
596*2775Sraf 
597*2775Sraf bucket_t *
next_from_list(void)598*2775Sraf next_from_list(void)
599*2775Sraf {
600*2775Sraf 	return (Bp = Bp->b_parent);
601*2775Sraf }
602*2775Sraf 
603*2775Sraf 
604*2775Sraf 
605*2775Sraf /*
606*2775Sraf  * Iface print utility
607*2775Sraf  */
608*2775Sraf static void
print_iface(const Interface * p)609*2775Sraf print_iface(const Interface * p)
610*2775Sraf {
611*2775Sraf 
612*2775Sraf 	errlog(TRACING, "%s (%s, %s, %s %d)", p->IF_name,
613*2775Sraf 		(p->IF_type == FUNCTION) ? "function" :
614*2775Sraf 		(p->IF_type == DATA) ? "data" : "unknown type",
615*2775Sraf 		(p->IF_version) ? p->IF_version : "unknown version",
616*2775Sraf 		(p->IF_class) ? p->IF_class : "unknown class",
617*2775Sraf 		p->IF_binding);
618*2775Sraf }
619*2775Sraf 
620*2775Sraf 
621*2775Sraf 
622*2775Sraf #define	HASHMAPSIZE	100
623*2775Sraf #define	ERR	(-1)
624*2775Sraf 
625*2775Sraf static struct {
626*2775Sraf 	hashmap_t *hh_map;
627*2775Sraf 	int hh_map_size;
628*2775Sraf 	int hh_mapC;
629*2775Sraf 	hashmap_t *hh_last;
630*2775Sraf } Hashhead = {
631*2775Sraf 	NULL, -1, -1, NULL
632*2775Sraf };
633*2775Sraf 
634*2775Sraf static int checksum(const char *);
635*2775Sraf static void print_hashmap(const hashmap_t *);
636*2775Sraf 
637*2775Sraf /*
638*2775Sraf  * new_hashmap -- create the hash.
639*2775Sraf  */
640*2775Sraf static void
new_hashmap(void)641*2775Sraf new_hashmap(void)
642*2775Sraf {
643*2775Sraf 
644*2775Sraf 	errlog(BEGIN, "new_hashmap() {");
645*2775Sraf 	if ((Hashhead.hh_map = calloc(sizeof (hashmap_t), HASHMAPSIZE))
646*2775Sraf 	    == NULL) {
647*2775Sraf 		errlog(FATAL, "out of memory creating a hash-map of "
648*2775Sraf 			"the versions");
649*2775Sraf 	}
650*2775Sraf 	Hashhead.hh_mapC = 0;
651*2775Sraf 	errlog(END, "}");
652*2775Sraf }
653*2775Sraf 
654*2775Sraf /*
655*2775Sraf  * add_to_hashmap -- add a bucket to the map.  This is strictly for
656*2775Sraf  *	use by add_parent()/add_uncle().
657*2775Sraf  */
658*2775Sraf static int
add_to_hashmap(const char * version_name,const bucket_t * bucket)659*2775Sraf add_to_hashmap(const char *version_name, const bucket_t *bucket)
660*2775Sraf {
661*2775Sraf 	hashmap_t *p;
662*2775Sraf 
663*2775Sraf 	assert(Hashhead.hh_map != NULL,
664*2775Sraf 	    "Hashead.map was null in add_to_hashmap");
665*2775Sraf 	assert(Hashhead.hh_mapC < HASHMAPSIZE,
666*2775Sraf 	    "mapC too big in add_to_hashmap");
667*2775Sraf 	errlog(BEGIN, "add_to_hashmap(%s, %s) {", version_name, bucket);
668*2775Sraf 	if (find_in_hashmap(version_name) != NULL) {
669*2775Sraf 		/* Seen for the second time. TBD... */
670*2775Sraf 		errlog(END, "} /* add_to_hashmap */");
671*2775Sraf 		return (ERR);
672*2775Sraf 	}
673*2775Sraf 	p = &Hashhead.hh_map[Hashhead.hh_mapC++];
674*2775Sraf 	if ((p->h_version_name = strdup(version_name)) == NULL) {
675*2775Sraf 		errlog(FATAL, "out of memory storing a version name");
676*2775Sraf 
677*2775Sraf 	}
678*2775Sraf 	p->h_bucket = (bucket_t *)bucket;
679*2775Sraf 	p->h_hash = checksum(version_name);
680*2775Sraf 	Hashhead.hh_last = p;
681*2775Sraf 	print_hashmap(p);
682*2775Sraf 	errlog(END, "} /* add_to_hashmap */");
683*2775Sraf 	return (0);
684*2775Sraf }
685*2775Sraf 
686*2775Sraf 
687*2775Sraf /*
688*2775Sraf  * find_in_hashmap -- find a bucket by name.  Strictly for use by addByName().
689*2775Sraf  */
690*2775Sraf static bucket_t *
find_in_hashmap(const char * version_name)691*2775Sraf find_in_hashmap(const char *version_name)
692*2775Sraf {
693*2775Sraf 	hashmap_t *current;
694*2775Sraf 	int hash = checksum(version_name);
695*2775Sraf 
696*2775Sraf 	assert(Hashhead.hh_map != NULL,
697*2775Sraf 		"Hashhead.hh_map was null in find_in_hashmap");
698*2775Sraf 	errlog(BEGIN, "find_in_hashmap(%s) {", version_name);
699*2775Sraf 	if (Hashhead.hh_last != NULL && Hashhead.hh_last->h_hash == hash &&
700*2775Sraf 	    strcmp(Hashhead.hh_last->h_version_name, version_name) == 0) {
701*2775Sraf 		errlog(END, "}");
702*2775Sraf 		return (Hashhead.hh_last->h_bucket);
703*2775Sraf 	}
704*2775Sraf 	for (current = Hashhead.hh_map;
705*2775Sraf 		current->h_version_name != NULL; ++current) {
706*2775Sraf 		if (current->h_hash == hash &&
707*2775Sraf 			strcmp(current->h_version_name, version_name) == 0) {
708*2775Sraf 			/* Found it */
709*2775Sraf 			Hashhead.hh_last = current;
710*2775Sraf 			errlog(END, "}");
711*2775Sraf 			return (current->h_bucket);
712*2775Sraf 		}
713*2775Sraf 	}
714*2775Sraf 	/* Doesn't exist, meaning version name is bogus. */
715*2775Sraf 	errlog(END, "}");
716*2775Sraf 	return (NULL);
717*2775Sraf }
718*2775Sraf 
719*2775Sraf /*
720*2775Sraf  * checksum -- from sum(1), algorithm 1.
721*2775Sraf  */
722*2775Sraf static int
checksum(const char * p)723*2775Sraf checksum(const char *p)
724*2775Sraf {
725*2775Sraf 	int sum;
726*2775Sraf 
727*2775Sraf 	for (sum = 0; *p != NULL; ++p) {
728*2775Sraf 		if (sum & 01)
729*2775Sraf 			sum = (sum >> 1) + 0x8000;
730*2775Sraf 		else
731*2775Sraf 			sum >>= 1;
732*2775Sraf 		sum += *p;
733*2775Sraf 		sum &= 0xFFFF;
734*2775Sraf 	}
735*2775Sraf 	return (sum);
736*2775Sraf }
737*2775Sraf 
738*2775Sraf static void
print_hashmap(const hashmap_t * h)739*2775Sraf print_hashmap(const hashmap_t *h)
740*2775Sraf {
741*2775Sraf 	errlog(VERBOSE, "struct hashmap_t at 0x4.4x {", h);
742*2775Sraf 	errlog(VERBOSE, "    int    h_hash = %d;", h->h_hash);
743*2775Sraf 	errlog(VERBOSE, "    char   *h_version_name = \"%s\";",
744*2775Sraf 		h->h_version_name);
745*2775Sraf 	errlog(VERBOSE, "    bucket_t *h_bucket = 0x%p;;",
746*2775Sraf 		(void *) h->h_bucket);
747*2775Sraf 	errlog(VERBOSE, "}");
748*2775Sraf }
749