1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23/*
24 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 */
27
28#pragma ident	"@(#)ctf_types.c	1.10	06/01/07 SMI"
29
30#include <ctf_impl.h>
31
32static int
33ctf_type_compat_helper(ctf_file_t*, ctf_id_t, ctf_file_t*,  ctf_id_t, int);
34
35ssize_t
36ctf_get_ctt_size(const ctf_file_t *fp, const ctf_type_t *tp, ssize_t *sizep,
37    ssize_t *incrementp)
38{
39	ssize_t size, increment;
40
41	if (fp->ctf_version > CTF_VERSION_1 &&
42	    tp->ctt_size == CTF_LSIZE_SENT) {
43		size = CTF_TYPE_LSIZE(tp);
44		increment = sizeof (ctf_type_t);
45	} else {
46		size = tp->ctt_size;
47		increment = sizeof (ctf_stype_t);
48	}
49
50	if (sizep)
51		*sizep = size;
52	if (incrementp)
53		*incrementp = increment;
54
55	return (size);
56}
57
58/*
59 * Iterate over the members of a STRUCT or UNION.  We pass the name, member
60 * type, and offset of each member to the specified callback function.
61 */
62int
63ctf_member_iter(ctf_file_t *fp, ctf_id_t type, ctf_member_f *func, void *arg)
64{
65	ctf_file_t *ofp = fp;
66	const ctf_type_t *tp;
67	ssize_t size, increment;
68	uint_t kind, n;
69	int rc;
70
71	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
72		return (CTF_ERR); /* errno is set for us */
73
74	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
75		return (CTF_ERR); /* errno is set for us */
76
77	(void) ctf_get_ctt_size(fp, tp, &size, &increment);
78	kind = LCTF_INFO_KIND(fp, tp->ctt_info);
79
80	if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
81		return (ctf_set_errno(ofp, ECTF_NOTSOU));
82
83	if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) {
84		const ctf_member_t *mp = (const ctf_member_t *)
85		    ((uintptr_t)tp + increment);
86
87		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) {
88			const char *name = ctf_strptr(fp, mp->ctm_name);
89			if ((rc = func(name, mp->ctm_type, mp->ctm_offset,
90			    arg)) != 0)
91				return (rc);
92		}
93
94	} else {
95		const ctf_lmember_t *lmp = (const ctf_lmember_t *)
96		    ((uintptr_t)tp + increment);
97
98		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) {
99			const char *name = ctf_strptr(fp, lmp->ctlm_name);
100			if ((rc = func(name, lmp->ctlm_type,
101			    (ulong_t)CTF_LMEM_OFFSET(lmp), arg)) != 0)
102				return (rc);
103		}
104	}
105
106	return (0);
107}
108
109/*
110 * Iterate over the members of an ENUM.  We pass the string name and associated
111 * integer value of each enum element to the specified callback function.
112 */
113int
114ctf_enum_iter(ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg)
115{
116	ctf_file_t *ofp = fp;
117	const ctf_type_t *tp;
118	const ctf_enum_t *ep;
119	ssize_t increment;
120	uint_t n;
121	int rc;
122
123	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
124		return (CTF_ERR); /* errno is set for us */
125
126	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
127		return (CTF_ERR); /* errno is set for us */
128
129	if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM)
130		return (ctf_set_errno(ofp, ECTF_NOTENUM));
131
132	(void) ctf_get_ctt_size(fp, tp, NULL, &increment);
133
134	ep = (const ctf_enum_t *)((uintptr_t)tp + increment);
135
136	for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) {
137		const char *name = ctf_strptr(fp, ep->cte_name);
138		if ((rc = func(name, ep->cte_value, arg)) != 0)
139			return (rc);
140	}
141
142	return (0);
143}
144
145/*
146 * Iterate over every root (user-visible) type in the given CTF container.
147 * We pass the type ID of each type to the specified callback function.
148 */
149int
150ctf_type_iter(ctf_file_t *fp, ctf_type_f *func, void *arg)
151{
152	ctf_id_t id, max = fp->ctf_typemax;
153	int rc, child = (fp->ctf_flags & LCTF_CHILD);
154
155	for (id = 1; id <= max; id++) {
156		const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR(fp, id);
157		if (CTF_INFO_ISROOT(tp->ctt_info) &&
158		    (rc = func(CTF_INDEX_TO_TYPE(id, child), arg)) != 0)
159			return (rc);
160	}
161
162	return (0);
163}
164
165/*
166 * Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and
167 * RESTRICT nodes until we reach a "base" type node.  This is useful when
168 * we want to follow a type ID to a node that has members or a size.  To guard
169 * against infinite loops, we implement simplified cycle detection and check
170 * each link against itself, the previous node, and the topmost node.
171 */
172ctf_id_t
173ctf_type_resolve(ctf_file_t *fp, ctf_id_t type)
174{
175	ctf_id_t prev = type, otype = type;
176	ctf_file_t *ofp = fp;
177	const ctf_type_t *tp;
178
179	while ((tp = ctf_lookup_by_id(&fp, type)) != NULL) {
180		switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
181		case CTF_K_TYPEDEF:
182		case CTF_K_VOLATILE:
183		case CTF_K_CONST:
184		case CTF_K_RESTRICT:
185			if (tp->ctt_type == type || tp->ctt_type == otype ||
186			    tp->ctt_type == prev) {
187				ctf_dprintf("type %ld cycle detected\n", otype);
188				return (ctf_set_errno(ofp, ECTF_CORRUPT));
189			}
190			prev = type;
191			type = tp->ctt_type;
192			break;
193		default:
194			return (type);
195		}
196	}
197
198	return (CTF_ERR); /* errno is set for us */
199}
200
201/*
202 * Lookup the given type ID and print a string name for it into buf.  Return
203 * the actual number of bytes (not including \0) needed to format the name.
204 */
205ssize_t
206ctf_type_lname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
207{
208	ctf_decl_t cd;
209	ctf_decl_node_t *cdp;
210	ctf_decl_prec_t prec, lp, rp;
211	int ptr, arr;
212	uint_t k;
213
214	if (fp == NULL && type == CTF_ERR)
215		return (-1); /* simplify caller code by permitting CTF_ERR */
216
217	ctf_decl_init(&cd, buf, len);
218	ctf_decl_push(&cd, fp, type);
219
220	if (cd.cd_err != 0) {
221		ctf_decl_fini(&cd);
222		return (ctf_set_errno(fp, cd.cd_err));
223	}
224
225	/*
226	 * If the type graph's order conflicts with lexical precedence order
227	 * for pointers or arrays, then we need to surround the declarations at
228	 * the corresponding lexical precedence with parentheses.  This can
229	 * result in either a parenthesized pointer (*) as in int (*)() or
230	 * int (*)[], or in a parenthesized pointer and array as in int (*[])().
231	 */
232	ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER;
233	arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY;
234
235	rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1;
236	lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1;
237
238	k = CTF_K_POINTER; /* avoid leading whitespace (see below) */
239
240	for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) {
241		for (cdp = ctf_list_next(&cd.cd_nodes[prec]);
242		    cdp != NULL; cdp = ctf_list_next(cdp)) {
243
244			ctf_file_t *rfp = fp;
245			const ctf_type_t *tp =
246			    ctf_lookup_by_id(&rfp, cdp->cd_type);
247			const char *name = ctf_strptr(rfp, tp->ctt_name);
248
249			if (k != CTF_K_POINTER && k != CTF_K_ARRAY)
250				ctf_decl_sprintf(&cd, " ");
251
252			if (lp == prec) {
253				ctf_decl_sprintf(&cd, "(");
254				lp = -1;
255			}
256
257			switch (cdp->cd_kind) {
258			case CTF_K_INTEGER:
259			case CTF_K_FLOAT:
260			case CTF_K_TYPEDEF:
261				ctf_decl_sprintf(&cd, "%s", name);
262				break;
263			case CTF_K_POINTER:
264				ctf_decl_sprintf(&cd, "*");
265				break;
266			case CTF_K_ARRAY:
267				ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n);
268				break;
269			case CTF_K_FUNCTION:
270				ctf_decl_sprintf(&cd, "()");
271				break;
272			case CTF_K_STRUCT:
273			case CTF_K_FORWARD:
274				ctf_decl_sprintf(&cd, "struct %s", name);
275				break;
276			case CTF_K_UNION:
277				ctf_decl_sprintf(&cd, "union %s", name);
278				break;
279			case CTF_K_ENUM:
280				ctf_decl_sprintf(&cd, "enum %s", name);
281				break;
282			case CTF_K_VOLATILE:
283				ctf_decl_sprintf(&cd, "volatile");
284				break;
285			case CTF_K_CONST:
286				ctf_decl_sprintf(&cd, "const");
287				break;
288			case CTF_K_RESTRICT:
289				ctf_decl_sprintf(&cd, "restrict");
290				break;
291			}
292
293			k = cdp->cd_kind;
294		}
295
296		if (rp == prec)
297			ctf_decl_sprintf(&cd, ")");
298	}
299
300	if (cd.cd_len >= len)
301		(void) ctf_set_errno(fp, ECTF_NAMELEN);
302
303	ctf_decl_fini(&cd);
304	return (cd.cd_len);
305}
306
307/*
308 * Lookup the given type ID and print a string name for it into buf.  If buf
309 * is too small, return NULL: the ECTF_NAMELEN error is set on 'fp' for us.
310 */
311char *
312ctf_type_name(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
313{
314	ssize_t rv = ctf_type_lname(fp, type, buf, len);
315	return (rv >= 0 && rv < len ? buf : NULL);
316}
317
318/*
319 * Resolve the type down to a base type node, and then return the size
320 * of the type storage in bytes.
321 */
322ssize_t
323ctf_type_size(ctf_file_t *fp, ctf_id_t type)
324{
325	const ctf_type_t *tp;
326	ssize_t size;
327	ctf_arinfo_t ar;
328
329	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
330		return (-1); /* errno is set for us */
331
332	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
333		return (-1); /* errno is set for us */
334
335	switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
336	case CTF_K_POINTER:
337		return (fp->ctf_dmodel->ctd_pointer);
338
339	case CTF_K_FUNCTION:
340		return (0); /* function size is only known by symtab */
341
342	case CTF_K_ENUM:
343		return (fp->ctf_dmodel->ctd_int);
344
345	case CTF_K_ARRAY:
346		/*
347		 * Array size is not directly returned by stabs data.  Instead,
348		 * it defines the element type and requires the user to perform
349		 * the multiplication.  If ctf_get_ctt_size() returns zero, the
350		 * current version of ctfconvert does not compute member sizes
351		 * and we compute the size here on its behalf.
352		 */
353		if ((size = ctf_get_ctt_size(fp, tp, NULL, NULL)) > 0)
354			return (size);
355
356		if (ctf_array_info(fp, type, &ar) == CTF_ERR ||
357		    (size = ctf_type_size(fp, ar.ctr_contents)) == CTF_ERR)
358			return (-1); /* errno is set for us */
359
360		return (size * ar.ctr_nelems);
361
362	default:
363		return (ctf_get_ctt_size(fp, tp, NULL, NULL));
364	}
365}
366
367/*
368 * Resolve the type down to a base type node, and then return the alignment
369 * needed for the type storage in bytes.
370 */
371ssize_t
372ctf_type_align(ctf_file_t *fp, ctf_id_t type)
373{
374	const ctf_type_t *tp;
375	ctf_arinfo_t r;
376
377	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
378		return (-1); /* errno is set for us */
379
380	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
381		return (-1); /* errno is set for us */
382
383	switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
384	case CTF_K_POINTER:
385	case CTF_K_FUNCTION:
386		return (fp->ctf_dmodel->ctd_pointer);
387
388	case CTF_K_ARRAY:
389		if (ctf_array_info(fp, type, &r) == CTF_ERR)
390			return (-1); /* errno is set for us */
391		return (ctf_type_align(fp, r.ctr_contents));
392
393	case CTF_K_STRUCT:
394	case CTF_K_UNION: {
395		uint_t n = LCTF_INFO_VLEN(fp, tp->ctt_info);
396		ssize_t size, increment;
397		size_t align = 0;
398		const void *vmp;
399
400		(void) ctf_get_ctt_size(fp, tp, &size, &increment);
401		vmp = (uchar_t *)tp + increment;
402
403		if (LCTF_INFO_KIND(fp, tp->ctt_info) == CTF_K_STRUCT)
404			n = MIN(n, 1); /* only use first member for structs */
405
406		if (fp->ctf_version == CTF_VERSION_1 ||
407		    size < CTF_LSTRUCT_THRESH) {
408			const ctf_member_t *mp = vmp;
409			for (; n != 0; n--, mp++) {
410				ssize_t am = ctf_type_align(fp, mp->ctm_type);
411				align = MAX(align, am);
412			}
413		} else {
414			const ctf_lmember_t *lmp = vmp;
415			for (; n != 0; n--, lmp++) {
416				ssize_t am = ctf_type_align(fp, lmp->ctlm_type);
417				align = MAX(align, am);
418			}
419		}
420
421		return (align);
422	}
423
424	case CTF_K_ENUM:
425		return (fp->ctf_dmodel->ctd_int);
426
427	default:
428		return (ctf_get_ctt_size(fp, tp, NULL, NULL));
429	}
430}
431
432/*
433 * Return the kind (CTF_K_* constant) for the specified type ID.
434 */
435int
436ctf_type_kind(ctf_file_t *fp, ctf_id_t type)
437{
438	const ctf_type_t *tp;
439
440	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
441		return (CTF_ERR); /* errno is set for us */
442
443	return (LCTF_INFO_KIND(fp, tp->ctt_info));
444}
445
446/*
447 * If the type is one that directly references another type (such as POINTER),
448 * then return the ID of the type to which it refers.
449 */
450ctf_id_t
451ctf_type_reference(ctf_file_t *fp, ctf_id_t type)
452{
453	ctf_file_t *ofp = fp;
454	const ctf_type_t *tp;
455
456	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
457		return (CTF_ERR); /* errno is set for us */
458
459	switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
460	case CTF_K_POINTER:
461	case CTF_K_TYPEDEF:
462	case CTF_K_VOLATILE:
463	case CTF_K_CONST:
464	case CTF_K_RESTRICT:
465		return (tp->ctt_type);
466	default:
467		return (ctf_set_errno(ofp, ECTF_NOTREF));
468	}
469}
470
471/*
472 * Find a pointer to type by looking in fp->ctf_ptrtab.  If we can't find a
473 * pointer to the given type, see if we can compute a pointer to the type
474 * resulting from resolving the type down to its base type and use that
475 * instead.  This helps with cases where the CTF data includes "struct foo *"
476 * but not "foo_t *" and the user accesses "foo_t *" in the debugger.
477 */
478ctf_id_t
479ctf_type_pointer(ctf_file_t *fp, ctf_id_t type)
480{
481	ctf_file_t *ofp = fp;
482	ctf_id_t ntype;
483
484	if (ctf_lookup_by_id(&fp, type) == NULL)
485		return (CTF_ERR); /* errno is set for us */
486
487	if ((ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]) != 0)
488		return (CTF_INDEX_TO_TYPE(ntype, (fp->ctf_flags & LCTF_CHILD)));
489
490	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
491		return (ctf_set_errno(ofp, ECTF_NOTYPE));
492
493	if (ctf_lookup_by_id(&fp, type) == NULL)
494		return (ctf_set_errno(ofp, ECTF_NOTYPE));
495
496	if ((ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]) != 0)
497		return (CTF_INDEX_TO_TYPE(ntype, (fp->ctf_flags & LCTF_CHILD)));
498
499	return (ctf_set_errno(ofp, ECTF_NOTYPE));
500}
501
502/*
503 * Return the encoding for the specified INTEGER or FLOAT.
504 */
505int
506ctf_type_encoding(ctf_file_t *fp, ctf_id_t type, ctf_encoding_t *ep)
507{
508	ctf_file_t *ofp = fp;
509	const ctf_type_t *tp;
510	ssize_t increment;
511	uint_t data;
512
513	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
514		return (CTF_ERR); /* errno is set for us */
515
516	(void) ctf_get_ctt_size(fp, tp, NULL, &increment);
517
518	switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
519	case CTF_K_INTEGER:
520		data = *(const uint_t *)((uintptr_t)tp + increment);
521		ep->cte_format = CTF_INT_ENCODING(data);
522		ep->cte_offset = CTF_INT_OFFSET(data);
523		ep->cte_bits = CTF_INT_BITS(data);
524		break;
525	case CTF_K_FLOAT:
526		data = *(const uint_t *)((uintptr_t)tp + increment);
527		ep->cte_format = CTF_FP_ENCODING(data);
528		ep->cte_offset = CTF_FP_OFFSET(data);
529		ep->cte_bits = CTF_FP_BITS(data);
530		break;
531	default:
532		return (ctf_set_errno(ofp, ECTF_NOTINTFP));
533	}
534
535	return (0);
536}
537
538int
539ctf_type_cmp(ctf_file_t *lfp, ctf_id_t ltype, ctf_file_t *rfp, ctf_id_t rtype)
540{
541	int rval;
542
543	if (ltype < rtype)
544		rval = -1;
545	else if (ltype > rtype)
546		rval = 1;
547	else
548		rval = 0;
549
550	if (lfp == rfp)
551		return (rval);
552
553	if (CTF_TYPE_ISPARENT(ltype) && lfp->ctf_parent != NULL)
554		lfp = lfp->ctf_parent;
555
556	if (CTF_TYPE_ISPARENT(rtype) && rfp->ctf_parent != NULL)
557		rfp = rfp->ctf_parent;
558
559	if (lfp < rfp)
560		return (-1);
561
562	if (lfp > rfp)
563		return (1);
564
565	return (rval);
566}
567
568/*
569 * Return a boolean value indicating if two types are compatible integers or
570 * floating-pointer values.  This function returns true if the two types are
571 * the same, or if they have the same ASCII name and encoding properties.
572 * This function could be extended to test for compatibility for other kinds.
573 */
574int
575ctf_type_compat(ctf_file_t *lfp, ctf_id_t ltype, ctf_file_t *rfp, ctf_id_t rtype)
576{
577	return ctf_type_compat_helper(lfp, ltype, rfp, rtype, 1);
578}
579
580/*
581 * This is a less pedantic version of ctf_type_compat.  For printf
582 * compatibility, the function does not need the type to have the
583 * same type.  Calling this function will only check for encoding
584 * compatibility.
585 */
586int
587ctf_type_printf_compat(ctf_file_t *lfp, ctf_id_t ltype, ctf_file_t *rfp, ctf_id_t rtype)
588{
589	return ctf_type_compat_helper(lfp, ltype, rfp, rtype, 0);
590}
591
592
593int
594ctf_type_compat_helper(ctf_file_t *lfp, ctf_id_t ltype, ctf_file_t *rfp,  ctf_id_t rtype, int nameMustMatch)
595{
596	const ctf_type_t *ltp, *rtp;
597	ctf_encoding_t le, re;
598	ctf_arinfo_t la, ra;
599	uint_t lkind, rkind;
600
601	if (ctf_type_cmp(lfp, ltype, rfp, rtype) == 0)
602		return (1);
603
604	ltype = ctf_type_resolve(lfp, ltype);
605	lkind = ctf_type_kind(lfp, ltype);
606
607	rtype = ctf_type_resolve(rfp, rtype);
608	rkind = ctf_type_kind(rfp, rtype);
609
610	ltp = ctf_lookup_by_id(&lfp, ltype);
611	rtp = ctf_lookup_by_id(&rfp, rtype);
612
613	if (nameMustMatch) {
614		if (lkind != rkind || ltp == NULL || rtp == NULL ||
615		    strcmp(ctf_strptr(lfp, ltp->ctt_name), ctf_strptr(rfp, rtp->ctt_name)) != 0)
616			return (0);
617	}
618
619	switch (lkind) {
620	case CTF_K_INTEGER:
621	case CTF_K_FLOAT:
622		return (ctf_type_encoding(lfp, ltype, &le) == 0 &&
623		    ctf_type_encoding(rfp, rtype, &re) == 0 &&
624		    bcmp(&le, &re, sizeof (ctf_encoding_t)) == 0);
625	case CTF_K_POINTER:
626		return (ctf_type_compat(lfp, ctf_type_reference(lfp, ltype),
627		    rfp, ctf_type_reference(rfp, rtype)));
628	case CTF_K_ARRAY:
629		return (ctf_array_info(lfp, ltype, &la) == 0 &&
630		    ctf_array_info(rfp, rtype, &ra) == 0 &&
631		    la.ctr_nelems == ra.ctr_nelems && ctf_type_compat(
632		    lfp, la.ctr_contents, rfp, ra.ctr_contents) &&
633		    ctf_type_compat(lfp, la.ctr_index, rfp, ra.ctr_index));
634	case CTF_K_STRUCT:
635	case CTF_K_UNION:
636		return (ctf_type_size(lfp, ltype) == ctf_type_size(rfp, rtype));
637	case CTF_K_ENUM:
638	case CTF_K_FORWARD:
639		return (1); /* no other checks required for these type kinds */
640	default:
641		return (0); /* should not get here since we did a resolve */
642	}
643}
644
645/*
646 * Return the type and offset for a given member of a STRUCT or UNION.
647 */
648int
649ctf_member_info(ctf_file_t *fp, ctf_id_t type, const char *name,
650    ctf_membinfo_t *mip)
651{
652	ctf_file_t *ofp = fp;
653	const ctf_type_t *tp;
654	ssize_t size, increment;
655	uint_t kind, n;
656
657	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
658		return (CTF_ERR); /* errno is set for us */
659
660	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
661		return (CTF_ERR); /* errno is set for us */
662
663	(void) ctf_get_ctt_size(fp, tp, &size, &increment);
664	kind = LCTF_INFO_KIND(fp, tp->ctt_info);
665
666	if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
667		return (ctf_set_errno(ofp, ECTF_NOTSOU));
668
669	if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) {
670		const ctf_member_t *mp = (const ctf_member_t *)
671		    ((uintptr_t)tp + increment);
672
673		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) {
674			if (strcmp(ctf_strptr(fp, mp->ctm_name), name) == 0) {
675				mip->ctm_type = mp->ctm_type;
676				mip->ctm_offset = mp->ctm_offset;
677				return (0);
678			}
679		}
680	} else {
681		const ctf_lmember_t *lmp = (const ctf_lmember_t *)
682		    ((uintptr_t)tp + increment);
683
684		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) {
685			if (strcmp(ctf_strptr(fp, lmp->ctlm_name), name) == 0) {
686				mip->ctm_type = lmp->ctlm_type;
687				mip->ctm_offset = (ulong_t)CTF_LMEM_OFFSET(lmp);
688				return (0);
689			}
690		}
691	}
692
693	return (ctf_set_errno(ofp, ECTF_NOMEMBNAM));
694}
695
696/*
697 * Return the array type, index, and size information for the specified ARRAY.
698 */
699int
700ctf_array_info(ctf_file_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
701{
702	ctf_file_t *ofp = fp;
703	const ctf_type_t *tp;
704	const ctf_array_t *ap;
705	ssize_t increment;
706
707	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
708		return (CTF_ERR); /* errno is set for us */
709
710	if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ARRAY)
711		return (ctf_set_errno(ofp, ECTF_NOTARRAY));
712
713	(void) ctf_get_ctt_size(fp, tp, NULL, &increment);
714
715	ap = (const ctf_array_t *)((uintptr_t)tp + increment);
716	arp->ctr_contents = ap->cta_contents;
717	arp->ctr_index = ap->cta_index;
718	arp->ctr_nelems = ap->cta_nelems;
719
720	return (0);
721}
722
723/*
724 * Convert the specified value to the corresponding enum member name, if a
725 * matching name can be found.  Otherwise NULL is returned.
726 */
727const char *
728ctf_enum_name(ctf_file_t *fp, ctf_id_t type, int value)
729{
730	ctf_file_t *ofp = fp;
731	const ctf_type_t *tp;
732	const ctf_enum_t *ep;
733	ssize_t increment;
734	uint_t n;
735
736	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
737		return (NULL); /* errno is set for us */
738
739	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
740		return (NULL); /* errno is set for us */
741
742	if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) {
743		(void) ctf_set_errno(ofp, ECTF_NOTENUM);
744		return (NULL);
745	}
746
747	(void) ctf_get_ctt_size(fp, tp, NULL, &increment);
748
749	ep = (const ctf_enum_t *)((uintptr_t)tp + increment);
750
751	for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) {
752		if (ep->cte_value == value)
753			return (ctf_strptr(fp, ep->cte_name));
754	}
755
756	(void) ctf_set_errno(ofp, ECTF_NOENUMNAM);
757	return (NULL);
758}
759
760/*
761 * Convert the specified enum tag name to the corresponding value, if a
762 * matching name can be found.  Otherwise CTF_ERR is returned.
763 */
764int
765ctf_enum_value(ctf_file_t *fp, ctf_id_t type, const char *name, int *valp)
766{
767	ctf_file_t *ofp = fp;
768	const ctf_type_t *tp;
769	const ctf_enum_t *ep;
770	ssize_t size, increment;
771	uint_t n;
772
773	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
774		return (CTF_ERR); /* errno is set for us */
775
776	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
777		return (CTF_ERR); /* errno is set for us */
778
779	if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) {
780		(void) ctf_set_errno(ofp, ECTF_NOTENUM);
781		return (CTF_ERR);
782	}
783
784	(void) ctf_get_ctt_size(fp, tp, &size, &increment);
785
786	ep = (const ctf_enum_t *)((uintptr_t)tp + increment);
787
788	for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) {
789		if (strcmp(ctf_strptr(fp, ep->cte_name), name) == 0) {
790			if (valp != NULL)
791				*valp = ep->cte_value;
792			return (0);
793		}
794	}
795
796	(void) ctf_set_errno(ofp, ECTF_NOENUMNAM);
797	return (CTF_ERR);
798}
799
800/*
801 * Recursively visit the members of any type.  This function is used as the
802 * engine for ctf_type_visit, below.  We resolve the input type, recursively
803 * invoke ourself for each type member if the type is a struct or union, and
804 * then invoke the callback function on the current type.  If any callback
805 * returns non-zero, we abort and percolate the error code back up to the top.
806 */
807static int
808ctf_type_rvisit(ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg,
809    const char *name, ulong_t offset, int depth)
810{
811	ctf_id_t otype = type;
812	const ctf_type_t *tp;
813	ssize_t size, increment;
814	uint_t kind, n;
815	int rc;
816
817	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
818		return (CTF_ERR); /* errno is set for us */
819
820	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
821		return (CTF_ERR); /* errno is set for us */
822
823	if ((rc = func(name, otype, offset, depth, arg)) != 0)
824		return (rc);
825
826	kind = LCTF_INFO_KIND(fp, tp->ctt_info);
827
828	if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
829		return (0);
830
831	(void) ctf_get_ctt_size(fp, tp, &size, &increment);
832
833	if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) {
834		const ctf_member_t *mp = (const ctf_member_t *)
835		    ((uintptr_t)tp + increment);
836
837		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) {
838			if ((rc = ctf_type_rvisit(fp, mp->ctm_type,
839			    func, arg, ctf_strptr(fp, mp->ctm_name),
840			    offset + mp->ctm_offset, depth + 1)) != 0)
841				return (rc);
842		}
843
844	} else {
845		const ctf_lmember_t *lmp = (const ctf_lmember_t *)
846		    ((uintptr_t)tp + increment);
847
848		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) {
849			if ((rc = ctf_type_rvisit(fp, lmp->ctlm_type,
850			    func, arg, ctf_strptr(fp, lmp->ctlm_name),
851			    offset + (ulong_t)CTF_LMEM_OFFSET(lmp),
852			    depth + 1)) != 0)
853				return (rc);
854		}
855	}
856
857	return (0);
858}
859
860/*
861 * Recursively visit the members of any type.  We pass the name, member
862 * type, and offset of each member to the specified callback function.
863 */
864int
865ctf_type_visit(ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg)
866{
867	return (ctf_type_rvisit(fp, type, func, arg, "", 0, 0));
868}
869