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