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