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 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 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 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 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 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 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 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 ** 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 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 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 * 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 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 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 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 * 574*753d2d2eSraf first_list(void) 575*753d2d2eSraf { 576*753d2d2eSraf Bc = 0; 577*753d2d2eSraf return (Buckethead[Bc]); 578*753d2d2eSraf } 579*753d2d2eSraf 580*753d2d2eSraf bucket_t * 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 * 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 * 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 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 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 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 * 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 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 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