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