1178525Sjb/*
2178525Sjb * CDDL HEADER START
3178525Sjb *
4178525Sjb * The contents of this file are subject to the terms of the
5178525Sjb * Common Development and Distribution License, Version 1.0 only
6178525Sjb * (the "License").  You may not use this file except in compliance
7178525Sjb * with the License.
8178525Sjb *
9178525Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10178525Sjb * or http://www.opensolaris.org/os/licensing.
11178525Sjb * See the License for the specific language governing permissions
12178525Sjb * and limitations under the License.
13178525Sjb *
14178525Sjb * When distributing Covered Code, include this CDDL HEADER in each
15178525Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16178525Sjb * If applicable, add the following below this CDDL HEADER, with the
17178525Sjb * fields enclosed by brackets "[]" replaced with your own identifying
18178525Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
19178525Sjb *
20178525Sjb * CDDL HEADER END
21178525Sjb */
22178525Sjb
23178525Sjb/*
24178525Sjb * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25178525Sjb * Use is subject to license terms.
26178525Sjb */
27254744Sdelphij/*
28254744Sdelphij * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
29254744Sdelphij */
30178525Sjb
31178525Sjb#include <sys/sysmacros.h>
32178525Sjb#include <sys/param.h>
33178525Sjb#include <sys/mman.h>
34178525Sjb#include <ctf_impl.h>
35254744Sdelphij#include <sys/debug.h>
36178525Sjb
37178525Sjb/*
38178525Sjb * This static string is used as the template for initially populating a
39178525Sjb * dynamic container's string table.  We always store \0 in the first byte,
40178525Sjb * and we use the generic string "PARENT" to mark this container's parent
41178525Sjb * if one is associated with the container using ctf_import().
42178525Sjb */
43178525Sjbstatic const char _CTF_STRTAB_TEMPLATE[] = "\0PARENT";
44178525Sjb
45178525Sjb/*
46178525Sjb * To create an empty CTF container, we just declare a zeroed header and call
47178525Sjb * ctf_bufopen() on it.  If ctf_bufopen succeeds, we mark the new container r/w
48178525Sjb * and initialize the dynamic members.  We set dtstrlen to 1 to reserve the
49178525Sjb * first byte of the string table for a \0 byte, and we start assigning type
50178525Sjb * IDs at 1 because type ID 0 is used as a sentinel.
51178525Sjb */
52178525Sjbctf_file_t *
53178525Sjbctf_create(int *errp)
54178525Sjb{
55178525Sjb	static const ctf_header_t hdr = { { CTF_MAGIC, CTF_VERSION, 0 } };
56178525Sjb
57178525Sjb	const ulong_t hashlen = 128;
58178525Sjb	ctf_dtdef_t **hash = ctf_alloc(hashlen * sizeof (ctf_dtdef_t *));
59178525Sjb	ctf_sect_t cts;
60178525Sjb	ctf_file_t *fp;
61178525Sjb
62178525Sjb	if (hash == NULL)
63178525Sjb		return (ctf_set_open_errno(errp, EAGAIN));
64178525Sjb
65178525Sjb	cts.cts_name = _CTF_SECTION;
66178525Sjb	cts.cts_type = SHT_PROGBITS;
67178525Sjb	cts.cts_flags = 0;
68257657Ssbruno	cts.cts_data = (void *)&hdr;
69178525Sjb	cts.cts_size = sizeof (hdr);
70178525Sjb	cts.cts_entsize = 1;
71178525Sjb	cts.cts_offset = 0;
72178525Sjb
73178525Sjb	if ((fp = ctf_bufopen(&cts, NULL, NULL, errp)) == NULL) {
74178525Sjb		ctf_free(hash, hashlen * sizeof (ctf_dtdef_t *));
75178525Sjb		return (NULL);
76178525Sjb	}
77178525Sjb
78178525Sjb	fp->ctf_flags |= LCTF_RDWR;
79178525Sjb	fp->ctf_dthashlen = hashlen;
80178525Sjb	bzero(hash, hashlen * sizeof (ctf_dtdef_t *));
81178525Sjb	fp->ctf_dthash = hash;
82178525Sjb	fp->ctf_dtstrlen = sizeof (_CTF_STRTAB_TEMPLATE);
83178525Sjb	fp->ctf_dtnextid = 1;
84178525Sjb	fp->ctf_dtoldid = 0;
85178525Sjb
86178525Sjb	return (fp);
87178525Sjb}
88178525Sjb
89178525Sjbstatic uchar_t *
90178525Sjbctf_copy_smembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t)
91178525Sjb{
92178525Sjb	ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
93178525Sjb	ctf_member_t ctm;
94178525Sjb
95178525Sjb	for (; dmd != NULL; dmd = ctf_list_next(dmd)) {
96178525Sjb		if (dmd->dmd_name) {
97178525Sjb			ctm.ctm_name = soff;
98178525Sjb			soff += strlen(dmd->dmd_name) + 1;
99178525Sjb		} else
100178525Sjb			ctm.ctm_name = 0;
101178525Sjb
102178525Sjb		ctm.ctm_type = (ushort_t)dmd->dmd_type;
103178525Sjb		ctm.ctm_offset = (ushort_t)dmd->dmd_offset;
104178525Sjb
105178525Sjb		bcopy(&ctm, t, sizeof (ctm));
106178525Sjb		t += sizeof (ctm);
107178525Sjb	}
108178525Sjb
109178525Sjb	return (t);
110178525Sjb}
111178525Sjb
112178525Sjbstatic uchar_t *
113178525Sjbctf_copy_lmembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t)
114178525Sjb{
115178525Sjb	ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
116178525Sjb	ctf_lmember_t ctlm;
117178525Sjb
118178525Sjb	for (; dmd != NULL; dmd = ctf_list_next(dmd)) {
119178525Sjb		if (dmd->dmd_name) {
120178525Sjb			ctlm.ctlm_name = soff;
121178525Sjb			soff += strlen(dmd->dmd_name) + 1;
122178525Sjb		} else
123178525Sjb			ctlm.ctlm_name = 0;
124178525Sjb
125178525Sjb		ctlm.ctlm_type = (ushort_t)dmd->dmd_type;
126178525Sjb		ctlm.ctlm_pad = 0;
127178525Sjb		ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI(dmd->dmd_offset);
128178525Sjb		ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO(dmd->dmd_offset);
129178525Sjb
130178525Sjb		bcopy(&ctlm, t, sizeof (ctlm));
131178525Sjb		t += sizeof (ctlm);
132178525Sjb	}
133178525Sjb
134178525Sjb	return (t);
135178525Sjb}
136178525Sjb
137178525Sjbstatic uchar_t *
138178525Sjbctf_copy_emembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t)
139178525Sjb{
140178525Sjb	ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
141178525Sjb	ctf_enum_t cte;
142178525Sjb
143178525Sjb	for (; dmd != NULL; dmd = ctf_list_next(dmd)) {
144178525Sjb		cte.cte_name = soff;
145178525Sjb		cte.cte_value = dmd->dmd_value;
146178525Sjb		soff += strlen(dmd->dmd_name) + 1;
147178525Sjb		bcopy(&cte, t, sizeof (cte));
148178525Sjb		t += sizeof (cte);
149178525Sjb	}
150178525Sjb
151178525Sjb	return (t);
152178525Sjb}
153178525Sjb
154178525Sjbstatic uchar_t *
155178525Sjbctf_copy_membnames(ctf_dtdef_t *dtd, uchar_t *s)
156178525Sjb{
157178525Sjb	ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
158178525Sjb	size_t len;
159178525Sjb
160178525Sjb	for (; dmd != NULL; dmd = ctf_list_next(dmd)) {
161178525Sjb		if (dmd->dmd_name == NULL)
162178525Sjb			continue; /* skip anonymous members */
163178525Sjb		len = strlen(dmd->dmd_name) + 1;
164178525Sjb		bcopy(dmd->dmd_name, s, len);
165178525Sjb		s += len;
166178525Sjb	}
167178525Sjb
168178525Sjb	return (s);
169178525Sjb}
170178525Sjb
171178525Sjb/*
172254744Sdelphij * Only types of dyanmic CTF containers contain reference counts. These
173254744Sdelphij * containers are marked RD/WR. Because of that we basically make this a no-op
174254744Sdelphij * for compatability with non-dynamic CTF sections. This is also a no-op for
175254744Sdelphij * types which are not dynamic types. It is the responsibility of the caller to
176254744Sdelphij * make sure it is a valid type. We help that caller out on debug builds.
177254744Sdelphij *
178254744Sdelphij * Note that the reference counts are not maintained for types that are not
179254744Sdelphij * within this container. In other words if we have a type in a parent, that
180254744Sdelphij * will not have its reference count increased. On the flip side, the parent
181254744Sdelphij * will not be allowed to remove dynamic types if it has children.
182254744Sdelphij */
183254744Sdelphijstatic void
184254744Sdelphijctf_ref_inc(ctf_file_t *fp, ctf_id_t tid)
185254744Sdelphij{
186254744Sdelphij	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid);
187254744Sdelphij
188254744Sdelphij	if (dtd == NULL)
189254744Sdelphij		return;
190254744Sdelphij
191254744Sdelphij	if (!(fp->ctf_flags & LCTF_RDWR))
192254744Sdelphij		return;
193254744Sdelphij
194254744Sdelphij	dtd->dtd_ref++;
195254744Sdelphij}
196254744Sdelphij
197254744Sdelphij/*
198254744Sdelphij * Just as with ctf_ref_inc, this is a no-op on non-writeable containers and the
199254744Sdelphij * caller should ensure that this is already a valid type.
200254744Sdelphij */
201254744Sdelphijstatic void
202254744Sdelphijctf_ref_dec(ctf_file_t *fp, ctf_id_t tid)
203254744Sdelphij{
204254744Sdelphij	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid);
205254744Sdelphij
206254744Sdelphij	if (dtd == NULL)
207254744Sdelphij		return;
208254744Sdelphij
209254744Sdelphij	if (!(fp->ctf_flags & LCTF_RDWR))
210254744Sdelphij		return;
211254744Sdelphij
212254744Sdelphij	ASSERT(dtd->dtd_ref >= 1);
213254744Sdelphij	dtd->dtd_ref--;
214254744Sdelphij}
215254744Sdelphij
216254744Sdelphij/*
217178525Sjb * If the specified CTF container is writable and has been modified, reload
218178525Sjb * this container with the updated type definitions.  In order to make this
219178525Sjb * code and the rest of libctf as simple as possible, we perform updates by
220178525Sjb * taking the dynamic type definitions and creating an in-memory CTF file
221178525Sjb * containing the definitions, and then call ctf_bufopen() on it.  This not
222178525Sjb * only leverages ctf_bufopen(), but also avoids having to bifurcate the rest
223178525Sjb * of the library code with different lookup paths for static and dynamic
224178525Sjb * type definitions.  We are therefore optimizing greatly for lookup over
225178525Sjb * update, which we assume will be an uncommon operation.  We perform one
226178525Sjb * extra trick here for the benefit of callers and to keep our code simple:
227178525Sjb * ctf_bufopen() will return a new ctf_file_t, but we want to keep the fp
228178525Sjb * constant for the caller, so after ctf_bufopen() returns, we use bcopy to
229178525Sjb * swap the interior of the old and new ctf_file_t's, and then free the old.
230254744Sdelphij *
231254744Sdelphij * Note that the lists of dynamic types stays around and the resulting container
232254744Sdelphij * is still writeable. Furthermore, the reference counts that are on the dtd's
233254744Sdelphij * are still valid.
234178525Sjb */
235178525Sjbint
236178525Sjbctf_update(ctf_file_t *fp)
237178525Sjb{
238178525Sjb	ctf_file_t ofp, *nfp;
239178525Sjb	ctf_header_t hdr;
240178525Sjb	ctf_dtdef_t *dtd;
241178525Sjb	ctf_sect_t cts;
242178525Sjb
243178525Sjb	uchar_t *s, *s0, *t;
244178525Sjb	size_t size;
245178525Sjb	void *buf;
246178525Sjb	int err;
247178525Sjb
248178525Sjb	if (!(fp->ctf_flags & LCTF_RDWR))
249178525Sjb		return (ctf_set_errno(fp, ECTF_RDONLY));
250178525Sjb
251178525Sjb	if (!(fp->ctf_flags & LCTF_DIRTY))
252178525Sjb		return (0); /* no update required */
253178525Sjb
254178525Sjb	/*
255178525Sjb	 * Fill in an initial CTF header.  We will leave the label, object,
256178525Sjb	 * and function sections empty and only output a header, type section,
257178525Sjb	 * and string table.  The type section begins at a 4-byte aligned
258178525Sjb	 * boundary past the CTF header itself (at relative offset zero).
259178525Sjb	 */
260178525Sjb	bzero(&hdr, sizeof (hdr));
261178525Sjb	hdr.cth_magic = CTF_MAGIC;
262178525Sjb	hdr.cth_version = CTF_VERSION;
263178525Sjb
264178525Sjb	if (fp->ctf_flags & LCTF_CHILD)
265178525Sjb		hdr.cth_parname = 1; /* i.e. _CTF_STRTAB_TEMPLATE[1] */
266178525Sjb
267178525Sjb	/*
268178525Sjb	 * Iterate through the dynamic type definition list and compute the
269178525Sjb	 * size of the CTF type section we will need to generate.
270178525Sjb	 */
271178525Sjb	for (size = 0, dtd = ctf_list_next(&fp->ctf_dtdefs);
272178525Sjb	    dtd != NULL; dtd = ctf_list_next(dtd)) {
273178525Sjb
274178525Sjb		uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
275178525Sjb		uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info);
276178525Sjb
277178525Sjb		if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
278178525Sjb			size += sizeof (ctf_stype_t);
279178525Sjb		else
280178525Sjb			size += sizeof (ctf_type_t);
281178525Sjb
282178525Sjb		switch (kind) {
283178525Sjb		case CTF_K_INTEGER:
284178525Sjb		case CTF_K_FLOAT:
285178525Sjb			size += sizeof (uint_t);
286178525Sjb			break;
287178525Sjb		case CTF_K_ARRAY:
288178525Sjb			size += sizeof (ctf_array_t);
289178525Sjb			break;
290178525Sjb		case CTF_K_FUNCTION:
291178525Sjb			size += sizeof (ushort_t) * (vlen + (vlen & 1));
292178525Sjb			break;
293178525Sjb		case CTF_K_STRUCT:
294178525Sjb		case CTF_K_UNION:
295178525Sjb			if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
296178525Sjb				size += sizeof (ctf_member_t) * vlen;
297178525Sjb			else
298178525Sjb				size += sizeof (ctf_lmember_t) * vlen;
299178525Sjb			break;
300178525Sjb		case CTF_K_ENUM:
301178525Sjb			size += sizeof (ctf_enum_t) * vlen;
302178525Sjb			break;
303178525Sjb		}
304178525Sjb	}
305178525Sjb
306178525Sjb	/*
307178525Sjb	 * Fill in the string table offset and size, compute the size of the
308178525Sjb	 * entire CTF buffer we need, and then allocate a new buffer and
309178525Sjb	 * bcopy the finished header to the start of the buffer.
310178525Sjb	 */
311178525Sjb	hdr.cth_stroff = hdr.cth_typeoff + size;
312178525Sjb	hdr.cth_strlen = fp->ctf_dtstrlen;
313178525Sjb	size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
314178525Sjb
315178525Sjb	if ((buf = ctf_data_alloc(size)) == MAP_FAILED)
316178525Sjb		return (ctf_set_errno(fp, EAGAIN));
317178525Sjb
318178525Sjb	bcopy(&hdr, buf, sizeof (ctf_header_t));
319178525Sjb	t = (uchar_t *)buf + sizeof (ctf_header_t);
320178525Sjb	s = s0 = (uchar_t *)buf + sizeof (ctf_header_t) + hdr.cth_stroff;
321178525Sjb
322178525Sjb	bcopy(_CTF_STRTAB_TEMPLATE, s, sizeof (_CTF_STRTAB_TEMPLATE));
323178525Sjb	s += sizeof (_CTF_STRTAB_TEMPLATE);
324178525Sjb
325178525Sjb	/*
326178525Sjb	 * We now take a final lap through the dynamic type definition list and
327178525Sjb	 * copy the appropriate type records and strings to the output buffer.
328178525Sjb	 */
329178525Sjb	for (dtd = ctf_list_next(&fp->ctf_dtdefs);
330178525Sjb	    dtd != NULL; dtd = ctf_list_next(dtd)) {
331178525Sjb
332178525Sjb		uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
333178525Sjb		uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info);
334178525Sjb
335178525Sjb		ctf_array_t cta;
336178525Sjb		uint_t encoding;
337178525Sjb		size_t len;
338178525Sjb
339178525Sjb		if (dtd->dtd_name != NULL) {
340178525Sjb			dtd->dtd_data.ctt_name = (uint_t)(s - s0);
341178525Sjb			len = strlen(dtd->dtd_name) + 1;
342178525Sjb			bcopy(dtd->dtd_name, s, len);
343178525Sjb			s += len;
344178525Sjb		} else
345178525Sjb			dtd->dtd_data.ctt_name = 0;
346178525Sjb
347178525Sjb		if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
348178525Sjb			len = sizeof (ctf_stype_t);
349178525Sjb		else
350178525Sjb			len = sizeof (ctf_type_t);
351178525Sjb
352178525Sjb		bcopy(&dtd->dtd_data, t, len);
353178525Sjb		t += len;
354178525Sjb
355178525Sjb		switch (kind) {
356178525Sjb		case CTF_K_INTEGER:
357178525Sjb		case CTF_K_FLOAT:
358178525Sjb			if (kind == CTF_K_INTEGER) {
359178525Sjb				encoding = CTF_INT_DATA(
360178525Sjb				    dtd->dtd_u.dtu_enc.cte_format,
361178525Sjb				    dtd->dtd_u.dtu_enc.cte_offset,
362178525Sjb				    dtd->dtd_u.dtu_enc.cte_bits);
363178525Sjb			} else {
364178525Sjb				encoding = CTF_FP_DATA(
365178525Sjb				    dtd->dtd_u.dtu_enc.cte_format,
366178525Sjb				    dtd->dtd_u.dtu_enc.cte_offset,
367178525Sjb				    dtd->dtd_u.dtu_enc.cte_bits);
368178525Sjb			}
369178525Sjb			bcopy(&encoding, t, sizeof (encoding));
370178525Sjb			t += sizeof (encoding);
371178525Sjb			break;
372178525Sjb
373178525Sjb		case CTF_K_ARRAY:
374178525Sjb			cta.cta_contents = (ushort_t)
375178525Sjb			    dtd->dtd_u.dtu_arr.ctr_contents;
376178525Sjb			cta.cta_index = (ushort_t)
377178525Sjb			    dtd->dtd_u.dtu_arr.ctr_index;
378178525Sjb			cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems;
379178525Sjb			bcopy(&cta, t, sizeof (cta));
380178525Sjb			t += sizeof (cta);
381178525Sjb			break;
382178525Sjb
383178525Sjb		case CTF_K_FUNCTION: {
384178525Sjb			ushort_t *argv = (ushort_t *)(uintptr_t)t;
385178525Sjb			uint_t argc;
386178525Sjb
387178525Sjb			for (argc = 0; argc < vlen; argc++)
388178525Sjb				*argv++ = (ushort_t)dtd->dtd_u.dtu_argv[argc];
389178525Sjb
390178525Sjb			if (vlen & 1)
391178525Sjb				*argv++ = 0; /* pad to 4-byte boundary */
392178525Sjb
393178525Sjb			t = (uchar_t *)argv;
394178525Sjb			break;
395178525Sjb		}
396178525Sjb
397178525Sjb		case CTF_K_STRUCT:
398178525Sjb		case CTF_K_UNION:
399178525Sjb			if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
400178525Sjb				t = ctf_copy_smembers(dtd, (uint_t)(s - s0), t);
401178525Sjb			else
402178525Sjb				t = ctf_copy_lmembers(dtd, (uint_t)(s - s0), t);
403178525Sjb			s = ctf_copy_membnames(dtd, s);
404178525Sjb			break;
405178525Sjb
406178525Sjb		case CTF_K_ENUM:
407178525Sjb			t = ctf_copy_emembers(dtd, (uint_t)(s - s0), t);
408178525Sjb			s = ctf_copy_membnames(dtd, s);
409178525Sjb			break;
410178525Sjb		}
411178525Sjb	}
412178525Sjb
413178525Sjb	/*
414178525Sjb	 * Finally, we are ready to ctf_bufopen() the new container.  If this
415178525Sjb	 * is successful, we then switch nfp and fp and free the old container.
416178525Sjb	 */
417178525Sjb	ctf_data_protect(buf, size);
418178525Sjb	cts.cts_name = _CTF_SECTION;
419178525Sjb	cts.cts_type = SHT_PROGBITS;
420178525Sjb	cts.cts_flags = 0;
421178525Sjb	cts.cts_data = buf;
422178525Sjb	cts.cts_size = size;
423178525Sjb	cts.cts_entsize = 1;
424178525Sjb	cts.cts_offset = 0;
425178525Sjb
426178525Sjb	if ((nfp = ctf_bufopen(&cts, NULL, NULL, &err)) == NULL) {
427178525Sjb		ctf_data_free(buf, size);
428178525Sjb		return (ctf_set_errno(fp, err));
429178525Sjb	}
430178525Sjb
431178525Sjb	(void) ctf_setmodel(nfp, ctf_getmodel(fp));
432178525Sjb	(void) ctf_import(nfp, fp->ctf_parent);
433178525Sjb
434178525Sjb	nfp->ctf_refcnt = fp->ctf_refcnt;
435178525Sjb	nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY;
436178525Sjb	nfp->ctf_data.cts_data = NULL; /* force ctf_data_free() on close */
437178525Sjb	nfp->ctf_dthash = fp->ctf_dthash;
438178525Sjb	nfp->ctf_dthashlen = fp->ctf_dthashlen;
439178525Sjb	nfp->ctf_dtdefs = fp->ctf_dtdefs;
440178525Sjb	nfp->ctf_dtstrlen = fp->ctf_dtstrlen;
441178525Sjb	nfp->ctf_dtnextid = fp->ctf_dtnextid;
442178525Sjb	nfp->ctf_dtoldid = fp->ctf_dtnextid - 1;
443178525Sjb	nfp->ctf_specific = fp->ctf_specific;
444178525Sjb
445178525Sjb	fp->ctf_dthash = NULL;
446178525Sjb	fp->ctf_dthashlen = 0;
447178525Sjb	bzero(&fp->ctf_dtdefs, sizeof (ctf_list_t));
448178525Sjb
449178525Sjb	bcopy(fp, &ofp, sizeof (ctf_file_t));
450178525Sjb	bcopy(nfp, fp, sizeof (ctf_file_t));
451178525Sjb	bcopy(&ofp, nfp, sizeof (ctf_file_t));
452178525Sjb
453178525Sjb	/*
454178525Sjb	 * Initialize the ctf_lookup_by_name top-level dictionary.  We keep an
455178525Sjb	 * array of type name prefixes and the corresponding ctf_hash to use.
456178525Sjb	 * NOTE: This code must be kept in sync with the code in ctf_bufopen().
457178525Sjb	 */
458178525Sjb	fp->ctf_lookups[0].ctl_hash = &fp->ctf_structs;
459178525Sjb	fp->ctf_lookups[1].ctl_hash = &fp->ctf_unions;
460178525Sjb	fp->ctf_lookups[2].ctl_hash = &fp->ctf_enums;
461178525Sjb	fp->ctf_lookups[3].ctl_hash = &fp->ctf_names;
462178525Sjb
463178525Sjb	nfp->ctf_refcnt = 1; /* force nfp to be freed */
464178525Sjb	ctf_close(nfp);
465178525Sjb
466178525Sjb	return (0);
467178525Sjb}
468178525Sjb
469178525Sjbvoid
470178525Sjbctf_dtd_insert(ctf_file_t *fp, ctf_dtdef_t *dtd)
471178525Sjb{
472178525Sjb	ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1);
473178525Sjb
474178525Sjb	dtd->dtd_hash = fp->ctf_dthash[h];
475178525Sjb	fp->ctf_dthash[h] = dtd;
476178525Sjb	ctf_list_append(&fp->ctf_dtdefs, dtd);
477178525Sjb}
478178525Sjb
479178525Sjbvoid
480178525Sjbctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd)
481178525Sjb{
482178525Sjb	ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1);
483178525Sjb	ctf_dtdef_t *p, **q = &fp->ctf_dthash[h];
484178525Sjb	ctf_dmdef_t *dmd, *nmd;
485178525Sjb	size_t len;
486254744Sdelphij	int kind, i;
487178525Sjb
488178525Sjb	for (p = *q; p != NULL; p = p->dtd_hash) {
489178525Sjb		if (p != dtd)
490178525Sjb			q = &p->dtd_hash;
491178525Sjb		else
492178525Sjb			break;
493178525Sjb	}
494178525Sjb
495178525Sjb	if (p != NULL)
496178525Sjb		*q = p->dtd_hash;
497178525Sjb
498254744Sdelphij	kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
499254744Sdelphij	switch (kind) {
500178525Sjb	case CTF_K_STRUCT:
501178525Sjb	case CTF_K_UNION:
502178525Sjb	case CTF_K_ENUM:
503178525Sjb		for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
504178525Sjb		    dmd != NULL; dmd = nmd) {
505178525Sjb			if (dmd->dmd_name != NULL) {
506178525Sjb				len = strlen(dmd->dmd_name) + 1;
507178525Sjb				ctf_free(dmd->dmd_name, len);
508178525Sjb				fp->ctf_dtstrlen -= len;
509178525Sjb			}
510254744Sdelphij			if (kind != CTF_K_ENUM)
511254744Sdelphij				ctf_ref_dec(fp, dmd->dmd_type);
512178525Sjb			nmd = ctf_list_next(dmd);
513178525Sjb			ctf_free(dmd, sizeof (ctf_dmdef_t));
514178525Sjb		}
515178525Sjb		break;
516178525Sjb	case CTF_K_FUNCTION:
517254744Sdelphij		ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
518254744Sdelphij		for (i = 0; i < CTF_INFO_VLEN(dtd->dtd_data.ctt_info); i++)
519254744Sdelphij			if (dtd->dtd_u.dtu_argv[i] != 0)
520254744Sdelphij				ctf_ref_dec(fp, dtd->dtd_u.dtu_argv[i]);
521178525Sjb		ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) *
522178525Sjb		    CTF_INFO_VLEN(dtd->dtd_data.ctt_info));
523178525Sjb		break;
524254744Sdelphij	case CTF_K_ARRAY:
525254744Sdelphij		ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents);
526254744Sdelphij		ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index);
527254744Sdelphij		break;
528254744Sdelphij	case CTF_K_TYPEDEF:
529254744Sdelphij		ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
530254744Sdelphij		break;
531254744Sdelphij	case CTF_K_POINTER:
532254744Sdelphij	case CTF_K_VOLATILE:
533254744Sdelphij	case CTF_K_CONST:
534254744Sdelphij	case CTF_K_RESTRICT:
535254744Sdelphij		ctf_ref_dec(fp, dtd->dtd_data.ctt_type);
536254744Sdelphij		break;
537178525Sjb	}
538178525Sjb
539178525Sjb	if (dtd->dtd_name) {
540178525Sjb		len = strlen(dtd->dtd_name) + 1;
541178525Sjb		ctf_free(dtd->dtd_name, len);
542178525Sjb		fp->ctf_dtstrlen -= len;
543178525Sjb	}
544178525Sjb
545178525Sjb	ctf_list_delete(&fp->ctf_dtdefs, dtd);
546178525Sjb	ctf_free(dtd, sizeof (ctf_dtdef_t));
547178525Sjb}
548178525Sjb
549178525Sjbctf_dtdef_t *
550178525Sjbctf_dtd_lookup(ctf_file_t *fp, ctf_id_t type)
551178525Sjb{
552178525Sjb	ulong_t h = type & (fp->ctf_dthashlen - 1);
553178525Sjb	ctf_dtdef_t *dtd;
554178525Sjb
555178525Sjb	if (fp->ctf_dthash == NULL)
556178525Sjb		return (NULL);
557178525Sjb
558178525Sjb	for (dtd = fp->ctf_dthash[h]; dtd != NULL; dtd = dtd->dtd_hash) {
559178525Sjb		if (dtd->dtd_type == type)
560178525Sjb			break;
561178525Sjb	}
562178525Sjb
563178525Sjb	return (dtd);
564178525Sjb}
565178525Sjb
566178525Sjb/*
567178525Sjb * Discard all of the dynamic type definitions that have been added to the
568178525Sjb * container since the last call to ctf_update().  We locate such types by
569178525Sjb * scanning the list and deleting elements that have type IDs greater than
570254744Sdelphij * ctf_dtoldid, which is set by ctf_update(), above. Note that to work properly
571254744Sdelphij * with our reference counting schemes, we must delete the dynamic list in
572254744Sdelphij * reverse.
573178525Sjb */
574178525Sjbint
575178525Sjbctf_discard(ctf_file_t *fp)
576178525Sjb{
577178525Sjb	ctf_dtdef_t *dtd, *ntd;
578178525Sjb
579178525Sjb	if (!(fp->ctf_flags & LCTF_RDWR))
580178525Sjb		return (ctf_set_errno(fp, ECTF_RDONLY));
581178525Sjb
582178525Sjb	if (!(fp->ctf_flags & LCTF_DIRTY))
583178525Sjb		return (0); /* no update required */
584178525Sjb
585254744Sdelphij	for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
586279862Smarkj		ntd = ctf_list_prev(dtd);
587279864Smarkj		if (CTF_TYPE_TO_INDEX(dtd->dtd_type) <= fp->ctf_dtoldid)
588178525Sjb			continue; /* skip types that have been committed */
589178525Sjb
590178525Sjb		ctf_dtd_delete(fp, dtd);
591178525Sjb	}
592178525Sjb
593178525Sjb	fp->ctf_dtnextid = fp->ctf_dtoldid + 1;
594178525Sjb	fp->ctf_flags &= ~LCTF_DIRTY;
595178525Sjb
596178525Sjb	return (0);
597178525Sjb}
598178525Sjb
599178525Sjbstatic ctf_id_t
600178525Sjbctf_add_generic(ctf_file_t *fp, uint_t flag, const char *name, ctf_dtdef_t **rp)
601178525Sjb{
602178525Sjb	ctf_dtdef_t *dtd;
603178525Sjb	ctf_id_t type;
604178525Sjb	char *s = NULL;
605178525Sjb
606178525Sjb	if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)
607178525Sjb		return (ctf_set_errno(fp, EINVAL));
608178525Sjb
609178525Sjb	if (!(fp->ctf_flags & LCTF_RDWR))
610178525Sjb		return (ctf_set_errno(fp, ECTF_RDONLY));
611178525Sjb
612178525Sjb	if (CTF_INDEX_TO_TYPE(fp->ctf_dtnextid, 1) > CTF_MAX_TYPE)
613178525Sjb		return (ctf_set_errno(fp, ECTF_FULL));
614178525Sjb
615178525Sjb	if ((dtd = ctf_alloc(sizeof (ctf_dtdef_t))) == NULL)
616178525Sjb		return (ctf_set_errno(fp, EAGAIN));
617178525Sjb
618178525Sjb	if (name != NULL && (s = ctf_strdup(name)) == NULL) {
619178525Sjb		ctf_free(dtd, sizeof (ctf_dtdef_t));
620178525Sjb		return (ctf_set_errno(fp, EAGAIN));
621178525Sjb	}
622178525Sjb
623178525Sjb	type = fp->ctf_dtnextid++;
624178525Sjb	type = CTF_INDEX_TO_TYPE(type, (fp->ctf_flags & LCTF_CHILD));
625178525Sjb
626178525Sjb	bzero(dtd, sizeof (ctf_dtdef_t));
627178525Sjb	dtd->dtd_name = s;
628178525Sjb	dtd->dtd_type = type;
629178525Sjb
630178525Sjb	if (s != NULL)
631178525Sjb		fp->ctf_dtstrlen += strlen(s) + 1;
632178525Sjb
633178525Sjb	ctf_dtd_insert(fp, dtd);
634178525Sjb	fp->ctf_flags |= LCTF_DIRTY;
635178525Sjb
636178525Sjb	*rp = dtd;
637178525Sjb	return (type);
638178525Sjb}
639178525Sjb
640178525Sjb/*
641178525Sjb * When encoding integer sizes, we want to convert a byte count in the range
642178525Sjb * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc).  The clp2() function
643178525Sjb * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr.
644178525Sjb */
645178525Sjbstatic size_t
646178525Sjbclp2(size_t x)
647178525Sjb{
648178525Sjb	x--;
649178525Sjb
650178525Sjb	x |= (x >> 1);
651178525Sjb	x |= (x >> 2);
652178525Sjb	x |= (x >> 4);
653178525Sjb	x |= (x >> 8);
654178525Sjb	x |= (x >> 16);
655178525Sjb
656178525Sjb	return (x + 1);
657178525Sjb}
658178525Sjb
659178525Sjbstatic ctf_id_t
660178525Sjbctf_add_encoded(ctf_file_t *fp, uint_t flag,
661178525Sjb    const char *name, const ctf_encoding_t *ep, uint_t kind)
662178525Sjb{
663178525Sjb	ctf_dtdef_t *dtd;
664178525Sjb	ctf_id_t type;
665178525Sjb
666178525Sjb	if (ep == NULL)
667178525Sjb		return (ctf_set_errno(fp, EINVAL));
668178525Sjb
669178525Sjb	if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
670178525Sjb		return (CTF_ERR); /* errno is set for us */
671178525Sjb
672178525Sjb	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0);
673178525Sjb	dtd->dtd_data.ctt_size = clp2(P2ROUNDUP(ep->cte_bits, NBBY) / NBBY);
674178525Sjb	dtd->dtd_u.dtu_enc = *ep;
675178525Sjb
676178525Sjb	return (type);
677178525Sjb}
678178525Sjb
679178525Sjbstatic ctf_id_t
680178525Sjbctf_add_reftype(ctf_file_t *fp, uint_t flag, ctf_id_t ref, uint_t kind)
681178525Sjb{
682178525Sjb	ctf_dtdef_t *dtd;
683178525Sjb	ctf_id_t type;
684178525Sjb
685178525Sjb	if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE)
686178525Sjb		return (ctf_set_errno(fp, EINVAL));
687178525Sjb
688178525Sjb	if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR)
689178525Sjb		return (CTF_ERR); /* errno is set for us */
690178525Sjb
691254744Sdelphij	ctf_ref_inc(fp, ref);
692254744Sdelphij
693178525Sjb	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0);
694178525Sjb	dtd->dtd_data.ctt_type = (ushort_t)ref;
695178525Sjb
696178525Sjb	return (type);
697178525Sjb}
698178525Sjb
699178525Sjbctf_id_t
700178525Sjbctf_add_integer(ctf_file_t *fp, uint_t flag,
701178525Sjb    const char *name, const ctf_encoding_t *ep)
702178525Sjb{
703178525Sjb	return (ctf_add_encoded(fp, flag, name, ep, CTF_K_INTEGER));
704178525Sjb}
705178525Sjb
706178525Sjbctf_id_t
707178525Sjbctf_add_float(ctf_file_t *fp, uint_t flag,
708178525Sjb    const char *name, const ctf_encoding_t *ep)
709178525Sjb{
710178525Sjb	return (ctf_add_encoded(fp, flag, name, ep, CTF_K_FLOAT));
711178525Sjb}
712178525Sjb
713178525Sjbctf_id_t
714178525Sjbctf_add_pointer(ctf_file_t *fp, uint_t flag, ctf_id_t ref)
715178525Sjb{
716178525Sjb	return (ctf_add_reftype(fp, flag, ref, CTF_K_POINTER));
717178525Sjb}
718178525Sjb
719178525Sjbctf_id_t
720178525Sjbctf_add_array(ctf_file_t *fp, uint_t flag, const ctf_arinfo_t *arp)
721178525Sjb{
722178525Sjb	ctf_dtdef_t *dtd;
723178525Sjb	ctf_id_t type;
724254744Sdelphij	ctf_file_t *fpd;
725178525Sjb
726178525Sjb	if (arp == NULL)
727178525Sjb		return (ctf_set_errno(fp, EINVAL));
728178525Sjb
729254744Sdelphij	fpd = fp;
730254744Sdelphij	if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL &&
731254744Sdelphij	    ctf_dtd_lookup(fp, arp->ctr_contents) == NULL)
732254744Sdelphij		return (ctf_set_errno(fp, ECTF_BADID));
733254744Sdelphij
734254744Sdelphij	fpd = fp;
735254744Sdelphij	if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL &&
736254744Sdelphij	    ctf_dtd_lookup(fp, arp->ctr_index) == NULL)
737254744Sdelphij		return (ctf_set_errno(fp, ECTF_BADID));
738254744Sdelphij
739178525Sjb	if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR)
740178525Sjb		return (CTF_ERR); /* errno is set for us */
741178525Sjb
742178525Sjb	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, flag, 0);
743178525Sjb	dtd->dtd_data.ctt_size = 0;
744178525Sjb	dtd->dtd_u.dtu_arr = *arp;
745254744Sdelphij	ctf_ref_inc(fp, arp->ctr_contents);
746254744Sdelphij	ctf_ref_inc(fp, arp->ctr_index);
747178525Sjb
748178525Sjb	return (type);
749178525Sjb}
750178525Sjb
751178525Sjbint
752178525Sjbctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
753178525Sjb{
754254744Sdelphij	ctf_file_t *fpd;
755178525Sjb	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type);
756178525Sjb
757178525Sjb	if (!(fp->ctf_flags & LCTF_RDWR))
758178525Sjb		return (ctf_set_errno(fp, ECTF_RDONLY));
759178525Sjb
760178525Sjb	if (dtd == NULL || CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
761178525Sjb		return (ctf_set_errno(fp, ECTF_BADID));
762178525Sjb
763254744Sdelphij	fpd = fp;
764254744Sdelphij	if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL &&
765254744Sdelphij	    ctf_dtd_lookup(fp, arp->ctr_contents) == NULL)
766254744Sdelphij		return (ctf_set_errno(fp, ECTF_BADID));
767254744Sdelphij
768254744Sdelphij	fpd = fp;
769254744Sdelphij	if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL &&
770254744Sdelphij	    ctf_dtd_lookup(fp, arp->ctr_index) == NULL)
771254744Sdelphij		return (ctf_set_errno(fp, ECTF_BADID));
772254744Sdelphij
773254744Sdelphij	ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents);
774254744Sdelphij	ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index);
775178525Sjb	fp->ctf_flags |= LCTF_DIRTY;
776178525Sjb	dtd->dtd_u.dtu_arr = *arp;
777254744Sdelphij	ctf_ref_inc(fp, arp->ctr_contents);
778254744Sdelphij	ctf_ref_inc(fp, arp->ctr_index);
779178525Sjb
780178525Sjb	return (0);
781178525Sjb}
782178525Sjb
783178525Sjbctf_id_t
784178525Sjbctf_add_function(ctf_file_t *fp, uint_t flag,
785178525Sjb    const ctf_funcinfo_t *ctc, const ctf_id_t *argv)
786178525Sjb{
787178525Sjb	ctf_dtdef_t *dtd;
788178525Sjb	ctf_id_t type;
789178525Sjb	uint_t vlen;
790254744Sdelphij	int i;
791178525Sjb	ctf_id_t *vdat = NULL;
792254744Sdelphij	ctf_file_t *fpd;
793178525Sjb
794178525Sjb	if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0 ||
795178525Sjb	    (ctc->ctc_argc != 0 && argv == NULL))
796178525Sjb		return (ctf_set_errno(fp, EINVAL));
797178525Sjb
798178525Sjb	vlen = ctc->ctc_argc;
799178525Sjb	if (ctc->ctc_flags & CTF_FUNC_VARARG)
800178525Sjb		vlen++; /* add trailing zero to indicate varargs (see below) */
801178525Sjb
802178525Sjb	if (vlen > CTF_MAX_VLEN)
803178525Sjb		return (ctf_set_errno(fp, EOVERFLOW));
804178525Sjb
805254744Sdelphij	fpd = fp;
806254744Sdelphij	if (ctf_lookup_by_id(&fpd, ctc->ctc_return) == NULL &&
807254744Sdelphij	    ctf_dtd_lookup(fp, ctc->ctc_return) == NULL)
808254744Sdelphij		return (ctf_set_errno(fp, ECTF_BADID));
809254744Sdelphij
810254744Sdelphij	for (i = 0; i < ctc->ctc_argc; i++) {
811254744Sdelphij		fpd = fp;
812254744Sdelphij		if (ctf_lookup_by_id(&fpd, argv[i]) == NULL &&
813254744Sdelphij		    ctf_dtd_lookup(fp, argv[i]) == NULL)
814254744Sdelphij			return (ctf_set_errno(fp, ECTF_BADID));
815254744Sdelphij	}
816254744Sdelphij
817178525Sjb	if (vlen != 0 && (vdat = ctf_alloc(sizeof (ctf_id_t) * vlen)) == NULL)
818178525Sjb		return (ctf_set_errno(fp, EAGAIN));
819178525Sjb
820178525Sjb	if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) {
821178525Sjb		ctf_free(vdat, sizeof (ctf_id_t) * vlen);
822178525Sjb		return (CTF_ERR); /* errno is set for us */
823178525Sjb	}
824178525Sjb
825178525Sjb	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, flag, vlen);
826178525Sjb	dtd->dtd_data.ctt_type = (ushort_t)ctc->ctc_return;
827178525Sjb
828254744Sdelphij	ctf_ref_inc(fp, ctc->ctc_return);
829254744Sdelphij	for (i = 0; i < ctc->ctc_argc; i++)
830254744Sdelphij		ctf_ref_inc(fp, argv[i]);
831254744Sdelphij
832178525Sjb	bcopy(argv, vdat, sizeof (ctf_id_t) * ctc->ctc_argc);
833178525Sjb	if (ctc->ctc_flags & CTF_FUNC_VARARG)
834178525Sjb		vdat[vlen - 1] = 0; /* add trailing zero to indicate varargs */
835178525Sjb	dtd->dtd_u.dtu_argv = vdat;
836178525Sjb
837178525Sjb	return (type);
838178525Sjb}
839178525Sjb
840178525Sjbctf_id_t
841178525Sjbctf_add_struct(ctf_file_t *fp, uint_t flag, const char *name)
842178525Sjb{
843178525Sjb	ctf_hash_t *hp = &fp->ctf_structs;
844178525Sjb	ctf_helem_t *hep = NULL;
845178525Sjb	ctf_dtdef_t *dtd;
846178525Sjb	ctf_id_t type;
847178525Sjb
848178525Sjb	if (name != NULL)
849178525Sjb		hep = ctf_hash_lookup(hp, fp, name, strlen(name));
850178525Sjb
851178525Sjb	if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD)
852178525Sjb		dtd = ctf_dtd_lookup(fp, type = hep->h_type);
853178525Sjb	else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
854178525Sjb		return (CTF_ERR); /* errno is set for us */
855178525Sjb
856178525Sjb	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_STRUCT, flag, 0);
857178525Sjb	dtd->dtd_data.ctt_size = 0;
858178525Sjb
859178525Sjb	return (type);
860178525Sjb}
861178525Sjb
862178525Sjbctf_id_t
863178525Sjbctf_add_union(ctf_file_t *fp, uint_t flag, const char *name)
864178525Sjb{
865178525Sjb	ctf_hash_t *hp = &fp->ctf_unions;
866178525Sjb	ctf_helem_t *hep = NULL;
867178525Sjb	ctf_dtdef_t *dtd;
868178525Sjb	ctf_id_t type;
869178525Sjb
870178525Sjb	if (name != NULL)
871178525Sjb		hep = ctf_hash_lookup(hp, fp, name, strlen(name));
872178525Sjb
873178525Sjb	if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD)
874178525Sjb		dtd = ctf_dtd_lookup(fp, type = hep->h_type);
875178525Sjb	else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
876178525Sjb		return (CTF_ERR); /* errno is set for us */
877178525Sjb
878178525Sjb	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_UNION, flag, 0);
879178525Sjb	dtd->dtd_data.ctt_size = 0;
880178525Sjb
881178525Sjb	return (type);
882178525Sjb}
883178525Sjb
884178525Sjbctf_id_t
885178525Sjbctf_add_enum(ctf_file_t *fp, uint_t flag, const char *name)
886178525Sjb{
887178525Sjb	ctf_hash_t *hp = &fp->ctf_enums;
888178525Sjb	ctf_helem_t *hep = NULL;
889178525Sjb	ctf_dtdef_t *dtd;
890178525Sjb	ctf_id_t type;
891178525Sjb
892178525Sjb	if (name != NULL)
893178525Sjb		hep = ctf_hash_lookup(hp, fp, name, strlen(name));
894178525Sjb
895178525Sjb	if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD)
896178525Sjb		dtd = ctf_dtd_lookup(fp, type = hep->h_type);
897178525Sjb	else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
898178525Sjb		return (CTF_ERR); /* errno is set for us */
899178525Sjb
900178525Sjb	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ENUM, flag, 0);
901178525Sjb	dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int;
902178525Sjb
903178525Sjb	return (type);
904178525Sjb}
905178525Sjb
906178525Sjbctf_id_t
907178525Sjbctf_add_forward(ctf_file_t *fp, uint_t flag, const char *name, uint_t kind)
908178525Sjb{
909178525Sjb	ctf_hash_t *hp;
910178525Sjb	ctf_helem_t *hep;
911178525Sjb	ctf_dtdef_t *dtd;
912178525Sjb	ctf_id_t type;
913178525Sjb
914178525Sjb	switch (kind) {
915178525Sjb	case CTF_K_STRUCT:
916178525Sjb		hp = &fp->ctf_structs;
917178525Sjb		break;
918178525Sjb	case CTF_K_UNION:
919178525Sjb		hp = &fp->ctf_unions;
920178525Sjb		break;
921178525Sjb	case CTF_K_ENUM:
922178525Sjb		hp = &fp->ctf_enums;
923178525Sjb		break;
924178525Sjb	default:
925178525Sjb		return (ctf_set_errno(fp, ECTF_NOTSUE));
926178525Sjb	}
927178525Sjb
928178525Sjb	/*
929178525Sjb	 * If the type is already defined or exists as a forward tag, just
930178525Sjb	 * return the ctf_id_t of the existing definition.
931178525Sjb	 */
932178525Sjb	if (name != NULL && (hep = ctf_hash_lookup(hp,
933178525Sjb	    fp, name, strlen(name))) != NULL)
934178525Sjb		return (hep->h_type);
935178525Sjb
936178525Sjb	if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
937178525Sjb		return (CTF_ERR); /* errno is set for us */
938178525Sjb
939178525Sjb	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FORWARD, flag, 0);
940178525Sjb	dtd->dtd_data.ctt_type = kind;
941178525Sjb
942178525Sjb	return (type);
943178525Sjb}
944178525Sjb
945178525Sjbctf_id_t
946178525Sjbctf_add_typedef(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref)
947178525Sjb{
948178525Sjb	ctf_dtdef_t *dtd;
949178525Sjb	ctf_id_t type;
950254744Sdelphij	ctf_file_t *fpd;
951178525Sjb
952254744Sdelphij	fpd = fp;
953254744Sdelphij	if (ref == CTF_ERR || (ctf_lookup_by_id(&fpd, ref) == NULL &&
954254744Sdelphij	    ctf_dtd_lookup(fp, ref) == NULL))
955178525Sjb		return (ctf_set_errno(fp, EINVAL));
956178525Sjb
957178525Sjb	if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR)
958178525Sjb		return (CTF_ERR); /* errno is set for us */
959178525Sjb
960178525Sjb	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, flag, 0);
961178525Sjb	dtd->dtd_data.ctt_type = (ushort_t)ref;
962254744Sdelphij	ctf_ref_inc(fp, ref);
963178525Sjb
964178525Sjb	return (type);
965178525Sjb}
966178525Sjb
967178525Sjbctf_id_t
968178525Sjbctf_add_volatile(ctf_file_t *fp, uint_t flag, ctf_id_t ref)
969178525Sjb{
970178525Sjb	return (ctf_add_reftype(fp, flag, ref, CTF_K_VOLATILE));
971178525Sjb}
972178525Sjb
973178525Sjbctf_id_t
974178525Sjbctf_add_const(ctf_file_t *fp, uint_t flag, ctf_id_t ref)
975178525Sjb{
976178525Sjb	return (ctf_add_reftype(fp, flag, ref, CTF_K_CONST));
977178525Sjb}
978178525Sjb
979178525Sjbctf_id_t
980178525Sjbctf_add_restrict(ctf_file_t *fp, uint_t flag, ctf_id_t ref)
981178525Sjb{
982178525Sjb	return (ctf_add_reftype(fp, flag, ref, CTF_K_RESTRICT));
983178525Sjb}
984178525Sjb
985178525Sjbint
986178525Sjbctf_add_enumerator(ctf_file_t *fp, ctf_id_t enid, const char *name, int value)
987178525Sjb{
988178525Sjb	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, enid);
989178525Sjb	ctf_dmdef_t *dmd;
990178525Sjb
991178525Sjb	uint_t kind, vlen, root;
992178525Sjb	char *s;
993178525Sjb
994178525Sjb	if (name == NULL)
995178525Sjb		return (ctf_set_errno(fp, EINVAL));
996178525Sjb
997178525Sjb	if (!(fp->ctf_flags & LCTF_RDWR))
998178525Sjb		return (ctf_set_errno(fp, ECTF_RDONLY));
999178525Sjb
1000178525Sjb	if (dtd == NULL)
1001178525Sjb		return (ctf_set_errno(fp, ECTF_BADID));
1002178525Sjb
1003178525Sjb	kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
1004178525Sjb	root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info);
1005178525Sjb	vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info);
1006178525Sjb
1007178525Sjb	if (kind != CTF_K_ENUM)
1008178525Sjb		return (ctf_set_errno(fp, ECTF_NOTENUM));
1009178525Sjb
1010178525Sjb	if (vlen == CTF_MAX_VLEN)
1011178525Sjb		return (ctf_set_errno(fp, ECTF_DTFULL));
1012178525Sjb
1013178525Sjb	for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
1014178525Sjb	    dmd != NULL; dmd = ctf_list_next(dmd)) {
1015178525Sjb		if (strcmp(dmd->dmd_name, name) == 0)
1016178525Sjb			return (ctf_set_errno(fp, ECTF_DUPMEMBER));
1017178525Sjb	}
1018178525Sjb
1019178525Sjb	if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL)
1020178525Sjb		return (ctf_set_errno(fp, EAGAIN));
1021178525Sjb
1022178525Sjb	if ((s = ctf_strdup(name)) == NULL) {
1023178525Sjb		ctf_free(dmd, sizeof (ctf_dmdef_t));
1024178525Sjb		return (ctf_set_errno(fp, EAGAIN));
1025178525Sjb	}
1026178525Sjb
1027178525Sjb	dmd->dmd_name = s;
1028178525Sjb	dmd->dmd_type = CTF_ERR;
1029178525Sjb	dmd->dmd_offset = 0;
1030178525Sjb	dmd->dmd_value = value;
1031178525Sjb
1032178525Sjb	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1);
1033178525Sjb	ctf_list_append(&dtd->dtd_u.dtu_members, dmd);
1034178525Sjb
1035178525Sjb	fp->ctf_dtstrlen += strlen(s) + 1;
1036178525Sjb	fp->ctf_flags |= LCTF_DIRTY;
1037178525Sjb
1038178525Sjb	return (0);
1039178525Sjb}
1040178525Sjb
1041178525Sjbint
1042178525Sjbctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type)
1043178525Sjb{
1044178525Sjb	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, souid);
1045178525Sjb	ctf_dmdef_t *dmd;
1046178525Sjb
1047178525Sjb	ssize_t msize, malign, ssize;
1048178525Sjb	uint_t kind, vlen, root;
1049178525Sjb	char *s = NULL;
1050178525Sjb
1051178525Sjb	if (!(fp->ctf_flags & LCTF_RDWR))
1052178525Sjb		return (ctf_set_errno(fp, ECTF_RDONLY));
1053178525Sjb
1054178525Sjb	if (dtd == NULL)
1055178525Sjb		return (ctf_set_errno(fp, ECTF_BADID));
1056178525Sjb
1057178525Sjb	kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
1058178525Sjb	root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info);
1059178525Sjb	vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info);
1060178525Sjb
1061178525Sjb	if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
1062178525Sjb		return (ctf_set_errno(fp, ECTF_NOTSOU));
1063178525Sjb
1064178525Sjb	if (vlen == CTF_MAX_VLEN)
1065178525Sjb		return (ctf_set_errno(fp, ECTF_DTFULL));
1066178525Sjb
1067178525Sjb	if (name != NULL) {
1068178525Sjb		for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
1069178525Sjb		    dmd != NULL; dmd = ctf_list_next(dmd)) {
1070178525Sjb			if (dmd->dmd_name != NULL &&
1071178525Sjb			    strcmp(dmd->dmd_name, name) == 0)
1072178525Sjb				return (ctf_set_errno(fp, ECTF_DUPMEMBER));
1073178525Sjb		}
1074178525Sjb	}
1075178525Sjb
1076178525Sjb	if ((msize = ctf_type_size(fp, type)) == CTF_ERR ||
1077178525Sjb	    (malign = ctf_type_align(fp, type)) == CTF_ERR)
1078178525Sjb		return (CTF_ERR); /* errno is set for us */
1079178525Sjb
1080178525Sjb	if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL)
1081178525Sjb		return (ctf_set_errno(fp, EAGAIN));
1082178525Sjb
1083178525Sjb	if (name != NULL && (s = ctf_strdup(name)) == NULL) {
1084178525Sjb		ctf_free(dmd, sizeof (ctf_dmdef_t));
1085178525Sjb		return (ctf_set_errno(fp, EAGAIN));
1086178525Sjb	}
1087178525Sjb
1088178525Sjb	dmd->dmd_name = s;
1089178525Sjb	dmd->dmd_type = type;
1090178525Sjb	dmd->dmd_value = -1;
1091178525Sjb
1092178525Sjb	if (kind == CTF_K_STRUCT && vlen != 0) {
1093178525Sjb		ctf_dmdef_t *lmd = ctf_list_prev(&dtd->dtd_u.dtu_members);
1094178525Sjb		ctf_id_t ltype = ctf_type_resolve(fp, lmd->dmd_type);
1095178525Sjb		size_t off = lmd->dmd_offset;
1096178525Sjb
1097178525Sjb		ctf_encoding_t linfo;
1098178525Sjb		ssize_t lsize;
1099178525Sjb
1100178525Sjb		if (ctf_type_encoding(fp, ltype, &linfo) != CTF_ERR)
1101178525Sjb			off += linfo.cte_bits;
1102178525Sjb		else if ((lsize = ctf_type_size(fp, ltype)) != CTF_ERR)
1103178525Sjb			off += lsize * NBBY;
1104178525Sjb
1105178525Sjb		/*
1106178525Sjb		 * Round up the offset of the end of the last member to the
1107178525Sjb		 * next byte boundary, convert 'off' to bytes, and then round
1108178525Sjb		 * it up again to the next multiple of the alignment required
1109178525Sjb		 * by the new member.  Finally, convert back to bits and store
1110178525Sjb		 * the result in dmd_offset.  Technically we could do more
1111178525Sjb		 * efficient packing if the new member is a bit-field, but
1112178525Sjb		 * we're the "compiler" and ANSI says we can do as we choose.
1113178525Sjb		 */
1114178525Sjb		off = roundup(off, NBBY) / NBBY;
1115178525Sjb		off = roundup(off, MAX(malign, 1));
1116178525Sjb		dmd->dmd_offset = off * NBBY;
1117178525Sjb		ssize = off + msize;
1118178525Sjb	} else {
1119178525Sjb		dmd->dmd_offset = 0;
1120178525Sjb		ssize = ctf_get_ctt_size(fp, &dtd->dtd_data, NULL, NULL);
1121178525Sjb		ssize = MAX(ssize, msize);
1122178525Sjb	}
1123178525Sjb
1124178525Sjb	if (ssize > CTF_MAX_SIZE) {
1125178525Sjb		dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
1126178525Sjb		dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(ssize);
1127178525Sjb		dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(ssize);
1128178525Sjb	} else
1129178525Sjb		dtd->dtd_data.ctt_size = (ushort_t)ssize;
1130178525Sjb
1131178525Sjb	dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1);
1132178525Sjb	ctf_list_append(&dtd->dtd_u.dtu_members, dmd);
1133178525Sjb
1134178525Sjb	if (s != NULL)
1135178525Sjb		fp->ctf_dtstrlen += strlen(s) + 1;
1136178525Sjb
1137254744Sdelphij	ctf_ref_inc(fp, type);
1138178525Sjb	fp->ctf_flags |= LCTF_DIRTY;
1139178525Sjb	return (0);
1140178525Sjb}
1141178525Sjb
1142254744Sdelphij/*
1143254744Sdelphij * This removes a type from the dynamic section. This will fail if the type is
1144254744Sdelphij * referenced by another type. Note that the CTF ID is never reused currently by
1145254744Sdelphij * CTF. Note that if this container is a parent container then we just outright
1146254744Sdelphij * refuse to remove the type. There currently is no notion of searching for the
1147254744Sdelphij * ctf_dtdef_t in parent containers. If there is, then this constraint could
1148254744Sdelphij * become finer grained.
1149254744Sdelphij */
1150254744Sdelphijint
1151254744Sdelphijctf_delete_type(ctf_file_t *fp, ctf_id_t type)
1152254744Sdelphij{
1153254744Sdelphij	ctf_file_t *fpd;
1154254744Sdelphij	ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type);
1155254744Sdelphij
1156254744Sdelphij	if (!(fp->ctf_flags & LCTF_RDWR))
1157254744Sdelphij		return (ctf_set_errno(fp, ECTF_RDONLY));
1158254744Sdelphij
1159254744Sdelphij	/*
1160254744Sdelphij	 * We want to give as useful an errno as possible. That means that we
1161254744Sdelphij	 * want to distinguish between a type which does not exist and one for
1162254744Sdelphij	 * which the type is not dynamic.
1163254744Sdelphij	 */
1164254744Sdelphij	fpd = fp;
1165254744Sdelphij	if (ctf_lookup_by_id(&fpd, type) == NULL &&
1166254744Sdelphij	    ctf_dtd_lookup(fp, type) == NULL)
1167254744Sdelphij		return (CTF_ERR); /* errno is set for us */
1168254744Sdelphij
1169254744Sdelphij	if (dtd == NULL)
1170254744Sdelphij		return (ctf_set_errno(fp, ECTF_NOTDYN));
1171254744Sdelphij
1172254744Sdelphij	if (dtd->dtd_ref != 0 || fp->ctf_refcnt > 1)
1173254744Sdelphij		return (ctf_set_errno(fp, ECTF_REFERENCED));
1174254744Sdelphij
1175254744Sdelphij	ctf_dtd_delete(fp, dtd);
1176254744Sdelphij	fp->ctf_flags |= LCTF_DIRTY;
1177254744Sdelphij	return (0);
1178254744Sdelphij}
1179254744Sdelphij
1180178525Sjbstatic int
1181178525Sjbenumcmp(const char *name, int value, void *arg)
1182178525Sjb{
1183178525Sjb	ctf_bundle_t *ctb = arg;
1184178525Sjb	int bvalue;
1185178525Sjb
1186178525Sjb	return (ctf_enum_value(ctb->ctb_file, ctb->ctb_type,
1187178525Sjb	    name, &bvalue) == CTF_ERR || value != bvalue);
1188178525Sjb}
1189178525Sjb
1190178525Sjbstatic int
1191178525Sjbenumadd(const char *name, int value, void *arg)
1192178525Sjb{
1193178525Sjb	ctf_bundle_t *ctb = arg;
1194178525Sjb
1195178525Sjb	return (ctf_add_enumerator(ctb->ctb_file, ctb->ctb_type,
1196178525Sjb	    name, value) == CTF_ERR);
1197178525Sjb}
1198178525Sjb
1199178525Sjb/*ARGSUSED*/
1200178525Sjbstatic int
1201178525Sjbmembcmp(const char *name, ctf_id_t type, ulong_t offset, void *arg)
1202178525Sjb{
1203178525Sjb	ctf_bundle_t *ctb = arg;
1204178525Sjb	ctf_membinfo_t ctm;
1205178525Sjb
1206178525Sjb	return (ctf_member_info(ctb->ctb_file, ctb->ctb_type,
1207178525Sjb	    name, &ctm) == CTF_ERR || ctm.ctm_offset != offset);
1208178525Sjb}
1209178525Sjb
1210178525Sjbstatic int
1211178525Sjbmembadd(const char *name, ctf_id_t type, ulong_t offset, void *arg)
1212178525Sjb{
1213178525Sjb	ctf_bundle_t *ctb = arg;
1214178525Sjb	ctf_dmdef_t *dmd;
1215178525Sjb	char *s = NULL;
1216178525Sjb
1217178525Sjb	if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL)
1218178525Sjb		return (ctf_set_errno(ctb->ctb_file, EAGAIN));
1219178525Sjb
1220178525Sjb	if (name != NULL && (s = ctf_strdup(name)) == NULL) {
1221178525Sjb		ctf_free(dmd, sizeof (ctf_dmdef_t));
1222178525Sjb		return (ctf_set_errno(ctb->ctb_file, EAGAIN));
1223178525Sjb	}
1224178525Sjb
1225178525Sjb	/*
1226178525Sjb	 * For now, dmd_type is copied as the src_fp's type; it is reset to an
1227178525Sjb	 * equivalent dst_fp type by a final loop in ctf_add_type(), below.
1228178525Sjb	 */
1229178525Sjb	dmd->dmd_name = s;
1230178525Sjb	dmd->dmd_type = type;
1231178525Sjb	dmd->dmd_offset = offset;
1232178525Sjb	dmd->dmd_value = -1;
1233178525Sjb
1234178525Sjb	ctf_list_append(&ctb->ctb_dtd->dtd_u.dtu_members, dmd);
1235178525Sjb
1236178525Sjb	if (s != NULL)
1237178525Sjb		ctb->ctb_file->ctf_dtstrlen += strlen(s) + 1;
1238178525Sjb
1239178525Sjb	ctb->ctb_file->ctf_flags |= LCTF_DIRTY;
1240178525Sjb	return (0);
1241178525Sjb}
1242178525Sjb
1243178525Sjb/*
1244178525Sjb * The ctf_add_type routine is used to copy a type from a source CTF container
1245178525Sjb * to a dynamic destination container.  This routine operates recursively by
1246178525Sjb * following the source type's links and embedded member types.  If the
1247178525Sjb * destination container already contains a named type which has the same
1248178525Sjb * attributes, then we succeed and return this type but no changes occur.
1249178525Sjb */
1250178525Sjbctf_id_t
1251178525Sjbctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
1252178525Sjb{
1253178525Sjb	ctf_id_t dst_type = CTF_ERR;
1254178525Sjb	uint_t dst_kind = CTF_K_UNKNOWN;
1255178525Sjb
1256178525Sjb	const ctf_type_t *tp;
1257178525Sjb	const char *name;
1258178525Sjb	uint_t kind, flag, vlen;
1259178525Sjb
1260178525Sjb	ctf_bundle_t src, dst;
1261178525Sjb	ctf_encoding_t src_en, dst_en;
1262178525Sjb	ctf_arinfo_t src_ar, dst_ar;
1263178525Sjb
1264178525Sjb	ctf_dtdef_t *dtd;
1265178525Sjb	ctf_funcinfo_t ctc;
1266178525Sjb	ssize_t size;
1267178525Sjb
1268178525Sjb	ctf_hash_t *hp;
1269178525Sjb	ctf_helem_t *hep;
1270178525Sjb
1271254744Sdelphij	if (dst_fp == src_fp)
1272254744Sdelphij		return (src_type);
1273254744Sdelphij
1274178525Sjb	if (!(dst_fp->ctf_flags & LCTF_RDWR))
1275178525Sjb		return (ctf_set_errno(dst_fp, ECTF_RDONLY));
1276178525Sjb
1277178525Sjb	if ((tp = ctf_lookup_by_id(&src_fp, src_type)) == NULL)
1278178525Sjb		return (ctf_set_errno(dst_fp, ctf_errno(src_fp)));
1279178525Sjb
1280178525Sjb	name = ctf_strptr(src_fp, tp->ctt_name);
1281178525Sjb	kind = LCTF_INFO_KIND(src_fp, tp->ctt_info);
1282178525Sjb	flag = LCTF_INFO_ROOT(src_fp, tp->ctt_info);
1283178525Sjb	vlen = LCTF_INFO_VLEN(src_fp, tp->ctt_info);
1284178525Sjb
1285178525Sjb	switch (kind) {
1286178525Sjb	case CTF_K_STRUCT:
1287178525Sjb		hp = &dst_fp->ctf_structs;
1288178525Sjb		break;
1289178525Sjb	case CTF_K_UNION:
1290178525Sjb		hp = &dst_fp->ctf_unions;
1291178525Sjb		break;
1292178525Sjb	case CTF_K_ENUM:
1293178525Sjb		hp = &dst_fp->ctf_enums;
1294178525Sjb		break;
1295178525Sjb	default:
1296178525Sjb		hp = &dst_fp->ctf_names;
1297178525Sjb		break;
1298178525Sjb	}
1299178525Sjb
1300178525Sjb	/*
1301178525Sjb	 * If the source type has a name and is a root type (visible at the
1302178525Sjb	 * top-level scope), lookup the name in the destination container and
1303178525Sjb	 * verify that it is of the same kind before we do anything else.
1304178525Sjb	 */
1305178525Sjb	if ((flag & CTF_ADD_ROOT) && name[0] != '\0' &&
1306178525Sjb	    (hep = ctf_hash_lookup(hp, dst_fp, name, strlen(name))) != NULL) {
1307178525Sjb		dst_type = (ctf_id_t)hep->h_type;
1308178525Sjb		dst_kind = ctf_type_kind(dst_fp, dst_type);
1309178525Sjb	}
1310178525Sjb
1311178525Sjb	/*
1312178525Sjb	 * If an identically named dst_type exists, fail with ECTF_CONFLICT
1313178525Sjb	 * unless dst_type is a forward declaration and src_type is a struct,
1314178525Sjb	 * union, or enum (i.e. the definition of the previous forward decl).
1315178525Sjb	 */
1316279869Smarkj	if (dst_type != CTF_ERR && dst_kind != kind) {
1317279869Smarkj		if (dst_kind != CTF_K_FORWARD || (kind != CTF_K_ENUM &&
1318279869Smarkj		    kind != CTF_K_STRUCT && kind != CTF_K_UNION))
1319279869Smarkj			return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
1320279869Smarkj		else
1321279869Smarkj			dst_type = CTF_ERR;
1322279869Smarkj	}
1323178525Sjb
1324178525Sjb	/*
1325178525Sjb	 * If the non-empty name was not found in the appropriate hash, search
1326178525Sjb	 * the list of pending dynamic definitions that are not yet committed.
1327178525Sjb	 * If a matching name and kind are found, assume this is the type that
1328178525Sjb	 * we are looking for.  This is necessary to permit ctf_add_type() to
1329178525Sjb	 * operate recursively on entities such as a struct that contains a
1330178525Sjb	 * pointer member that refers to the same struct type.
1331282739Smarkj	 *
1332282739Smarkj	 * In the case of integer and floating point types, we match using the
1333282739Smarkj	 * type encoding as well - else we may incorrectly return a bitfield
1334282739Smarkj	 * type, for instance.
1335178525Sjb	 */
1336178525Sjb	if (dst_type == CTF_ERR && name[0] != '\0') {
1337178525Sjb		for (dtd = ctf_list_prev(&dst_fp->ctf_dtdefs); dtd != NULL &&
1338279864Smarkj		    CTF_TYPE_TO_INDEX(dtd->dtd_type) > dst_fp->ctf_dtoldid;
1339178525Sjb		    dtd = ctf_list_prev(dtd)) {
1340282739Smarkj			if (CTF_INFO_KIND(dtd->dtd_data.ctt_info) != kind ||
1341282739Smarkj			    dtd->dtd_name == NULL ||
1342282739Smarkj			    strcmp(dtd->dtd_name, name) != 0)
1343282739Smarkj				continue;
1344282739Smarkj			if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT) {
1345282739Smarkj				if (ctf_type_encoding(src_fp, src_type,
1346282739Smarkj				    &src_en) != 0)
1347282739Smarkj					continue;
1348282739Smarkj				if (bcmp(&src_en, &dtd->dtd_u.dtu_enc,
1349282739Smarkj				    sizeof (ctf_encoding_t)) != 0)
1350282739Smarkj					continue;
1351282739Smarkj			}
1352282739Smarkj			return (dtd->dtd_type);
1353178525Sjb		}
1354178525Sjb	}
1355178525Sjb
1356178525Sjb	src.ctb_file = src_fp;
1357178525Sjb	src.ctb_type = src_type;
1358178525Sjb	src.ctb_dtd = NULL;
1359178525Sjb
1360178525Sjb	dst.ctb_file = dst_fp;
1361178525Sjb	dst.ctb_type = dst_type;
1362178525Sjb	dst.ctb_dtd = NULL;
1363178525Sjb
1364178525Sjb	/*
1365178525Sjb	 * Now perform kind-specific processing.  If dst_type is CTF_ERR, then
1366178525Sjb	 * we add a new type with the same properties as src_type to dst_fp.
1367178525Sjb	 * If dst_type is not CTF_ERR, then we verify that dst_type has the
1368178525Sjb	 * same attributes as src_type.  We recurse for embedded references.
1369178525Sjb	 */
1370178525Sjb	switch (kind) {
1371178525Sjb	case CTF_K_INTEGER:
1372178525Sjb	case CTF_K_FLOAT:
1373178525Sjb		if (ctf_type_encoding(src_fp, src_type, &src_en) != 0)
1374178525Sjb			return (ctf_set_errno(dst_fp, ctf_errno(src_fp)));
1375178525Sjb
1376178525Sjb		if (dst_type != CTF_ERR) {
1377178525Sjb			if (ctf_type_encoding(dst_fp, dst_type, &dst_en) != 0)
1378178525Sjb				return (CTF_ERR); /* errno is set for us */
1379178525Sjb
1380178525Sjb			if (bcmp(&src_en, &dst_en, sizeof (ctf_encoding_t)))
1381178525Sjb				return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
1382178525Sjb
1383178525Sjb		} else if (kind == CTF_K_INTEGER) {
1384178525Sjb			dst_type = ctf_add_integer(dst_fp, flag, name, &src_en);
1385178525Sjb		} else
1386178525Sjb			dst_type = ctf_add_float(dst_fp, flag, name, &src_en);
1387178525Sjb		break;
1388178525Sjb
1389178525Sjb	case CTF_K_POINTER:
1390178525Sjb	case CTF_K_VOLATILE:
1391178525Sjb	case CTF_K_CONST:
1392178525Sjb	case CTF_K_RESTRICT:
1393178525Sjb		src_type = ctf_type_reference(src_fp, src_type);
1394178525Sjb		src_type = ctf_add_type(dst_fp, src_fp, src_type);
1395178525Sjb
1396178525Sjb		if (src_type == CTF_ERR)
1397178525Sjb			return (CTF_ERR); /* errno is set for us */
1398178525Sjb
1399178525Sjb		dst_type = ctf_add_reftype(dst_fp, flag, src_type, kind);
1400178525Sjb		break;
1401178525Sjb
1402178525Sjb	case CTF_K_ARRAY:
1403178525Sjb		if (ctf_array_info(src_fp, src_type, &src_ar) == CTF_ERR)
1404178525Sjb			return (ctf_set_errno(dst_fp, ctf_errno(src_fp)));
1405178525Sjb
1406178525Sjb		src_ar.ctr_contents =
1407178525Sjb		    ctf_add_type(dst_fp, src_fp, src_ar.ctr_contents);
1408178525Sjb		src_ar.ctr_index =
1409178525Sjb		    ctf_add_type(dst_fp, src_fp, src_ar.ctr_index);
1410178525Sjb		src_ar.ctr_nelems = src_ar.ctr_nelems;
1411178525Sjb
1412178525Sjb		if (src_ar.ctr_contents == CTF_ERR ||
1413178525Sjb		    src_ar.ctr_index == CTF_ERR)
1414178525Sjb			return (CTF_ERR); /* errno is set for us */
1415178525Sjb
1416178525Sjb		if (dst_type != CTF_ERR) {
1417178525Sjb			if (ctf_array_info(dst_fp, dst_type, &dst_ar) != 0)
1418178525Sjb				return (CTF_ERR); /* errno is set for us */
1419178525Sjb
1420178525Sjb			if (bcmp(&src_ar, &dst_ar, sizeof (ctf_arinfo_t)))
1421178525Sjb				return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
1422178525Sjb		} else
1423178525Sjb			dst_type = ctf_add_array(dst_fp, flag, &src_ar);
1424178525Sjb		break;
1425178525Sjb
1426178525Sjb	case CTF_K_FUNCTION:
1427178525Sjb		ctc.ctc_return = ctf_add_type(dst_fp, src_fp, tp->ctt_type);
1428178525Sjb		ctc.ctc_argc = 0;
1429178525Sjb		ctc.ctc_flags = 0;
1430178525Sjb
1431178525Sjb		if (ctc.ctc_return == CTF_ERR)
1432178525Sjb			return (CTF_ERR); /* errno is set for us */
1433178525Sjb
1434178525Sjb		dst_type = ctf_add_function(dst_fp, flag, &ctc, NULL);
1435178525Sjb		break;
1436178525Sjb
1437178525Sjb	case CTF_K_STRUCT:
1438178525Sjb	case CTF_K_UNION: {
1439178525Sjb		ctf_dmdef_t *dmd;
1440178525Sjb		int errs = 0;
1441178525Sjb
1442178525Sjb		/*
1443178525Sjb		 * Technically to match a struct or union we need to check both
1444178525Sjb		 * ways (src members vs. dst, dst members vs. src) but we make
1445178525Sjb		 * this more optimal by only checking src vs. dst and comparing
1446178525Sjb		 * the total size of the structure (which we must do anyway)
1447178525Sjb		 * which covers the possibility of dst members not in src.
1448178525Sjb		 * This optimization can be defeated for unions, but is so
1449178525Sjb		 * pathological as to render it irrelevant for our purposes.
1450178525Sjb		 */
1451178525Sjb		if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD) {
1452178525Sjb			if (ctf_type_size(src_fp, src_type) !=
1453178525Sjb			    ctf_type_size(dst_fp, dst_type))
1454178525Sjb				return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
1455178525Sjb
1456178525Sjb			if (ctf_member_iter(src_fp, src_type, membcmp, &dst))
1457178525Sjb				return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
1458178525Sjb
1459178525Sjb			break;
1460178525Sjb		}
1461178525Sjb
1462178525Sjb		/*
1463178525Sjb		 * Unlike the other cases, copying structs and unions is done
1464178525Sjb		 * manually so as to avoid repeated lookups in ctf_add_member
1465178525Sjb		 * and to ensure the exact same member offsets as in src_type.
1466178525Sjb		 */
1467178525Sjb		dst_type = ctf_add_generic(dst_fp, flag, name, &dtd);
1468178525Sjb		if (dst_type == CTF_ERR)
1469178525Sjb			return (CTF_ERR); /* errno is set for us */
1470178525Sjb
1471178525Sjb		dst.ctb_type = dst_type;
1472178525Sjb		dst.ctb_dtd = dtd;
1473178525Sjb
1474178525Sjb		if (ctf_member_iter(src_fp, src_type, membadd, &dst) != 0)
1475178525Sjb			errs++; /* increment errs and fail at bottom of case */
1476178525Sjb
1477178525Sjb		if ((size = ctf_type_size(src_fp, src_type)) > CTF_MAX_SIZE) {
1478178525Sjb			dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
1479178525Sjb			dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size);
1480178525Sjb			dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size);
1481178525Sjb		} else
1482178525Sjb			dtd->dtd_data.ctt_size = (ushort_t)size;
1483178525Sjb
1484178525Sjb		dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, vlen);
1485178525Sjb
1486178525Sjb		/*
1487178525Sjb		 * Make a final pass through the members changing each dmd_type
1488178525Sjb		 * (a src_fp type) to an equivalent type in dst_fp.  We pass
1489178525Sjb		 * through all members, leaving any that fail set to CTF_ERR.
1490178525Sjb		 */
1491178525Sjb		for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
1492178525Sjb		    dmd != NULL; dmd = ctf_list_next(dmd)) {
1493178525Sjb			if ((dmd->dmd_type = ctf_add_type(dst_fp, src_fp,
1494178525Sjb			    dmd->dmd_type)) == CTF_ERR)
1495178525Sjb				errs++;
1496178525Sjb		}
1497178525Sjb
1498178525Sjb		if (errs)
1499178525Sjb			return (CTF_ERR); /* errno is set for us */
1500254744Sdelphij
1501254744Sdelphij		/*
1502254744Sdelphij		 * Now that we know that we can't fail, we go through and bump
1503254744Sdelphij		 * all the reference counts on the member types.
1504254744Sdelphij		 */
1505254744Sdelphij		for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members);
1506254744Sdelphij		    dmd != NULL; dmd = ctf_list_next(dmd))
1507254744Sdelphij			ctf_ref_inc(dst_fp, dmd->dmd_type);
1508178525Sjb		break;
1509178525Sjb	}
1510178525Sjb
1511178525Sjb	case CTF_K_ENUM:
1512178525Sjb		if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD) {
1513178525Sjb			if (ctf_enum_iter(src_fp, src_type, enumcmp, &dst) ||
1514178525Sjb			    ctf_enum_iter(dst_fp, dst_type, enumcmp, &src))
1515178525Sjb				return (ctf_set_errno(dst_fp, ECTF_CONFLICT));
1516178525Sjb		} else {
1517178525Sjb			dst_type = ctf_add_enum(dst_fp, flag, name);
1518178525Sjb			if ((dst.ctb_type = dst_type) == CTF_ERR ||
1519178525Sjb			    ctf_enum_iter(src_fp, src_type, enumadd, &dst))
1520178525Sjb				return (CTF_ERR); /* errno is set for us */
1521178525Sjb		}
1522178525Sjb		break;
1523178525Sjb
1524178525Sjb	case CTF_K_FORWARD:
1525178525Sjb		if (dst_type == CTF_ERR) {
1526178525Sjb			dst_type = ctf_add_forward(dst_fp,
1527178525Sjb			    flag, name, CTF_K_STRUCT); /* assume STRUCT */
1528178525Sjb		}
1529178525Sjb		break;
1530178525Sjb
1531178525Sjb	case CTF_K_TYPEDEF:
1532178525Sjb		src_type = ctf_type_reference(src_fp, src_type);
1533178525Sjb		src_type = ctf_add_type(dst_fp, src_fp, src_type);
1534178525Sjb
1535178525Sjb		if (src_type == CTF_ERR)
1536178525Sjb			return (CTF_ERR); /* errno is set for us */
1537178525Sjb
1538178525Sjb		/*
1539178525Sjb		 * If dst_type is not CTF_ERR at this point, we should check if
1540178525Sjb		 * ctf_type_reference(dst_fp, dst_type) != src_type and if so
1541178525Sjb		 * fail with ECTF_CONFLICT.  However, this causes problems with
1542178525Sjb		 * <sys/types.h> typedefs that vary based on things like if
1543178525Sjb		 * _ILP32x then pid_t is int otherwise long.  We therefore omit
1544178525Sjb		 * this check and assume that if the identically named typedef
1545178525Sjb		 * already exists in dst_fp, it is correct or equivalent.
1546178525Sjb		 */
1547178525Sjb		if (dst_type == CTF_ERR) {
1548178525Sjb			dst_type = ctf_add_typedef(dst_fp, flag,
1549178525Sjb			    name, src_type);
1550178525Sjb		}
1551178525Sjb		break;
1552178525Sjb
1553178525Sjb	default:
1554178525Sjb		return (ctf_set_errno(dst_fp, ECTF_CORRUPT));
1555178525Sjb	}
1556178525Sjb
1557178525Sjb	return (dst_type);
1558178525Sjb}
1559