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