xref: /illumos-gate/usr/src/common/ctf/ctf_types.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 
32 ssize_t
33 ctf_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  */
59 int
60 ctf_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  */
110 int
111 ctf_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  */
146 int
147 ctf_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  */
169 ctf_id_t
170 ctf_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  */
202 ssize_t
203 ctf_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  */
308 char *
309 ctf_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  */
319 ssize_t
320 ctf_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  */
368 ssize_t
369 ctf_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  */
432 int
433 ctf_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  */
447 ctf_id_t
448 ctf_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  */
475 ctf_id_t
476 ctf_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  */
502 int
503 ctf_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 
535 int
536 ctf_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  */
571 int
572 ctf_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  */
625 int
626 ctf_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  */
676 int
677 ctf_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  */
704 const char *
705 ctf_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  */
741 int
742 ctf_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  */
784 static int
785 ctf_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  */
841 int
842 ctf_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