Path: blob/main/cddl/contrib/opensolaris/tools/ctf/cvt/merge.c
39458 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 2006 Sun Microsystems, Inc. All rights reserved.22* Use is subject to license terms.23*/2425#pragma ident "%Z%%M% %I% %E% SMI"2627/*28* This file contains routines that merge one tdata_t tree, called the child,29* into another, called the parent. Note that these names are used mainly for30* convenience and to represent the direction of the merge. They are not meant31* to imply any relationship between the tdata_t graphs prior to the merge.32*33* tdata_t structures contain two main elements - a hash of iidesc_t nodes, and34* a directed graph of tdesc_t nodes, pointed to by the iidesc_t nodes. Simply35* put, we merge the tdesc_t graphs, followed by the iidesc_t nodes, and then we36* clean up loose ends.37*38* The algorithm is as follows:39*40* 1. Mapping iidesc_t nodes41*42* For each child iidesc_t node, we first try to map its tdesc_t subgraph43* against the tdesc_t graph in the parent. For each node in the child subgraph44* that exists in the parent, a mapping between the two (between their type IDs)45* is established. For the child nodes that cannot be mapped onto existing46* parent nodes, a mapping is established between the child node ID and a47* newly-allocated ID that the node will use when it is re-created in the48* parent. These unmappable nodes are added to the md_tdtba (tdesc_t To Be49* Added) hash, which tracks nodes that need to be created in the parent.50*51* If all of the nodes in the subgraph for an iidesc_t in the child can be52* mapped to existing nodes in the parent, then we can try to map the child53* iidesc_t onto an iidesc_t in the parent. If we cannot find an equivalent54* iidesc_t, or if we were not able to completely map the tdesc_t subgraph(s),55* then we add this iidesc_t to the md_iitba (iidesc_t To Be Added) list. This56* list tracks iidesc_t nodes that are to be created in the parent.57*58* While visiting the tdesc_t nodes, we may discover a forward declaration (a59* FORWARD tdesc_t) in the parent that is resolved in the child. That is, there60* may be a structure or union definition in the child with the same name as the61* forward declaration in the parent. If we find such a node, we record an62* association in the md_fdida (Forward => Definition ID Association) list63* between the parent ID of the forward declaration and the ID that the64* definition will use when re-created in the parent.65*66* 2. Creating new tdesc_t nodes (the md_tdtba hash)67*68* We have now attempted to map all tdesc_t nodes from the child into the69* parent, and have, in md_tdtba, a hash of all tdesc_t nodes that need to be70* created (or, as we so wittily call it, conjured) in the parent. We iterate71* through this hash, creating the indicated tdesc_t nodes. For a given tdesc_t72* node, conjuring requires two steps - the copying of the common tdesc_t data73* (name, type, etc) from the child node, and the creation of links from the74* newly-created node to the parent equivalents of other tdesc_t nodes pointed75* to by node being conjured. Note that in some cases, the targets of these76* links will be on the md_tdtba hash themselves, and may not have been created77* yet. As such, we can't establish the links from these new nodes into the78* parent graph. We therefore conjure them with links to nodes in the *child*79* graph, and add pointers to the links to be created to the md_tdtbr (tdesc_t80* To Be Remapped) hash. For example, a POINTER tdesc_t that could not be81* resolved would have its &tdesc_t->t_tdesc added to md_tdtbr.82*83* 3. Creating new iidesc_t nodes (the md_iitba list)84*85* When we have completed step 2, all tdesc_t nodes have been created (or86* already existed) in the parent. Some of them may have incorrect links (the87* members of the md_tdtbr list), but they've all been created. As such, we can88* create all of the iidesc_t nodes, as we can attach the tdesc_t subgraph89* pointers correctly. We create each node, and attach the pointers to the90* appropriate parts of the parent tdesc_t graph.91*92* 4. Resolving newly-created tdesc_t node links (the md_tdtbr list)93*94* As in step 3, we rely on the fact that all of the tdesc_t nodes have been95* created. Each entry in the md_tdtbr list is a pointer to where a link into96* the parent will be established. As saved in the md_tdtbr list, these97* pointers point into the child tdesc_t subgraph. We can thus get the target98* type ID from the child, look at the ID mapping to determine the desired link99* target, and redirect the link accordingly.100*101* 5. Parent => child forward declaration resolution102*103* If entries were made in the md_fdida list in step 1, we have forward104* declarations in the parent that need to be resolved to their definitions105* re-created in step 2 from the child. Using the md_fdida list, we can locate106* the definition for the forward declaration, and we can redirect all inbound107* edges to the forward declaration node to the actual definition.108*109* A pox on the house of anyone who changes the algorithm without updating110* this comment.111*/112113#include <stdio.h>114#include <strings.h>115#include <assert.h>116#include <pthread.h>117118#include "ctf_headers.h"119#include "ctftools.h"120#include "list.h"121#include "alist.h"122#include "memory.h"123#include "traverse.h"124125typedef struct equiv_data equiv_data_t;126typedef struct merge_cb_data merge_cb_data_t;127128/*129* There are two traversals in this file, for equivalency and for tdesc_t130* re-creation, that do not fit into the tdtraverse() framework. We have our131* own traversal mechanism and ops vector here for those two cases.132*/133typedef struct tdesc_ops {134const char *name;135int (*equiv)(tdesc_t *, tdesc_t *, equiv_data_t *);136tdesc_t *(*conjure)(tdesc_t *, int, merge_cb_data_t *);137} tdesc_ops_t;138extern tdesc_ops_t tdesc_ops[];139140/*141* The workhorse structure of tdata_t merging. Holds all lists of nodes to be142* processed during various phases of the merge algorithm.143*/144struct merge_cb_data {145tdata_t *md_parent;146tdata_t *md_tgt;147alist_t *md_ta; /* Type Association */148alist_t *md_fdida; /* Forward -> Definition ID Association */149list_t **md_iitba; /* iidesc_t nodes To Be Added to the parent */150hash_t *md_tdtba; /* tdesc_t nodes To Be Added to the parent */151list_t **md_tdtbr; /* tdesc_t nodes To Be Remapped */152int md_flags;153}; /* merge_cb_data_t */154155/*156* When we first create a tdata_t from stabs data, we will have duplicate nodes.157* Normal merges, however, assume that the child tdata_t is already self-unique,158* and for speed reasons do not attempt to self-uniquify. If this flag is set,159* the merge algorithm will self-uniquify by avoiding the insertion of160* duplicates in the md_tdtdba list.161*/162#define MCD_F_SELFUNIQUIFY 0x1163164/*165* When we merge the CTF data for the modules, we don't want it to contain any166* data that can be found in the reference module (usually genunix). If this167* flag is set, we're doing a merge between the fully merged tdata_t for this168* module and the tdata_t for the reference module, with the data unique to this169* module ending up in a third tdata_t. It is this third tdata_t that will end170* up in the .SUNW_ctf section for the module.171*/172#define MCD_F_REFMERGE 0x2173174/*175* Mapping of child type IDs to parent type IDs176*/177178static void179add_mapping(alist_t *ta, tid_t srcid, tid_t tgtid)180{181debug(3, "Adding mapping %u <%x> => %u <%x>\n", srcid, srcid, tgtid, tgtid);182183assert(!alist_find(ta, (void *)(uintptr_t)srcid, NULL));184assert(srcid != 0 && tgtid != 0);185186alist_add(ta, (void *)(uintptr_t)srcid, (void *)(uintptr_t)tgtid);187}188189static tid_t190get_mapping(alist_t *ta, int srcid)191{192void *ltgtid;193194if (alist_find(ta, (void *)(uintptr_t)srcid, (void **)<gtid))195return ((uintptr_t)ltgtid);196else197return (0);198}199200/*201* Determining equivalence of tdesc_t subgraphs202*/203204struct equiv_data {205alist_t *ed_ta;206tdesc_t *ed_node;207tdesc_t *ed_tgt;208209int ed_clear_mark;210int ed_cur_mark;211int ed_selfuniquify;212}; /* equiv_data_t */213214static int equiv_node(tdesc_t *, tdesc_t *, equiv_data_t *);215216/*ARGSUSED2*/217static int218equiv_intrinsic(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed __unused)219{220intr_t *si = stdp->t_intr;221intr_t *ti = ttdp->t_intr;222223if (si->intr_type != ti->intr_type ||224si->intr_signed != ti->intr_signed ||225si->intr_offset != ti->intr_offset ||226si->intr_nbits != ti->intr_nbits)227return (0);228229if (si->intr_type == INTR_INT &&230si->intr_iformat != ti->intr_iformat)231return (0);232else if (si->intr_type == INTR_REAL &&233si->intr_fformat != ti->intr_fformat)234return (0);235236return (1);237}238239static int240equiv_plain(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed)241{242return (equiv_node(stdp->t_tdesc, ttdp->t_tdesc, ed));243}244245static int246equiv_function(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed)247{248fndef_t *fn1 = stdp->t_fndef, *fn2 = ttdp->t_fndef;249int i;250251if (fn1->fn_nargs != fn2->fn_nargs ||252fn1->fn_vargs != fn2->fn_vargs)253return (0);254255if (!equiv_node(fn1->fn_ret, fn2->fn_ret, ed))256return (0);257258for (i = 0; i < (int) fn1->fn_nargs; i++) {259if (!equiv_node(fn1->fn_args[i], fn2->fn_args[i], ed))260return (0);261}262263return (1);264}265266static int267equiv_array(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed)268{269ardef_t *ar1 = stdp->t_ardef, *ar2 = ttdp->t_ardef;270271if (!equiv_node(ar1->ad_contents, ar2->ad_contents, ed) ||272!equiv_node(ar1->ad_idxtype, ar2->ad_idxtype, ed))273return (0);274275if (ar1->ad_nelems != ar2->ad_nelems)276return (0);277278return (1);279}280281static int282equiv_su(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed)283{284mlist_t *ml1 = stdp->t_members, *ml2 = ttdp->t_members;285286while (ml1 && ml2) {287if (ml1->ml_offset != ml2->ml_offset ||288strcmp(ml1->ml_name, ml2->ml_name) != 0 ||289ml1->ml_size != ml2->ml_size ||290!equiv_node(ml1->ml_type, ml2->ml_type, ed))291return (0);292293ml1 = ml1->ml_next;294ml2 = ml2->ml_next;295}296297if (ml1 || ml2)298return (0);299300return (1);301}302303/*ARGSUSED2*/304static int305equiv_enum(tdesc_t *stdp, tdesc_t *ttdp, equiv_data_t *ed __unused)306{307elist_t *el1 = stdp->t_emem;308elist_t *el2 = ttdp->t_emem;309310while (el1 && el2) {311if (el1->el_number != el2->el_number ||312strcmp(el1->el_name, el2->el_name) != 0)313return (0);314315el1 = el1->el_next;316el2 = el2->el_next;317}318319if (el1 || el2)320return (0);321322return (1);323}324325/*ARGSUSED*/326static int327equiv_assert(tdesc_t *stdp __unused, tdesc_t *ttdp __unused, equiv_data_t *ed __unused)328{329/* foul, evil, and very bad - this is a "shouldn't happen" */330assert(1 == 0);331332return (0);333}334335static int336fwd_equiv(tdesc_t *ctdp, tdesc_t *mtdp)337{338tdesc_t *defn = (ctdp->t_type == FORWARD ? mtdp : ctdp);339340return (defn->t_type == STRUCT || defn->t_type == UNION ||341defn->t_type == ENUM);342}343344static int345equiv_node(tdesc_t *ctdp, tdesc_t *mtdp, equiv_data_t *ed)346{347int (*equiv)(tdesc_t *, tdesc_t *, equiv_data_t *);348int mapping;349350if (ctdp->t_emark > ed->ed_clear_mark &&351mtdp->t_emark > ed->ed_clear_mark)352return (ctdp->t_emark == mtdp->t_emark);353354/*355* In normal (non-self-uniquify) mode, we don't want to do equivalency356* checking on a subgraph that has already been checked. If a mapping357* has already been established for a given child node, we can simply358* compare the mapping for the child node with the ID of the parent359* node. If we are in self-uniquify mode, then we're comparing two360* subgraphs within the child graph, and thus need to ignore any361* type mappings that have been created, as they are only valid into the362* parent.363*/364if ((mapping = get_mapping(ed->ed_ta, ctdp->t_id)) > 0 &&365mapping == mtdp->t_id && !ed->ed_selfuniquify)366return (1);367368if (!streq(ctdp->t_name, mtdp->t_name))369return (0);370371if (ctdp->t_type != mtdp->t_type) {372if (ctdp->t_type == FORWARD || mtdp->t_type == FORWARD)373return (fwd_equiv(ctdp, mtdp));374else375return (0);376}377378ctdp->t_emark = ed->ed_cur_mark;379mtdp->t_emark = ed->ed_cur_mark;380ed->ed_cur_mark++;381382if ((equiv = tdesc_ops[ctdp->t_type].equiv) != NULL)383return (equiv(ctdp, mtdp, ed));384385return (1);386}387388/*389* We perform an equivalency check on two subgraphs by traversing through them390* in lockstep. If a given node is equivalent in both the parent and the child,391* we mark it in both subgraphs, using the t_emark field, with a monotonically392* increasing number. If, in the course of the traversal, we reach a node that393* we have visited and numbered during this equivalency check, we have a cycle.394* If the previously-visited nodes don't have the same emark, then the edges395* that brought us to these nodes are not equivalent, and so the check ends.396* If the emarks are the same, the edges are equivalent. We then backtrack and397* continue the traversal. If we have exhausted all edges in the subgraph, and398* have not found any inequivalent nodes, then the subgraphs are equivalent.399*/400static int401equiv_cb(void *bucket, void *arg)402{403equiv_data_t *ed = arg;404tdesc_t *mtdp = bucket;405tdesc_t *ctdp = ed->ed_node;406407ed->ed_clear_mark = ed->ed_cur_mark + 1;408ed->ed_cur_mark = ed->ed_clear_mark + 1;409410if (equiv_node(ctdp, mtdp, ed)) {411debug(3, "equiv_node matched %d <%x> %d <%x>\n",412ctdp->t_id, ctdp->t_id, mtdp->t_id, mtdp->t_id);413ed->ed_tgt = mtdp;414/* matched. stop looking */415return (-1);416}417418return (0);419}420421/*ARGSUSED1*/422static int423map_td_tree_pre(tdesc_t *ctdp, tdesc_t **ctdpp __unused, void *private)424{425merge_cb_data_t *mcd = private;426427if (get_mapping(mcd->md_ta, ctdp->t_id) > 0)428return (0);429430return (1);431}432433/*ARGSUSED1*/434static int435map_td_tree_post(tdesc_t *ctdp, tdesc_t **ctdpp __unused, void *private)436{437merge_cb_data_t *mcd = private;438equiv_data_t ed;439440ed.ed_ta = mcd->md_ta;441ed.ed_clear_mark = mcd->md_parent->td_curemark;442ed.ed_cur_mark = mcd->md_parent->td_curemark + 1;443ed.ed_node = ctdp;444ed.ed_selfuniquify = 0;445446debug(3, "map_td_tree_post on %d <%x> %s\n", ctdp->t_id, ctdp->t_id,tdesc_name(ctdp));447448if (hash_find_iter(mcd->md_parent->td_layouthash, ctdp,449equiv_cb, &ed) < 0) {450/* We found an equivalent node */451if (ed.ed_tgt->t_type == FORWARD && ctdp->t_type != FORWARD) {452int id = mcd->md_tgt->td_nextid++;453454debug(3, "Creating new defn type %d <%x>\n", id, id);455add_mapping(mcd->md_ta, ctdp->t_id, id);456alist_add(mcd->md_fdida, (void *)(ulong_t)ed.ed_tgt,457(void *)(ulong_t)id);458hash_add(mcd->md_tdtba, ctdp);459} else460add_mapping(mcd->md_ta, ctdp->t_id, ed.ed_tgt->t_id);461462} else if (debug_level > 1 && hash_iter(mcd->md_parent->td_idhash,463equiv_cb, &ed) < 0) {464/*465* We didn't find an equivalent node by looking through the466* layout hash, but we somehow found it by performing an467* exhaustive search through the entire graph. This usually468* means that the "name" hash function is broken.469*/470aborterr("Second pass for %d (%s) == %d\n", ctdp->t_id,471tdesc_name(ctdp), ed.ed_tgt->t_id);472} else {473int id = mcd->md_tgt->td_nextid++;474475debug(3, "Creating new type %d <%x>\n", id, id);476add_mapping(mcd->md_ta, ctdp->t_id, id);477hash_add(mcd->md_tdtba, ctdp);478}479480mcd->md_parent->td_curemark = ed.ed_cur_mark + 1;481482return (1);483}484485/*ARGSUSED1*/486static int487map_td_tree_self_post(tdesc_t *ctdp, tdesc_t **ctdpp __unused, void *private)488{489merge_cb_data_t *mcd = private;490equiv_data_t ed;491492ed.ed_ta = mcd->md_ta;493ed.ed_clear_mark = mcd->md_parent->td_curemark;494ed.ed_cur_mark = mcd->md_parent->td_curemark + 1;495ed.ed_node = ctdp;496ed.ed_selfuniquify = 1;497ed.ed_tgt = NULL;498499if (hash_find_iter(mcd->md_tdtba, ctdp, equiv_cb, &ed) < 0) {500debug(3, "Self check found %d <%x> in %d <%x>\n", ctdp->t_id,501ctdp->t_id, ed.ed_tgt->t_id, ed.ed_tgt->t_id);502add_mapping(mcd->md_ta, ctdp->t_id,503get_mapping(mcd->md_ta, ed.ed_tgt->t_id));504} else if (debug_level > 1 && hash_iter(mcd->md_tdtba,505equiv_cb, &ed) < 0) {506/*507* We didn't find an equivalent node using the quick way (going508* through the hash normally), but we did find it by iterating509* through the entire hash. This usually means that the hash510* function is broken.511*/512aborterr("Self-unique second pass for %d <%x> (%s) == %d <%x>\n",513ctdp->t_id, ctdp->t_id, tdesc_name(ctdp), ed.ed_tgt->t_id,514ed.ed_tgt->t_id);515} else {516int id = mcd->md_tgt->td_nextid++;517518debug(3, "Creating new type %d <%x>\n", id, id);519add_mapping(mcd->md_ta, ctdp->t_id, id);520hash_add(mcd->md_tdtba, ctdp);521}522523mcd->md_parent->td_curemark = ed.ed_cur_mark + 1;524525return (1);526}527528static tdtrav_cb_f map_pre[] = {529NULL,530map_td_tree_pre, /* intrinsic */531map_td_tree_pre, /* pointer */532map_td_tree_pre, /* array */533map_td_tree_pre, /* function */534map_td_tree_pre, /* struct */535map_td_tree_pre, /* union */536map_td_tree_pre, /* enum */537map_td_tree_pre, /* forward */538map_td_tree_pre, /* typedef */539tdtrav_assert, /* typedef_unres */540map_td_tree_pre, /* volatile */541map_td_tree_pre, /* const */542map_td_tree_pre /* restrict */543};544545static tdtrav_cb_f map_post[] = {546NULL,547map_td_tree_post, /* intrinsic */548map_td_tree_post, /* pointer */549map_td_tree_post, /* array */550map_td_tree_post, /* function */551map_td_tree_post, /* struct */552map_td_tree_post, /* union */553map_td_tree_post, /* enum */554map_td_tree_post, /* forward */555map_td_tree_post, /* typedef */556tdtrav_assert, /* typedef_unres */557map_td_tree_post, /* volatile */558map_td_tree_post, /* const */559map_td_tree_post /* restrict */560};561562static tdtrav_cb_f map_self_post[] = {563NULL,564map_td_tree_self_post, /* intrinsic */565map_td_tree_self_post, /* pointer */566map_td_tree_self_post, /* array */567map_td_tree_self_post, /* function */568map_td_tree_self_post, /* struct */569map_td_tree_self_post, /* union */570map_td_tree_self_post, /* enum */571map_td_tree_self_post, /* forward */572map_td_tree_self_post, /* typedef */573tdtrav_assert, /* typedef_unres */574map_td_tree_self_post, /* volatile */575map_td_tree_self_post, /* const */576map_td_tree_self_post /* restrict */577};578579/*580* Determining equivalence of iidesc_t nodes581*/582583typedef struct iifind_data {584iidesc_t *iif_template;585alist_t *iif_ta;586int iif_newidx;587int iif_refmerge;588} iifind_data_t;589590/*591* Check to see if this iidesc_t (node) - the current one on the list we're592* iterating through - matches the target one (iif->iif_template). Return -1593* if it matches, to stop the iteration.594*/595static int596iidesc_match(void *data, void *arg)597{598iidesc_t *node = data;599iifind_data_t *iif = arg;600int i;601602if (node->ii_type != iif->iif_template->ii_type ||603!streq(node->ii_name, iif->iif_template->ii_name) ||604node->ii_dtype->t_id != iif->iif_newidx)605return (0);606607if ((node->ii_type == II_SVAR || node->ii_type == II_SFUN) &&608!streq(node->ii_owner, iif->iif_template->ii_owner))609return (0);610611if (node->ii_nargs != iif->iif_template->ii_nargs)612return (0);613614for (i = 0; i < node->ii_nargs; i++) {615if (get_mapping(iif->iif_ta,616iif->iif_template->ii_args[i]->t_id) !=617node->ii_args[i]->t_id)618return (0);619}620621if (iif->iif_refmerge) {622switch (iif->iif_template->ii_type) {623case II_GFUN:624case II_SFUN:625case II_GVAR:626case II_SVAR:627debug(3, "suppressing duping of %d %s from %s\n",628iif->iif_template->ii_type,629iif->iif_template->ii_name,630(iif->iif_template->ii_owner ?631iif->iif_template->ii_owner : "NULL"));632return (0);633case II_NOT:634case II_PSYM:635case II_SOU:636case II_TYPE:637break;638}639}640641return (-1);642}643644static int645merge_type_cb(void *data, void *arg)646{647iidesc_t *sii = data;648merge_cb_data_t *mcd = arg;649iifind_data_t iif;650tdtrav_cb_f *post;651652post = (mcd->md_flags & MCD_F_SELFUNIQUIFY ? map_self_post : map_post);653654/* Map the tdesc nodes */655(void) iitraverse(sii, &mcd->md_parent->td_curvgen, NULL, map_pre, post,656mcd);657658/* Map the iidesc nodes */659iif.iif_template = sii;660iif.iif_ta = mcd->md_ta;661iif.iif_newidx = get_mapping(mcd->md_ta, sii->ii_dtype->t_id);662iif.iif_refmerge = (mcd->md_flags & MCD_F_REFMERGE);663664if (hash_match(mcd->md_parent->td_iihash, sii, iidesc_match,665&iif) == 1)666/* successfully mapped */667return (1);668669debug(3, "tba %s (%d)\n", (sii->ii_name ? sii->ii_name : "(anon)"),670sii->ii_type);671672list_add(mcd->md_iitba, sii);673674return (0);675}676677static int678remap_node(tdesc_t **tgtp, tdesc_t *oldtgt, int selftid, tdesc_t *newself,679merge_cb_data_t *mcd)680{681tdesc_t *tgt = NULL;682tdesc_t template;683int oldid = oldtgt->t_id;684685if (oldid == selftid) {686*tgtp = newself;687return (1);688}689690if ((template.t_id = get_mapping(mcd->md_ta, oldid)) == 0)691aborterr("failed to get mapping for tid %d <%x>\n", oldid, oldid);692693if (!hash_find(mcd->md_parent->td_idhash, (void *)&template,694(void *)&tgt) && (!(mcd->md_flags & MCD_F_REFMERGE) ||695!hash_find(mcd->md_tgt->td_idhash, (void *)&template,696(void *)&tgt))) {697debug(3, "Remap couldn't find %d <%x> (from %d <%x>)\n", template.t_id,698template.t_id, oldid, oldid);699*tgtp = oldtgt;700list_add(mcd->md_tdtbr, tgtp);701return (0);702}703704*tgtp = tgt;705return (1);706}707708static tdesc_t *709conjure_template(tdesc_t *old, int newselfid)710{711tdesc_t *new = xcalloc(sizeof (tdesc_t));712713new->t_name = old->t_name ? xstrdup(old->t_name) : NULL;714new->t_type = old->t_type;715new->t_size = old->t_size;716new->t_id = newselfid;717new->t_flags = old->t_flags;718719return (new);720}721722/*ARGSUSED2*/723static tdesc_t *724conjure_intrinsic(tdesc_t *old, int newselfid, merge_cb_data_t *mcd __unused)725{726tdesc_t *new = conjure_template(old, newselfid);727728new->t_intr = xmalloc(sizeof (intr_t));729bcopy(old->t_intr, new->t_intr, sizeof (intr_t));730731return (new);732}733734static tdesc_t *735conjure_plain(tdesc_t *old, int newselfid, merge_cb_data_t *mcd)736{737tdesc_t *new = conjure_template(old, newselfid);738739(void) remap_node(&new->t_tdesc, old->t_tdesc, old->t_id, new, mcd);740741return (new);742}743744static tdesc_t *745conjure_function(tdesc_t *old, int newselfid, merge_cb_data_t *mcd)746{747tdesc_t *new = conjure_template(old, newselfid);748fndef_t *nfn = xmalloc(sizeof (fndef_t));749fndef_t *ofn = old->t_fndef;750int i;751752(void) remap_node(&nfn->fn_ret, ofn->fn_ret, old->t_id, new, mcd);753754nfn->fn_nargs = ofn->fn_nargs;755nfn->fn_vargs = ofn->fn_vargs;756757if (nfn->fn_nargs > 0)758nfn->fn_args = xcalloc(sizeof (tdesc_t *) * ofn->fn_nargs);759760for (i = 0; i < (int) ofn->fn_nargs; i++) {761(void) remap_node(&nfn->fn_args[i], ofn->fn_args[i], old->t_id,762new, mcd);763}764765new->t_fndef = nfn;766767return (new);768}769770static tdesc_t *771conjure_array(tdesc_t *old, int newselfid, merge_cb_data_t *mcd)772{773tdesc_t *new = conjure_template(old, newselfid);774ardef_t *nar = xmalloc(sizeof (ardef_t));775ardef_t *oar = old->t_ardef;776777(void) remap_node(&nar->ad_contents, oar->ad_contents, old->t_id, new,778mcd);779(void) remap_node(&nar->ad_idxtype, oar->ad_idxtype, old->t_id, new,780mcd);781782nar->ad_nelems = oar->ad_nelems;783784new->t_ardef = nar;785786return (new);787}788789static tdesc_t *790conjure_su(tdesc_t *old, int newselfid, merge_cb_data_t *mcd)791{792tdesc_t *new = conjure_template(old, newselfid);793mlist_t *omem, **nmemp;794795for (omem = old->t_members, nmemp = &new->t_members;796omem; omem = omem->ml_next, nmemp = &((*nmemp)->ml_next)) {797*nmemp = xmalloc(sizeof (mlist_t));798(*nmemp)->ml_offset = omem->ml_offset;799(*nmemp)->ml_size = omem->ml_size;800(*nmemp)->ml_name = xstrdup(omem->ml_name ? omem->ml_name : "empty omem->ml_name");801(void) remap_node(&((*nmemp)->ml_type), omem->ml_type,802old->t_id, new, mcd);803}804*nmemp = NULL;805806return (new);807}808809/*ARGSUSED2*/810static tdesc_t *811conjure_enum(tdesc_t *old, int newselfid, merge_cb_data_t *mcd __unused)812{813tdesc_t *new = conjure_template(old, newselfid);814elist_t *oel, **nelp;815816for (oel = old->t_emem, nelp = &new->t_emem;817oel; oel = oel->el_next, nelp = &((*nelp)->el_next)) {818*nelp = xmalloc(sizeof (elist_t));819(*nelp)->el_name = xstrdup(oel->el_name);820(*nelp)->el_number = oel->el_number;821}822*nelp = NULL;823824return (new);825}826827/*ARGSUSED2*/828static tdesc_t *829conjure_forward(tdesc_t *old, int newselfid, merge_cb_data_t *mcd)830{831tdesc_t *new = conjure_template(old, newselfid);832833list_add(&mcd->md_tgt->td_fwdlist, new);834835return (new);836}837838/*ARGSUSED*/839static tdesc_t *840conjure_assert(tdesc_t *old __unused, int newselfid __unused, merge_cb_data_t *mcd __unused)841{842assert(1 == 0);843return (NULL);844}845846static iidesc_t *847conjure_iidesc(iidesc_t *old, merge_cb_data_t *mcd)848{849iidesc_t *new = iidesc_dup(old);850int i;851852(void) remap_node(&new->ii_dtype, old->ii_dtype, -1, NULL, mcd);853for (i = 0; i < new->ii_nargs; i++) {854(void) remap_node(&new->ii_args[i], old->ii_args[i], -1, NULL,855mcd);856}857858return (new);859}860861static int862fwd_redir(tdesc_t *fwd, tdesc_t **fwdp, void *private)863{864alist_t *map = private;865void *defn;866867if (!alist_find(map, (void *)fwd, (void **)&defn))868return (0);869870debug(3, "Redirecting an edge to %s\n", tdesc_name(defn));871872*fwdp = defn;873874return (1);875}876877static tdtrav_cb_f fwd_redir_cbs[] = {878NULL,879NULL, /* intrinsic */880NULL, /* pointer */881NULL, /* array */882NULL, /* function */883NULL, /* struct */884NULL, /* union */885NULL, /* enum */886fwd_redir, /* forward */887NULL, /* typedef */888tdtrav_assert, /* typedef_unres */889NULL, /* volatile */890NULL, /* const */891NULL /* restrict */892};893894typedef struct redir_mstr_data {895tdata_t *rmd_tgt;896alist_t *rmd_map;897} redir_mstr_data_t;898899static int900redir_mstr_fwd_cb(void *name, void *value, void *arg)901{902tdesc_t *fwd = name;903int defnid = (uintptr_t)value;904redir_mstr_data_t *rmd = arg;905tdesc_t template;906tdesc_t *defn;907908template.t_id = defnid;909910if (!hash_find(rmd->rmd_tgt->td_idhash, (void *)&template,911(void *)&defn)) {912aborterr("Couldn't unforward %d (%s)\n", defnid,913tdesc_name(defn));914}915916debug(3, "Forward map: resolved %d to %s\n", defnid, tdesc_name(defn));917918alist_add(rmd->rmd_map, (void *)fwd, (void *)defn);919920return (1);921}922923static void924redir_mstr_fwds(merge_cb_data_t *mcd)925{926redir_mstr_data_t rmd;927alist_t *map = alist_new(NULL, NULL);928929rmd.rmd_tgt = mcd->md_tgt;930rmd.rmd_map = map;931932if (alist_iter(mcd->md_fdida, redir_mstr_fwd_cb, &rmd)) {933(void) iitraverse_hash(mcd->md_tgt->td_iihash,934&mcd->md_tgt->td_curvgen, fwd_redir_cbs, NULL, NULL, map);935}936937alist_free(map);938}939940static int941add_iitba_cb(void *data, void *private)942{943merge_cb_data_t *mcd = private;944iidesc_t *tba = data;945iidesc_t *new;946iifind_data_t iif;947int newidx;948949newidx = get_mapping(mcd->md_ta, tba->ii_dtype->t_id);950assert(newidx != -1);951952(void) list_remove(mcd->md_iitba, data, NULL, NULL);953954iif.iif_template = tba;955iif.iif_ta = mcd->md_ta;956iif.iif_newidx = newidx;957iif.iif_refmerge = (mcd->md_flags & MCD_F_REFMERGE);958959if (hash_match(mcd->md_parent->td_iihash, tba, iidesc_match,960&iif) == 1) {961debug(3, "iidesc_t %s already exists\n",962(tba->ii_name ? tba->ii_name : "(anon)"));963return (1);964}965966new = conjure_iidesc(tba, mcd);967hash_add(mcd->md_tgt->td_iihash, new);968969return (1);970}971972static int973add_tdesc(tdesc_t *oldtdp, int newid, merge_cb_data_t *mcd)974{975tdesc_t *newtdp;976tdesc_t template;977978template.t_id = newid;979assert(hash_find(mcd->md_parent->td_idhash,980(void *)&template, NULL) == 0);981982debug(3, "trying to conjure %d %s (%d, <%x>) as %d, <%x>\n",983oldtdp->t_type, tdesc_name(oldtdp), oldtdp->t_id,984oldtdp->t_id, newid, newid);985986if ((newtdp = tdesc_ops[oldtdp->t_type].conjure(oldtdp, newid,987mcd)) == NULL)988/* couldn't map everything */989return (0);990991debug(3, "succeeded\n");992993hash_add(mcd->md_tgt->td_idhash, newtdp);994hash_add(mcd->md_tgt->td_layouthash, newtdp);995996return (1);997}998999static int1000add_tdtba_cb(void *data, void *arg)1001{1002tdesc_t *tdp = data;1003merge_cb_data_t *mcd = arg;1004int newid;1005int rc;10061007newid = get_mapping(mcd->md_ta, tdp->t_id);1008assert(newid != -1);10091010if ((rc = add_tdesc(tdp, newid, mcd)))1011hash_remove(mcd->md_tdtba, (void *)tdp);10121013return (rc);1014}10151016static int1017add_tdtbr_cb(void *data, void *arg)1018{1019tdesc_t **tdpp = data;1020merge_cb_data_t *mcd = arg;10211022debug(3, "Remapping %s (%d)\n", tdesc_name(*tdpp), (*tdpp)->t_id);10231024if (!remap_node(tdpp, *tdpp, -1, NULL, mcd))1025return (0);10261027(void) list_remove(mcd->md_tdtbr, (void *)tdpp, NULL, NULL);1028return (1);1029}10301031static void1032merge_types(hash_t *src, merge_cb_data_t *mcd)1033{1034list_t *iitba = NULL;1035list_t *tdtbr = NULL;1036int iirc, tdrc;10371038mcd->md_iitba = &iitba;1039mcd->md_tdtba = hash_new(TDATA_LAYOUT_HASH_SIZE, tdesc_layouthash,1040tdesc_layoutcmp);1041mcd->md_tdtbr = &tdtbr;10421043(void) hash_iter(src, merge_type_cb, mcd);10441045tdrc = hash_iter(mcd->md_tdtba, add_tdtba_cb, mcd);1046debug(3, "add_tdtba_cb added %d items\n", tdrc);10471048iirc = list_iter(*mcd->md_iitba, add_iitba_cb, mcd);1049debug(3, "add_iitba_cb added %d items\n", iirc);10501051assert(list_count(*mcd->md_iitba) == 0 &&1052hash_count(mcd->md_tdtba) == 0);10531054tdrc = list_iter(*mcd->md_tdtbr, add_tdtbr_cb, mcd);1055debug(3, "add_tdtbr_cb added %d items\n", tdrc);10561057if (list_count(*mcd->md_tdtbr) != 0)1058aborterr("Couldn't remap all nodes\n");10591060/*1061* We now have an alist of master forwards and the ids of the new master1062* definitions for those forwards in mcd->md_fdida. By this point,1063* we're guaranteed that all of the master definitions referenced in1064* fdida have been added to the master tree. We now traverse through1065* the master tree, redirecting all edges inbound to forwards that have1066* definitions to those definitions.1067*/1068if (mcd->md_parent == mcd->md_tgt) {1069redir_mstr_fwds(mcd);1070}1071}10721073void1074merge_into_master(tdata_t *cur, tdata_t *mstr, tdata_t *tgt, int selfuniquify)1075{1076merge_cb_data_t mcd;10771078cur->td_ref++;1079mstr->td_ref++;1080if (tgt)1081tgt->td_ref++;10821083assert(cur->td_ref == 1 && mstr->td_ref == 1 &&1084(tgt == NULL || tgt->td_ref == 1));10851086mcd.md_parent = mstr;1087mcd.md_tgt = (tgt ? tgt : mstr);1088mcd.md_ta = alist_new(NULL, NULL);1089mcd.md_fdida = alist_new(NULL, NULL);1090mcd.md_flags = 0;10911092if (selfuniquify)1093mcd.md_flags |= MCD_F_SELFUNIQUIFY;1094if (tgt)1095mcd.md_flags |= MCD_F_REFMERGE;10961097mstr->td_curvgen = MAX(mstr->td_curvgen, cur->td_curvgen);1098mstr->td_curemark = MAX(mstr->td_curemark, cur->td_curemark);10991100merge_types(cur->td_iihash, &mcd);11011102if (debug_level >= 3) {1103debug(3, "Type association stats\n");1104alist_stats(mcd.md_ta, 0);1105debug(3, "Layout hash stats\n");1106hash_stats(mcd.md_tgt->td_layouthash, 1);1107}11081109alist_free(mcd.md_fdida);1110alist_free(mcd.md_ta);11111112cur->td_ref--;1113mstr->td_ref--;1114if (tgt)1115tgt->td_ref--;1116}11171118tdesc_ops_t tdesc_ops[] = {1119{ "ERROR! BAD tdesc TYPE", NULL, NULL },1120{ "intrinsic", equiv_intrinsic, conjure_intrinsic },1121{ "pointer", equiv_plain, conjure_plain },1122{ "array", equiv_array, conjure_array },1123{ "function", equiv_function, conjure_function },1124{ "struct", equiv_su, conjure_su },1125{ "union", equiv_su, conjure_su },1126{ "enum", equiv_enum, conjure_enum },1127{ "forward", NULL, conjure_forward },1128{ "typedef", equiv_plain, conjure_plain },1129{ "typedef_unres", equiv_assert, conjure_assert },1130{ "volatile", equiv_plain, conjure_plain },1131{ "const", equiv_plain, conjure_plain },1132{ "restrict", equiv_plain, conjure_plain }1133};113411351136