Path: blob/main/cddl/contrib/opensolaris/tools/ctf/cvt/tdata.c
39586 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License (the "License").5* You may not use this file except in compliance with the License.6*7* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE8* or http://www.opensolaris.org/os/licensing.9* See the License for the specific language governing permissions10* and limitations under the License.11*12* When distributing Covered Code, include this CDDL HEADER in each13* file and include the License file at usr/src/OPENSOLARIS.LICENSE.14* If applicable, add the following below this CDDL HEADER, with the15* fields enclosed by brackets "[]" replaced with your own identifying16* information: Portions Copyright [yyyy] [name of copyright owner]17*18* CDDL HEADER END19*/20/*21* Copyright 2010 Sun Microsystems, Inc. All rights reserved.22* Use is subject to license terms.23*/2425/*26* Routines for manipulating tdesc and tdata structures27*/2829#include <stdio.h>30#include <stdlib.h>31#include <strings.h>32#include <pthread.h>3334#include "ctftools.h"35#include "memory.h"36#include "traverse.h"3738/*39* The layout hash is used during the equivalency checking. We have a node in40* the child graph that may be equivalent to a node in the parent graph. To41* find the corresponding node (if any) in the parent, we need a quick way to42* get to all nodes in the parent that look like the node in the child. Since a43* large number of nodes don't have names, we need to incorporate the layout of44* the node into the hash. If we don't, we'll end up with the vast majority of45* nodes in bucket zero, with one or two nodes in each of the remaining buckets.46*47* There are a couple of constraints, both of which concern forward48* declarations. Recall that a forward declaration tdesc is equivalent to a49* tdesc that actually defines the structure or union. As such, we cannot50* incorporate anything into the hash for a named struct or union node that51* couldn't be found by looking at the forward, and vice versa.52*/53int54tdesc_layouthash(int nbuckets, void *node)55{56tdesc_t *tdp = node;57char *name = NULL;58ulong_t h = 0;5960if (tdp->t_name)61name = tdp->t_name;62else {63switch (tdp->t_type) {64case POINTER:65case TYPEDEF:66case VOLATILE:67case CONST:68case RESTRICT:69name = tdp->t_tdesc->t_name;70break;71case FUNCTION:72h = tdp->t_fndef->fn_nargs +73tdp->t_fndef->fn_vargs;74name = tdp->t_fndef->fn_ret->t_name;75break;76case ARRAY:77h = tdp->t_ardef->ad_nelems;78name = tdp->t_ardef->ad_contents->t_name;79break;80case STRUCT:81case UNION:82/*83* Unnamed structures, which cannot have forward84* declarations pointing to them. We can therefore85* incorporate the name of the first member into86* the hash value, assuming there are any.87*/88if (tdp->t_members != NULL)89name = tdp->t_members->ml_name;90break;91case ENUM:92/* Use the first element in the hash value */93name = tdp->t_emem->el_name;94break;95default:96/*97* Intrinsics, forwards, and typedefs all have98* names.99*/100warning("Unexpected unnamed %d tdesc (ID %d)\n",101tdp->t_type, tdp->t_id);102}103}104105if (name)106return (hash_name(nbuckets, name));107108return (h % nbuckets);109}110111int112tdesc_layoutcmp(void *arg1, void *arg2)113{114tdesc_t *tdp1 = arg1, *tdp2 = arg2;115116if (tdp1->t_name == NULL) {117if (tdp2->t_name == NULL)118return (0);119else120return (-1);121} else if (tdp2->t_name == NULL)122return (1);123else124return (strcmp(tdp1->t_name, tdp2->t_name));125}126127int128tdesc_idhash(int nbuckets, void *data)129{130tdesc_t *tdp = data;131132return (tdp->t_id % nbuckets);133}134135int136tdesc_idcmp(void *arg1, void *arg2)137{138tdesc_t *tdp1 = arg1, *tdp2 = arg2;139140if (tdp1->t_id == tdp2->t_id)141return (0);142else143return (tdp1->t_id > tdp2->t_id ? 1 : -1);144}145146int147tdesc_namehash(int nbuckets, void *data)148{149tdesc_t *tdp = data;150ulong_t h, g;151char *c;152153if (tdp->t_name == NULL)154return (0);155156for (h = 0, c = tdp->t_name; *c; c++) {157h = (h << 4) + *c;158if ((g = (h & 0xf0000000)) != 0) {159h ^= (g >> 24);160h ^= g;161}162}163164return (h % nbuckets);165}166167int168tdesc_namecmp(void *arg1, void *arg2)169{170tdesc_t *tdp1 = arg1, *tdp2 = arg2;171172return (!streq(tdp1->t_name, tdp2->t_name));173}174175#ifdef illumos176/*ARGSUSED1*/177static int178tdesc_print(void *data, void *private __unused)179{180tdesc_t *tdp = data;181182printf("%7d %s\n", tdp->t_id, tdesc_name(tdp));183184return (1);185}186#endif187188static void189free_intr(tdesc_t *tdp)190{191free(tdp->t_intr);192}193194static void195free_ardef(tdesc_t *tdp)196{197free(tdp->t_ardef);198}199200static void201free_mlist(tdesc_t *tdp)202{203mlist_t *ml = tdp->t_members;204mlist_t *oml;205206while (ml) {207oml = ml;208ml = ml->ml_next;209210if (oml->ml_name)211free(oml->ml_name);212free(oml);213}214}215216static void217free_elist(tdesc_t *tdp)218{219elist_t *el = tdp->t_emem;220elist_t *oel;221222while (el) {223oel = el;224el = el->el_next;225226if (oel->el_name)227free(oel->el_name);228free(oel);229}230}231232static void (*free_cbs[])(tdesc_t *) = {233NULL,234free_intr,235NULL,236free_ardef,237NULL,238free_mlist,239free_mlist,240free_elist,241NULL,242NULL,243NULL,244NULL,245NULL,246NULL247};248249/*ARGSUSED1*/250static void251tdesc_free_cb(void *arg, void *private __unused)252{253tdesc_t *tdp = arg;254if (tdp->t_name)255free(tdp->t_name);256if (free_cbs[tdp->t_type])257free_cbs[tdp->t_type](tdp);258free(tdp);259260return;261}262263void264tdesc_free(tdesc_t *tdp)265{266tdesc_free_cb(tdp, NULL);267}268269static int270tdata_label_cmp(void *arg1, void *arg2)271{272labelent_t *le1 = arg1;273labelent_t *le2 = arg2;274return (le1->le_idx - le2->le_idx);275}276277void278tdata_label_add(tdata_t *td, const char *label, int idx)279{280labelent_t *le = xmalloc(sizeof (*le));281282le->le_name = xstrdup(label);283le->le_idx = (idx == -1 ? td->td_nextid - 1 : idx);284285slist_add(&td->td_labels, le, tdata_label_cmp);286}287288static int289tdata_label_top_cb(void *data, void *arg)290{291labelent_t *le = data;292labelent_t **topp = arg;293294*topp = le;295296return (1);297}298299labelent_t *300tdata_label_top(tdata_t *td)301{302labelent_t *top = NULL;303304(void) list_iter(td->td_labels, tdata_label_top_cb, &top);305306return (top);307}308309static int310tdata_label_find_cb(void *arg1, void *arg2)311{312labelent_t *le = arg1;313labelent_t *tmpl = arg2;314return (streq(le->le_name, tmpl->le_name));315}316317int318tdata_label_find(tdata_t *td, char *label)319{320labelent_t let;321labelent_t *ret;322323if (streq(label, "BASE")) {324ret = (labelent_t *)list_first(td->td_labels);325return (ret ? ret->le_idx : -1);326}327328let.le_name = label;329330if (!(ret = (labelent_t *)list_find(td->td_labels, &let,331tdata_label_find_cb)))332return (-1);333334return (ret->le_idx);335}336337static int338tdata_label_newmax_cb(void *data, void *arg)339{340labelent_t *le = data;341int *newmaxp = arg;342343if (le->le_idx > *newmaxp) {344le->le_idx = *newmaxp;345return (1);346}347348return (0);349}350351void352tdata_label_newmax(tdata_t *td, int newmax)353{354(void) list_iter(td->td_labels, tdata_label_newmax_cb, &newmax);355}356357/*ARGSUSED1*/358static void359tdata_label_free_cb(void *arg, void *private __unused)360{361labelent_t *le = arg;362if (le->le_name)363free(le->le_name);364free(le);365}366367void368tdata_label_free(tdata_t *td)369{370list_free(td->td_labels, tdata_label_free_cb, NULL);371td->td_labels = NULL;372}373374tdata_t *375tdata_new(void)376{377tdata_t *new = xcalloc(sizeof (tdata_t));378379new->td_layouthash = hash_new(TDATA_LAYOUT_HASH_SIZE, tdesc_layouthash,380tdesc_layoutcmp);381new->td_idhash = hash_new(TDATA_ID_HASH_SIZE, tdesc_idhash,382tdesc_idcmp);383/*384* This is also traversed as a list, but amortized O(1)385* lookup massively impacts part of the merge phase, so386* we store the iidescs as a hash.387*/388new->td_iihash = hash_new(IIDESC_HASH_SIZE, iidesc_hash, NULL);389new->td_nextid = 1;390new->td_curvgen = 1;391392pthread_mutex_init(&new->td_mergelock, NULL);393394return (new);395}396397void398tdata_free(tdata_t *td)399{400hash_free(td->td_iihash, iidesc_free, NULL);401hash_free(td->td_layouthash, tdesc_free_cb, NULL);402hash_free(td->td_idhash, NULL, NULL);403list_free(td->td_fwdlist, NULL, NULL);404405tdata_label_free(td);406407free(td->td_parlabel);408free(td->td_parname);409410pthread_mutex_destroy(&td->td_mergelock);411412free(td);413}414415/*ARGSUSED1*/416static int417build_hashes(tdesc_t *ctdp, tdesc_t **ctdpp __unused, void *private)418{419tdata_t *td = private;420421hash_add(td->td_idhash, ctdp);422hash_add(td->td_layouthash, ctdp);423424return (1);425}426427static tdtrav_cb_f build_hashes_cbs[] = {428NULL,429build_hashes, /* intrinsic */430build_hashes, /* pointer */431build_hashes, /* array */432build_hashes, /* function */433build_hashes, /* struct */434build_hashes, /* union */435build_hashes, /* enum */436build_hashes, /* forward */437build_hashes, /* typedef */438tdtrav_assert, /* typedef_unres */439build_hashes, /* volatile */440build_hashes, /* const */441build_hashes /* restrict */442};443444static void445tdata_build_hashes_common(tdata_t *td, hash_t *hash)446{447(void) iitraverse_hash(hash, &td->td_curvgen, NULL, NULL,448build_hashes_cbs, td);449}450451void452tdata_build_hashes(tdata_t *td)453{454tdata_build_hashes_common(td, td->td_iihash);455}456457/* Merge td2 into td1. td2 is destroyed by the merge */458void459tdata_merge(tdata_t *td1, tdata_t *td2)460{461td1->td_curemark = MAX(td1->td_curemark, td2->td_curemark);462td1->td_curvgen = MAX(td1->td_curvgen, td2->td_curvgen);463td1->td_nextid = MAX(td1->td_nextid, td2->td_nextid);464465hash_merge(td1->td_iihash, td2->td_iihash);466467/* Add td2's type tree to the hashes */468tdata_build_hashes_common(td1, td2->td_iihash);469470list_concat(&td1->td_fwdlist, td2->td_fwdlist);471td2->td_fwdlist = NULL;472473slist_merge(&td1->td_labels, td2->td_labels,474tdata_label_cmp);475td2->td_labels = NULL;476477/* free the td2 hashes (data is now part of td1) */478479hash_free(td2->td_layouthash, NULL, NULL);480td2->td_layouthash = NULL;481482hash_free(td2->td_iihash, NULL, NULL);483td2->td_iihash = NULL;484485tdata_free(td2);486}487488489