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 */
27178525Sjb
28178525Sjb#include <ctf_impl.h>
29178525Sjb
30178525Sjbssize_t
31178525Sjbctf_get_ctt_size(const ctf_file_t *fp, const ctf_type_t *tp, ssize_t *sizep,
32178525Sjb    ssize_t *incrementp)
33178525Sjb{
34178525Sjb	ssize_t size, increment;
35178525Sjb
36178525Sjb	if (fp->ctf_version > CTF_VERSION_1 &&
37178525Sjb	    tp->ctt_size == CTF_LSIZE_SENT) {
38178525Sjb		size = CTF_TYPE_LSIZE(tp);
39178525Sjb		increment = sizeof (ctf_type_t);
40178525Sjb	} else {
41178525Sjb		size = tp->ctt_size;
42178525Sjb		increment = sizeof (ctf_stype_t);
43178525Sjb	}
44178525Sjb
45178525Sjb	if (sizep)
46178525Sjb		*sizep = size;
47178525Sjb	if (incrementp)
48178525Sjb		*incrementp = increment;
49178525Sjb
50178525Sjb	return (size);
51178525Sjb}
52178525Sjb
53178525Sjb/*
54178525Sjb * Iterate over the members of a STRUCT or UNION.  We pass the name, member
55178525Sjb * type, and offset of each member to the specified callback function.
56178525Sjb */
57178525Sjbint
58178525Sjbctf_member_iter(ctf_file_t *fp, ctf_id_t type, ctf_member_f *func, void *arg)
59178525Sjb{
60178525Sjb	ctf_file_t *ofp = fp;
61178525Sjb	const ctf_type_t *tp;
62178525Sjb	ssize_t size, increment;
63178525Sjb	uint_t kind, n;
64178525Sjb	int rc;
65178525Sjb
66178525Sjb	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
67178525Sjb		return (CTF_ERR); /* errno is set for us */
68178525Sjb
69178525Sjb	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
70178525Sjb		return (CTF_ERR); /* errno is set for us */
71178525Sjb
72178525Sjb	(void) ctf_get_ctt_size(fp, tp, &size, &increment);
73178525Sjb	kind = LCTF_INFO_KIND(fp, tp->ctt_info);
74178525Sjb
75178525Sjb	if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
76178525Sjb		return (ctf_set_errno(ofp, ECTF_NOTSOU));
77178525Sjb
78178525Sjb	if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) {
79178525Sjb		const ctf_member_t *mp = (const ctf_member_t *)
80178525Sjb		    ((uintptr_t)tp + increment);
81178525Sjb
82178525Sjb		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) {
83178525Sjb			const char *name = ctf_strptr(fp, mp->ctm_name);
84178525Sjb			if ((rc = func(name, mp->ctm_type, mp->ctm_offset,
85178525Sjb			    arg)) != 0)
86178525Sjb				return (rc);
87178525Sjb		}
88178525Sjb
89178525Sjb	} else {
90178525Sjb		const ctf_lmember_t *lmp = (const ctf_lmember_t *)
91178525Sjb		    ((uintptr_t)tp + increment);
92178525Sjb
93178525Sjb		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) {
94178525Sjb			const char *name = ctf_strptr(fp, lmp->ctlm_name);
95178525Sjb			if ((rc = func(name, lmp->ctlm_type,
96178525Sjb			    (ulong_t)CTF_LMEM_OFFSET(lmp), arg)) != 0)
97178525Sjb				return (rc);
98178525Sjb		}
99178525Sjb	}
100178525Sjb
101178525Sjb	return (0);
102178525Sjb}
103178525Sjb
104178525Sjb/*
105178525Sjb * Iterate over the members of an ENUM.  We pass the string name and associated
106178525Sjb * integer value of each enum element to the specified callback function.
107178525Sjb */
108178525Sjbint
109178525Sjbctf_enum_iter(ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg)
110178525Sjb{
111178525Sjb	ctf_file_t *ofp = fp;
112178525Sjb	const ctf_type_t *tp;
113178525Sjb	const ctf_enum_t *ep;
114178525Sjb	ssize_t increment;
115178525Sjb	uint_t n;
116178525Sjb	int rc;
117178525Sjb
118178525Sjb	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
119178525Sjb		return (CTF_ERR); /* errno is set for us */
120178525Sjb
121178525Sjb	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
122178525Sjb		return (CTF_ERR); /* errno is set for us */
123178525Sjb
124178525Sjb	if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM)
125178525Sjb		return (ctf_set_errno(ofp, ECTF_NOTENUM));
126178525Sjb
127178525Sjb	(void) ctf_get_ctt_size(fp, tp, NULL, &increment);
128178525Sjb
129178525Sjb	ep = (const ctf_enum_t *)((uintptr_t)tp + increment);
130178525Sjb
131178525Sjb	for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) {
132178525Sjb		const char *name = ctf_strptr(fp, ep->cte_name);
133178525Sjb		if ((rc = func(name, ep->cte_value, arg)) != 0)
134178525Sjb			return (rc);
135178525Sjb	}
136178525Sjb
137178525Sjb	return (0);
138178525Sjb}
139178525Sjb
140178525Sjb/*
141178525Sjb * Iterate over every root (user-visible) type in the given CTF container.
142178525Sjb * We pass the type ID of each type to the specified callback function.
143178525Sjb */
144178525Sjbint
145178525Sjbctf_type_iter(ctf_file_t *fp, ctf_type_f *func, void *arg)
146178525Sjb{
147178525Sjb	ctf_id_t id, max = fp->ctf_typemax;
148178525Sjb	int rc, child = (fp->ctf_flags & LCTF_CHILD);
149178525Sjb
150178525Sjb	for (id = 1; id <= max; id++) {
151178525Sjb		const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR(fp, id);
152178525Sjb		if (CTF_INFO_ISROOT(tp->ctt_info) &&
153178525Sjb		    (rc = func(CTF_INDEX_TO_TYPE(id, child), arg)) != 0)
154178525Sjb			return (rc);
155178525Sjb	}
156178525Sjb
157178525Sjb	return (0);
158178525Sjb}
159178525Sjb
160178525Sjb/*
161178525Sjb * Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and
162178525Sjb * RESTRICT nodes until we reach a "base" type node.  This is useful when
163178525Sjb * we want to follow a type ID to a node that has members or a size.  To guard
164178525Sjb * against infinite loops, we implement simplified cycle detection and check
165178525Sjb * each link against itself, the previous node, and the topmost node.
166178525Sjb */
167178525Sjbctf_id_t
168178525Sjbctf_type_resolve(ctf_file_t *fp, ctf_id_t type)
169178525Sjb{
170178525Sjb	ctf_id_t prev = type, otype = type;
171178525Sjb	ctf_file_t *ofp = fp;
172178525Sjb	const ctf_type_t *tp;
173178525Sjb
174178525Sjb	while ((tp = ctf_lookup_by_id(&fp, type)) != NULL) {
175178525Sjb		switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
176178525Sjb		case CTF_K_TYPEDEF:
177178525Sjb		case CTF_K_VOLATILE:
178178525Sjb		case CTF_K_CONST:
179178525Sjb		case CTF_K_RESTRICT:
180178525Sjb			if (tp->ctt_type == type || tp->ctt_type == otype ||
181178525Sjb			    tp->ctt_type == prev) {
182178525Sjb				ctf_dprintf("type %ld cycle detected\n", otype);
183178525Sjb				return (ctf_set_errno(ofp, ECTF_CORRUPT));
184178525Sjb			}
185178525Sjb			prev = type;
186178525Sjb			type = tp->ctt_type;
187178525Sjb			break;
188178525Sjb		default:
189178525Sjb			return (type);
190178525Sjb		}
191178525Sjb	}
192178525Sjb
193178525Sjb	return (CTF_ERR); /* errno is set for us */
194178525Sjb}
195178525Sjb
196178525Sjb/*
197178525Sjb * Lookup the given type ID and print a string name for it into buf.  Return
198178525Sjb * the actual number of bytes (not including \0) needed to format the name.
199178525Sjb */
200267941Srpaulostatic ssize_t
201267941Srpauloctf_type_qlname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
202267941Srpaulo    const char *qname)
203178525Sjb{
204178525Sjb	ctf_decl_t cd;
205178525Sjb	ctf_decl_node_t *cdp;
206178525Sjb	ctf_decl_prec_t prec, lp, rp;
207178525Sjb	int ptr, arr;
208178525Sjb	uint_t k;
209178525Sjb
210178525Sjb	if (fp == NULL && type == CTF_ERR)
211178525Sjb		return (-1); /* simplify caller code by permitting CTF_ERR */
212178525Sjb
213178525Sjb	ctf_decl_init(&cd, buf, len);
214178525Sjb	ctf_decl_push(&cd, fp, type);
215178525Sjb
216178525Sjb	if (cd.cd_err != 0) {
217178525Sjb		ctf_decl_fini(&cd);
218178525Sjb		return (ctf_set_errno(fp, cd.cd_err));
219178525Sjb	}
220178525Sjb
221178525Sjb	/*
222178525Sjb	 * If the type graph's order conflicts with lexical precedence order
223178525Sjb	 * for pointers or arrays, then we need to surround the declarations at
224178525Sjb	 * the corresponding lexical precedence with parentheses.  This can
225178525Sjb	 * result in either a parenthesized pointer (*) as in int (*)() or
226178525Sjb	 * int (*)[], or in a parenthesized pointer and array as in int (*[])().
227178525Sjb	 */
228178525Sjb	ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER;
229178525Sjb	arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY;
230178525Sjb
231178525Sjb	rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1;
232178525Sjb	lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1;
233178525Sjb
234178525Sjb	k = CTF_K_POINTER; /* avoid leading whitespace (see below) */
235178525Sjb
236178525Sjb	for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) {
237178525Sjb		for (cdp = ctf_list_next(&cd.cd_nodes[prec]);
238178525Sjb		    cdp != NULL; cdp = ctf_list_next(cdp)) {
239178525Sjb
240178525Sjb			ctf_file_t *rfp = fp;
241178525Sjb			const ctf_type_t *tp =
242178525Sjb			    ctf_lookup_by_id(&rfp, cdp->cd_type);
243178525Sjb			const char *name = ctf_strptr(rfp, tp->ctt_name);
244178525Sjb
245178525Sjb			if (k != CTF_K_POINTER && k != CTF_K_ARRAY)
246178525Sjb				ctf_decl_sprintf(&cd, " ");
247178525Sjb
248178525Sjb			if (lp == prec) {
249178525Sjb				ctf_decl_sprintf(&cd, "(");
250178525Sjb				lp = -1;
251178525Sjb			}
252178525Sjb
253178525Sjb			switch (cdp->cd_kind) {
254178525Sjb			case CTF_K_INTEGER:
255178525Sjb			case CTF_K_FLOAT:
256178525Sjb			case CTF_K_TYPEDEF:
257267941Srpaulo				if (qname != NULL)
258267941Srpaulo					ctf_decl_sprintf(&cd, "%s`", qname);
259178525Sjb				ctf_decl_sprintf(&cd, "%s", name);
260178525Sjb				break;
261178525Sjb			case CTF_K_POINTER:
262178525Sjb				ctf_decl_sprintf(&cd, "*");
263178525Sjb				break;
264178525Sjb			case CTF_K_ARRAY:
265178525Sjb				ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n);
266178525Sjb				break;
267178525Sjb			case CTF_K_FUNCTION:
268178525Sjb				ctf_decl_sprintf(&cd, "()");
269178525Sjb				break;
270178525Sjb			case CTF_K_STRUCT:
271178525Sjb			case CTF_K_FORWARD:
272267941Srpaulo				ctf_decl_sprintf(&cd, "struct ");
273267941Srpaulo				if (qname != NULL)
274267941Srpaulo					ctf_decl_sprintf(&cd, "%s`", qname);
275267941Srpaulo				ctf_decl_sprintf(&cd, "%s", name);
276178525Sjb				break;
277178525Sjb			case CTF_K_UNION:
278267941Srpaulo				ctf_decl_sprintf(&cd, "union ");
279267941Srpaulo				if (qname != NULL)
280267941Srpaulo					ctf_decl_sprintf(&cd, "%s`", qname);
281267941Srpaulo				ctf_decl_sprintf(&cd, "%s", name);
282178525Sjb				break;
283178525Sjb			case CTF_K_ENUM:
284267941Srpaulo				ctf_decl_sprintf(&cd, "enum ");
285267941Srpaulo				if (qname != NULL)
286267941Srpaulo					ctf_decl_sprintf(&cd, "%s`", qname);
287267941Srpaulo				ctf_decl_sprintf(&cd, "%s", name);
288178525Sjb				break;
289178525Sjb			case CTF_K_VOLATILE:
290178525Sjb				ctf_decl_sprintf(&cd, "volatile");
291178525Sjb				break;
292178525Sjb			case CTF_K_CONST:
293178525Sjb				ctf_decl_sprintf(&cd, "const");
294178525Sjb				break;
295178525Sjb			case CTF_K_RESTRICT:
296178525Sjb				ctf_decl_sprintf(&cd, "restrict");
297178525Sjb				break;
298178525Sjb			}
299178525Sjb
300178525Sjb			k = cdp->cd_kind;
301178525Sjb		}
302178525Sjb
303178525Sjb		if (rp == prec)
304178525Sjb			ctf_decl_sprintf(&cd, ")");
305178525Sjb	}
306178525Sjb
307178525Sjb	if (cd.cd_len >= len)
308178525Sjb		(void) ctf_set_errno(fp, ECTF_NAMELEN);
309178525Sjb
310178525Sjb	ctf_decl_fini(&cd);
311178525Sjb	return (cd.cd_len);
312178525Sjb}
313178525Sjb
314267941Srpaulossize_t
315267941Srpauloctf_type_lname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
316267941Srpaulo{
317267941Srpaulo	return (ctf_type_qlname(fp, type, buf, len, NULL));
318267941Srpaulo}
319267941Srpaulo
320178525Sjb/*
321178525Sjb * Lookup the given type ID and print a string name for it into buf.  If buf
322178525Sjb * is too small, return NULL: the ECTF_NAMELEN error is set on 'fp' for us.
323178525Sjb */
324178525Sjbchar *
325178525Sjbctf_type_name(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
326178525Sjb{
327267941Srpaulo	ssize_t rv = ctf_type_qlname(fp, type, buf, len, NULL);
328178525Sjb	return (rv >= 0 && rv < len ? buf : NULL);
329178525Sjb}
330178525Sjb
331267941Srpaulochar *
332267941Srpauloctf_type_qname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
333267941Srpaulo    const char *qname)
334267941Srpaulo{
335267941Srpaulo	ssize_t rv = ctf_type_qlname(fp, type, buf, len, qname);
336267941Srpaulo	return (rv >= 0 && rv < len ? buf : NULL);
337267941Srpaulo}
338267941Srpaulo
339267941Srpaulo
340178525Sjb/*
341178525Sjb * Resolve the type down to a base type node, and then return the size
342178525Sjb * of the type storage in bytes.
343178525Sjb */
344178525Sjbssize_t
345178525Sjbctf_type_size(ctf_file_t *fp, ctf_id_t type)
346178525Sjb{
347178525Sjb	const ctf_type_t *tp;
348178525Sjb	ssize_t size;
349178525Sjb	ctf_arinfo_t ar;
350178525Sjb
351178525Sjb	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
352178525Sjb		return (-1); /* errno is set for us */
353178525Sjb
354178525Sjb	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
355178525Sjb		return (-1); /* errno is set for us */
356178525Sjb
357178525Sjb	switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
358178525Sjb	case CTF_K_POINTER:
359178525Sjb		return (fp->ctf_dmodel->ctd_pointer);
360178525Sjb
361178525Sjb	case CTF_K_FUNCTION:
362178525Sjb		return (0); /* function size is only known by symtab */
363178525Sjb
364178525Sjb	case CTF_K_ENUM:
365178525Sjb		return (fp->ctf_dmodel->ctd_int);
366178525Sjb
367178525Sjb	case CTF_K_ARRAY:
368178525Sjb		/*
369178525Sjb		 * Array size is not directly returned by stabs data.  Instead,
370178525Sjb		 * it defines the element type and requires the user to perform
371178525Sjb		 * the multiplication.  If ctf_get_ctt_size() returns zero, the
372178525Sjb		 * current version of ctfconvert does not compute member sizes
373178525Sjb		 * and we compute the size here on its behalf.
374178525Sjb		 */
375178525Sjb		if ((size = ctf_get_ctt_size(fp, tp, NULL, NULL)) > 0)
376178525Sjb			return (size);
377178525Sjb
378178525Sjb		if (ctf_array_info(fp, type, &ar) == CTF_ERR ||
379178525Sjb		    (size = ctf_type_size(fp, ar.ctr_contents)) == CTF_ERR)
380178525Sjb			return (-1); /* errno is set for us */
381178525Sjb
382178525Sjb		return (size * ar.ctr_nelems);
383178525Sjb
384178525Sjb	default:
385178525Sjb		return (ctf_get_ctt_size(fp, tp, NULL, NULL));
386178525Sjb	}
387178525Sjb}
388178525Sjb
389178525Sjb/*
390178525Sjb * Resolve the type down to a base type node, and then return the alignment
391178525Sjb * needed for the type storage in bytes.
392178525Sjb */
393178525Sjbssize_t
394178525Sjbctf_type_align(ctf_file_t *fp, ctf_id_t type)
395178525Sjb{
396178525Sjb	const ctf_type_t *tp;
397178525Sjb	ctf_arinfo_t r;
398178525Sjb
399178525Sjb	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
400178525Sjb		return (-1); /* errno is set for us */
401178525Sjb
402178525Sjb	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
403178525Sjb		return (-1); /* errno is set for us */
404178525Sjb
405178525Sjb	switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
406178525Sjb	case CTF_K_POINTER:
407178525Sjb	case CTF_K_FUNCTION:
408178525Sjb		return (fp->ctf_dmodel->ctd_pointer);
409178525Sjb
410178525Sjb	case CTF_K_ARRAY:
411178525Sjb		if (ctf_array_info(fp, type, &r) == CTF_ERR)
412178525Sjb			return (-1); /* errno is set for us */
413178525Sjb		return (ctf_type_align(fp, r.ctr_contents));
414178525Sjb
415178525Sjb	case CTF_K_STRUCT:
416178525Sjb	case CTF_K_UNION: {
417178525Sjb		uint_t n = LCTF_INFO_VLEN(fp, tp->ctt_info);
418178525Sjb		ssize_t size, increment;
419178525Sjb		size_t align = 0;
420178525Sjb		const void *vmp;
421178525Sjb
422178525Sjb		(void) ctf_get_ctt_size(fp, tp, &size, &increment);
423178525Sjb		vmp = (uchar_t *)tp + increment;
424178525Sjb
425178525Sjb		if (LCTF_INFO_KIND(fp, tp->ctt_info) == CTF_K_STRUCT)
426178525Sjb			n = MIN(n, 1); /* only use first member for structs */
427178525Sjb
428178525Sjb		if (fp->ctf_version == CTF_VERSION_1 ||
429178525Sjb		    size < CTF_LSTRUCT_THRESH) {
430178525Sjb			const ctf_member_t *mp = vmp;
431178525Sjb			for (; n != 0; n--, mp++) {
432178525Sjb				ssize_t am = ctf_type_align(fp, mp->ctm_type);
433178525Sjb				align = MAX(align, am);
434178525Sjb			}
435178525Sjb		} else {
436178525Sjb			const ctf_lmember_t *lmp = vmp;
437178525Sjb			for (; n != 0; n--, lmp++) {
438178525Sjb				ssize_t am = ctf_type_align(fp, lmp->ctlm_type);
439178525Sjb				align = MAX(align, am);
440178525Sjb			}
441178525Sjb		}
442178525Sjb
443178525Sjb		return (align);
444178525Sjb	}
445178525Sjb
446178525Sjb	case CTF_K_ENUM:
447178525Sjb		return (fp->ctf_dmodel->ctd_int);
448178525Sjb
449178525Sjb	default:
450178525Sjb		return (ctf_get_ctt_size(fp, tp, NULL, NULL));
451178525Sjb	}
452178525Sjb}
453178525Sjb
454178525Sjb/*
455178525Sjb * Return the kind (CTF_K_* constant) for the specified type ID.
456178525Sjb */
457178525Sjbint
458178525Sjbctf_type_kind(ctf_file_t *fp, ctf_id_t type)
459178525Sjb{
460178525Sjb	const ctf_type_t *tp;
461178525Sjb
462178525Sjb	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
463178525Sjb		return (CTF_ERR); /* errno is set for us */
464178525Sjb
465178525Sjb	return (LCTF_INFO_KIND(fp, tp->ctt_info));
466178525Sjb}
467178525Sjb
468178525Sjb/*
469178525Sjb * If the type is one that directly references another type (such as POINTER),
470178525Sjb * then return the ID of the type to which it refers.
471178525Sjb */
472178525Sjbctf_id_t
473178525Sjbctf_type_reference(ctf_file_t *fp, ctf_id_t type)
474178525Sjb{
475178525Sjb	ctf_file_t *ofp = fp;
476178525Sjb	const ctf_type_t *tp;
477178525Sjb
478178525Sjb	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
479178525Sjb		return (CTF_ERR); /* errno is set for us */
480178525Sjb
481178525Sjb	switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
482178525Sjb	case CTF_K_POINTER:
483178525Sjb	case CTF_K_TYPEDEF:
484178525Sjb	case CTF_K_VOLATILE:
485178525Sjb	case CTF_K_CONST:
486178525Sjb	case CTF_K_RESTRICT:
487178525Sjb		return (tp->ctt_type);
488178525Sjb	default:
489178525Sjb		return (ctf_set_errno(ofp, ECTF_NOTREF));
490178525Sjb	}
491178525Sjb}
492178525Sjb
493178525Sjb/*
494178525Sjb * Find a pointer to type by looking in fp->ctf_ptrtab.  If we can't find a
495178525Sjb * pointer to the given type, see if we can compute a pointer to the type
496178525Sjb * resulting from resolving the type down to its base type and use that
497178525Sjb * instead.  This helps with cases where the CTF data includes "struct foo *"
498178525Sjb * but not "foo_t *" and the user accesses "foo_t *" in the debugger.
499178525Sjb */
500178525Sjbctf_id_t
501178525Sjbctf_type_pointer(ctf_file_t *fp, ctf_id_t type)
502178525Sjb{
503178525Sjb	ctf_file_t *ofp = fp;
504178525Sjb	ctf_id_t ntype;
505178525Sjb
506178525Sjb	if (ctf_lookup_by_id(&fp, type) == NULL)
507178525Sjb		return (CTF_ERR); /* errno is set for us */
508178525Sjb
509178525Sjb	if ((ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]) != 0)
510178525Sjb		return (CTF_INDEX_TO_TYPE(ntype, (fp->ctf_flags & LCTF_CHILD)));
511178525Sjb
512178525Sjb	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
513178525Sjb		return (ctf_set_errno(ofp, ECTF_NOTYPE));
514178525Sjb
515178525Sjb	if (ctf_lookup_by_id(&fp, type) == NULL)
516178525Sjb		return (ctf_set_errno(ofp, ECTF_NOTYPE));
517178525Sjb
518178525Sjb	if ((ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]) != 0)
519178525Sjb		return (CTF_INDEX_TO_TYPE(ntype, (fp->ctf_flags & LCTF_CHILD)));
520178525Sjb
521178525Sjb	return (ctf_set_errno(ofp, ECTF_NOTYPE));
522178525Sjb}
523178525Sjb
524178525Sjb/*
525178525Sjb * Return the encoding for the specified INTEGER or FLOAT.
526178525Sjb */
527178525Sjbint
528178525Sjbctf_type_encoding(ctf_file_t *fp, ctf_id_t type, ctf_encoding_t *ep)
529178525Sjb{
530178525Sjb	ctf_file_t *ofp = fp;
531178525Sjb	const ctf_type_t *tp;
532178525Sjb	ssize_t increment;
533178525Sjb	uint_t data;
534178525Sjb
535178525Sjb	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
536178525Sjb		return (CTF_ERR); /* errno is set for us */
537178525Sjb
538178525Sjb	(void) ctf_get_ctt_size(fp, tp, NULL, &increment);
539178525Sjb
540178525Sjb	switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
541178525Sjb	case CTF_K_INTEGER:
542178525Sjb		data = *(const uint_t *)((uintptr_t)tp + increment);
543178525Sjb		ep->cte_format = CTF_INT_ENCODING(data);
544178525Sjb		ep->cte_offset = CTF_INT_OFFSET(data);
545178525Sjb		ep->cte_bits = CTF_INT_BITS(data);
546178525Sjb		break;
547178525Sjb	case CTF_K_FLOAT:
548178525Sjb		data = *(const uint_t *)((uintptr_t)tp + increment);
549178525Sjb		ep->cte_format = CTF_FP_ENCODING(data);
550178525Sjb		ep->cte_offset = CTF_FP_OFFSET(data);
551178525Sjb		ep->cte_bits = CTF_FP_BITS(data);
552178525Sjb		break;
553178525Sjb	default:
554178525Sjb		return (ctf_set_errno(ofp, ECTF_NOTINTFP));
555178525Sjb	}
556178525Sjb
557178525Sjb	return (0);
558178525Sjb}
559178525Sjb
560178525Sjbint
561178525Sjbctf_type_cmp(ctf_file_t *lfp, ctf_id_t ltype, ctf_file_t *rfp, ctf_id_t rtype)
562178525Sjb{
563178525Sjb	int rval;
564178525Sjb
565178525Sjb	if (ltype < rtype)
566178525Sjb		rval = -1;
567178525Sjb	else if (ltype > rtype)
568178525Sjb		rval = 1;
569178525Sjb	else
570178525Sjb		rval = 0;
571178525Sjb
572178525Sjb	if (lfp == rfp)
573178525Sjb		return (rval);
574178525Sjb
575178525Sjb	if (CTF_TYPE_ISPARENT(ltype) && lfp->ctf_parent != NULL)
576178525Sjb		lfp = lfp->ctf_parent;
577178525Sjb
578178525Sjb	if (CTF_TYPE_ISPARENT(rtype) && rfp->ctf_parent != NULL)
579178525Sjb		rfp = rfp->ctf_parent;
580178525Sjb
581178525Sjb	if (lfp < rfp)
582178525Sjb		return (-1);
583178525Sjb
584178525Sjb	if (lfp > rfp)
585178525Sjb		return (1);
586178525Sjb
587178525Sjb	return (rval);
588178525Sjb}
589178525Sjb
590178525Sjb/*
591178525Sjb * Return a boolean value indicating if two types are compatible integers or
592178525Sjb * floating-pointer values.  This function returns true if the two types are
593178525Sjb * the same, or if they have the same ASCII name and encoding properties.
594178525Sjb * This function could be extended to test for compatibility for other kinds.
595178525Sjb */
596178525Sjbint
597178525Sjbctf_type_compat(ctf_file_t *lfp, ctf_id_t ltype,
598178525Sjb    ctf_file_t *rfp, ctf_id_t rtype)
599178525Sjb{
600178525Sjb	const ctf_type_t *ltp, *rtp;
601178525Sjb	ctf_encoding_t le, re;
602178525Sjb	ctf_arinfo_t la, ra;
603178525Sjb	uint_t lkind, rkind;
604178525Sjb
605178525Sjb	if (ctf_type_cmp(lfp, ltype, rfp, rtype) == 0)
606178525Sjb		return (1);
607178525Sjb
608178525Sjb	ltype = ctf_type_resolve(lfp, ltype);
609178525Sjb	lkind = ctf_type_kind(lfp, ltype);
610178525Sjb
611178525Sjb	rtype = ctf_type_resolve(rfp, rtype);
612178525Sjb	rkind = ctf_type_kind(rfp, rtype);
613178525Sjb
614178525Sjb	if (lkind != rkind ||
615178525Sjb	    (ltp = ctf_lookup_by_id(&lfp, ltype)) == NULL ||
616178525Sjb	    (rtp = ctf_lookup_by_id(&rfp, rtype)) == NULL ||
617178525Sjb	    strcmp(ctf_strptr(lfp, ltp->ctt_name),
618178525Sjb	    ctf_strptr(rfp, rtp->ctt_name)) != 0)
619178525Sjb		return (0);
620178525Sjb
621178525Sjb	switch (lkind) {
622178525Sjb	case CTF_K_INTEGER:
623178525Sjb	case CTF_K_FLOAT:
624178525Sjb		return (ctf_type_encoding(lfp, ltype, &le) == 0 &&
625178525Sjb		    ctf_type_encoding(rfp, rtype, &re) == 0 &&
626178525Sjb		    bcmp(&le, &re, sizeof (ctf_encoding_t)) == 0);
627178525Sjb	case CTF_K_POINTER:
628178525Sjb		return (ctf_type_compat(lfp, ctf_type_reference(lfp, ltype),
629178525Sjb		    rfp, ctf_type_reference(rfp, rtype)));
630178525Sjb	case CTF_K_ARRAY:
631178525Sjb		return (ctf_array_info(lfp, ltype, &la) == 0 &&
632178525Sjb		    ctf_array_info(rfp, rtype, &ra) == 0 &&
633178525Sjb		    la.ctr_nelems == ra.ctr_nelems && ctf_type_compat(
634178525Sjb		    lfp, la.ctr_contents, rfp, ra.ctr_contents) &&
635178525Sjb		    ctf_type_compat(lfp, la.ctr_index, rfp, ra.ctr_index));
636178525Sjb	case CTF_K_STRUCT:
637178525Sjb	case CTF_K_UNION:
638178525Sjb		return (ctf_type_size(lfp, ltype) == ctf_type_size(rfp, rtype));
639178525Sjb	case CTF_K_ENUM:
640178525Sjb	case CTF_K_FORWARD:
641178525Sjb		return (1); /* no other checks required for these type kinds */
642178525Sjb	default:
643178525Sjb		return (0); /* should not get here since we did a resolve */
644178525Sjb	}
645178525Sjb}
646178525Sjb
647313129Smarkjstatic int
648313129Smarkj_ctf_member_info(ctf_file_t *fp, ctf_id_t type, const char *name, ulong_t off,
649178525Sjb    ctf_membinfo_t *mip)
650178525Sjb{
651178525Sjb	ctf_file_t *ofp = fp;
652178525Sjb	const ctf_type_t *tp;
653178525Sjb	ssize_t size, increment;
654178525Sjb	uint_t kind, n;
655178525Sjb
656178525Sjb	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
657178525Sjb		return (CTF_ERR); /* errno is set for us */
658178525Sjb
659178525Sjb	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
660178525Sjb		return (CTF_ERR); /* errno is set for us */
661178525Sjb
662178525Sjb	(void) ctf_get_ctt_size(fp, tp, &size, &increment);
663178525Sjb	kind = LCTF_INFO_KIND(fp, tp->ctt_info);
664178525Sjb
665178525Sjb	if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
666178525Sjb		return (ctf_set_errno(ofp, ECTF_NOTSOU));
667178525Sjb
668178525Sjb	if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) {
669178525Sjb		const ctf_member_t *mp = (const ctf_member_t *)
670178525Sjb		    ((uintptr_t)tp + increment);
671178525Sjb
672178525Sjb		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) {
673313129Smarkj			if (mp->ctm_name == 0 &&
674313129Smarkj			    _ctf_member_info(fp, mp->ctm_type, name,
675313129Smarkj			    mp->ctm_offset + off, mip) == 0)
676313129Smarkj				return (0);
677178525Sjb			if (strcmp(ctf_strptr(fp, mp->ctm_name), name) == 0) {
678178525Sjb				mip->ctm_type = mp->ctm_type;
679313129Smarkj				mip->ctm_offset = mp->ctm_offset + off;
680178525Sjb				return (0);
681178525Sjb			}
682178525Sjb		}
683178525Sjb	} else {
684178525Sjb		const ctf_lmember_t *lmp = (const ctf_lmember_t *)
685178525Sjb		    ((uintptr_t)tp + increment);
686178525Sjb
687178525Sjb		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) {
688313129Smarkj			if (lmp->ctlm_name == 0 &&
689313129Smarkj			    _ctf_member_info(fp, lmp->ctlm_name, name,
690313129Smarkj			    (ulong_t)CTF_LMEM_OFFSET(lmp) + off, mip) == 0)
691313129Smarkj				return (0);
692178525Sjb			if (strcmp(ctf_strptr(fp, lmp->ctlm_name), name) == 0) {
693178525Sjb				mip->ctm_type = lmp->ctlm_type;
694313129Smarkj				mip->ctm_offset =
695313129Smarkj				    (ulong_t)CTF_LMEM_OFFSET(lmp) + off;
696178525Sjb				return (0);
697178525Sjb			}
698178525Sjb		}
699178525Sjb	}
700178525Sjb
701178525Sjb	return (ctf_set_errno(ofp, ECTF_NOMEMBNAM));
702178525Sjb}
703178525Sjb
704178525Sjb/*
705313129Smarkj * Return the type and offset for a given member of a STRUCT or UNION.
706313129Smarkj */
707313129Smarkjint
708313129Smarkjctf_member_info(ctf_file_t *fp, ctf_id_t type, const char *name,
709313129Smarkj    ctf_membinfo_t *mip)
710313129Smarkj{
711313129Smarkj
712313129Smarkj	return (_ctf_member_info(fp, type, name, 0, mip));
713313129Smarkj}
714313129Smarkj
715313129Smarkj/*
716178525Sjb * Return the array type, index, and size information for the specified ARRAY.
717178525Sjb */
718178525Sjbint
719178525Sjbctf_array_info(ctf_file_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
720178525Sjb{
721178525Sjb	ctf_file_t *ofp = fp;
722178525Sjb	const ctf_type_t *tp;
723178525Sjb	const ctf_array_t *ap;
724178525Sjb	ssize_t increment;
725178525Sjb
726178525Sjb	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
727178525Sjb		return (CTF_ERR); /* errno is set for us */
728178525Sjb
729178525Sjb	if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ARRAY)
730178525Sjb		return (ctf_set_errno(ofp, ECTF_NOTARRAY));
731178525Sjb
732178525Sjb	(void) ctf_get_ctt_size(fp, tp, NULL, &increment);
733178525Sjb
734178525Sjb	ap = (const ctf_array_t *)((uintptr_t)tp + increment);
735178525Sjb	arp->ctr_contents = ap->cta_contents;
736178525Sjb	arp->ctr_index = ap->cta_index;
737178525Sjb	arp->ctr_nelems = ap->cta_nelems;
738178525Sjb
739178525Sjb	return (0);
740178525Sjb}
741178525Sjb
742178525Sjb/*
743178525Sjb * Convert the specified value to the corresponding enum member name, if a
744178525Sjb * matching name can be found.  Otherwise NULL is returned.
745178525Sjb */
746178525Sjbconst char *
747178525Sjbctf_enum_name(ctf_file_t *fp, ctf_id_t type, int value)
748178525Sjb{
749178525Sjb	ctf_file_t *ofp = fp;
750178525Sjb	const ctf_type_t *tp;
751178525Sjb	const ctf_enum_t *ep;
752178525Sjb	ssize_t increment;
753178525Sjb	uint_t n;
754178525Sjb
755178525Sjb	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
756178525Sjb		return (NULL); /* errno is set for us */
757178525Sjb
758178525Sjb	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
759178525Sjb		return (NULL); /* errno is set for us */
760178525Sjb
761178525Sjb	if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) {
762178525Sjb		(void) ctf_set_errno(ofp, ECTF_NOTENUM);
763178525Sjb		return (NULL);
764178525Sjb	}
765178525Sjb
766178525Sjb	(void) ctf_get_ctt_size(fp, tp, NULL, &increment);
767178525Sjb
768178525Sjb	ep = (const ctf_enum_t *)((uintptr_t)tp + increment);
769178525Sjb
770178525Sjb	for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) {
771178525Sjb		if (ep->cte_value == value)
772178525Sjb			return (ctf_strptr(fp, ep->cte_name));
773178525Sjb	}
774178525Sjb
775178525Sjb	(void) ctf_set_errno(ofp, ECTF_NOENUMNAM);
776178525Sjb	return (NULL);
777178525Sjb}
778178525Sjb
779178525Sjb/*
780178525Sjb * Convert the specified enum tag name to the corresponding value, if a
781178525Sjb * matching name can be found.  Otherwise CTF_ERR is returned.
782178525Sjb */
783178525Sjbint
784178525Sjbctf_enum_value(ctf_file_t *fp, ctf_id_t type, const char *name, int *valp)
785178525Sjb{
786178525Sjb	ctf_file_t *ofp = fp;
787178525Sjb	const ctf_type_t *tp;
788178525Sjb	const ctf_enum_t *ep;
789178525Sjb	ssize_t size, increment;
790178525Sjb	uint_t n;
791178525Sjb
792178525Sjb	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
793178525Sjb		return (CTF_ERR); /* errno is set for us */
794178525Sjb
795178525Sjb	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
796178525Sjb		return (CTF_ERR); /* errno is set for us */
797178525Sjb
798178525Sjb	if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) {
799178525Sjb		(void) ctf_set_errno(ofp, ECTF_NOTENUM);
800178525Sjb		return (CTF_ERR);
801178525Sjb	}
802178525Sjb
803178525Sjb	(void) ctf_get_ctt_size(fp, tp, &size, &increment);
804178525Sjb
805178525Sjb	ep = (const ctf_enum_t *)((uintptr_t)tp + increment);
806178525Sjb
807178525Sjb	for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) {
808178525Sjb		if (strcmp(ctf_strptr(fp, ep->cte_name), name) == 0) {
809178525Sjb			if (valp != NULL)
810178525Sjb				*valp = ep->cte_value;
811178525Sjb			return (0);
812178525Sjb		}
813178525Sjb	}
814178525Sjb
815178525Sjb	(void) ctf_set_errno(ofp, ECTF_NOENUMNAM);
816178525Sjb	return (CTF_ERR);
817178525Sjb}
818178525Sjb
819178525Sjb/*
820178525Sjb * Recursively visit the members of any type.  This function is used as the
821178525Sjb * engine for ctf_type_visit, below.  We resolve the input type, recursively
822178525Sjb * invoke ourself for each type member if the type is a struct or union, and
823178525Sjb * then invoke the callback function on the current type.  If any callback
824178525Sjb * returns non-zero, we abort and percolate the error code back up to the top.
825178525Sjb */
826178525Sjbstatic int
827178525Sjbctf_type_rvisit(ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg,
828178525Sjb    const char *name, ulong_t offset, int depth)
829178525Sjb{
830178525Sjb	ctf_id_t otype = type;
831178525Sjb	const ctf_type_t *tp;
832178525Sjb	ssize_t size, increment;
833178525Sjb	uint_t kind, n;
834178525Sjb	int rc;
835178525Sjb
836178525Sjb	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
837178525Sjb		return (CTF_ERR); /* errno is set for us */
838178525Sjb
839178525Sjb	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
840178525Sjb		return (CTF_ERR); /* errno is set for us */
841178525Sjb
842178525Sjb	if ((rc = func(name, otype, offset, depth, arg)) != 0)
843178525Sjb		return (rc);
844178525Sjb
845178525Sjb	kind = LCTF_INFO_KIND(fp, tp->ctt_info);
846178525Sjb
847178525Sjb	if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
848178525Sjb		return (0);
849178525Sjb
850178525Sjb	(void) ctf_get_ctt_size(fp, tp, &size, &increment);
851178525Sjb
852178525Sjb	if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) {
853178525Sjb		const ctf_member_t *mp = (const ctf_member_t *)
854178525Sjb		    ((uintptr_t)tp + increment);
855178525Sjb
856178525Sjb		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) {
857178525Sjb			if ((rc = ctf_type_rvisit(fp, mp->ctm_type,
858178525Sjb			    func, arg, ctf_strptr(fp, mp->ctm_name),
859178525Sjb			    offset + mp->ctm_offset, depth + 1)) != 0)
860178525Sjb				return (rc);
861178525Sjb		}
862178525Sjb
863178525Sjb	} else {
864178525Sjb		const ctf_lmember_t *lmp = (const ctf_lmember_t *)
865178525Sjb		    ((uintptr_t)tp + increment);
866178525Sjb
867178525Sjb		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) {
868178525Sjb			if ((rc = ctf_type_rvisit(fp, lmp->ctlm_type,
869178525Sjb			    func, arg, ctf_strptr(fp, lmp->ctlm_name),
870178525Sjb			    offset + (ulong_t)CTF_LMEM_OFFSET(lmp),
871178525Sjb			    depth + 1)) != 0)
872178525Sjb				return (rc);
873178525Sjb		}
874178525Sjb	}
875178525Sjb
876178525Sjb	return (0);
877178525Sjb}
878178525Sjb
879178525Sjb/*
880178525Sjb * Recursively visit the members of any type.  We pass the name, member
881178525Sjb * type, and offset of each member to the specified callback function.
882178525Sjb */
883178525Sjbint
884178525Sjbctf_type_visit(ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg)
885178525Sjb{
886178525Sjb	return (ctf_type_rvisit(fp, type, func, arg, "", 0, 0));
887178525Sjb}
888