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