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