ctf_types.c revision 285830
11590Srgrimes/*
21590Srgrimes * CDDL HEADER START
31590Srgrimes *
41590Srgrimes * The contents of this file are subject to the terms of the
51590Srgrimes * Common Development and Distribution License, Version 1.0 only
61590Srgrimes * (the "License").  You may not use this file except in compliance
71590Srgrimes * with the License.
81590Srgrimes *
91590Srgrimes * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
101590Srgrimes * or http://www.opensolaris.org/os/licensing.
111590Srgrimes * See the License for the specific language governing permissions
121590Srgrimes * and limitations under the License.
131590Srgrimes *
141590Srgrimes * When distributing Covered Code, include this CDDL HEADER in each
151590Srgrimes * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
161590Srgrimes * If applicable, add the following below this CDDL HEADER, with the
171590Srgrimes * fields enclosed by brackets "[]" replaced with your own identifying
181590Srgrimes * information: Portions Copyright [yyyy] [name of copyright owner]
191590Srgrimes *
201590Srgrimes * CDDL HEADER END
211590Srgrimes */
221590Srgrimes
231590Srgrimes/*
241590Srgrimes * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
251590Srgrimes * Use is subject to license terms.
261590Srgrimes */
271590Srgrimes
281590Srgrimes#include <ctf_impl.h>
291590Srgrimes
301590Srgrimesssize_t
311590Srgrimesctf_get_ctt_size(const ctf_file_t *fp, const ctf_type_t *tp, ssize_t *sizep,
321590Srgrimes    ssize_t *incrementp)
3354828Sroberto{
341590Srgrimes	ssize_t size, increment;
351590Srgrimes
3672945Sknu	if (fp->ctf_version > CTF_VERSION_1 &&
3772945Sknu	    tp->ctt_size == CTF_LSIZE_SENT) {
3876250Sphk		size = CTF_TYPE_LSIZE(tp);
3976250Sphk		increment = sizeof (ctf_type_t);
4076250Sphk	} else {
411590Srgrimes		size = tp->ctt_size;
4276250Sphk		increment = sizeof (ctf_stype_t);
4392786Smarkm	}
4476250Sphk
4576250Sphk	if (sizep)
4676250Sphk		*sizep = size;
4776250Sphk	if (incrementp)
4876250Sphk		*incrementp = increment;
4976250Sphk
5076250Sphk	return (size);
5176250Sphk}
5276250Sphk
5376250Sphk/*
5476250Sphk * Iterate over the members of a STRUCT or UNION.  We pass the name, member
5576250Sphk * type, and offset of each member to the specified callback function.
56129812Seik */
5776250Sphkint
5876250Sphkctf_member_iter(ctf_file_t *fp, ctf_id_t type, ctf_member_f *func, void *arg)
5976250Sphk{
6076250Sphk	ctf_file_t *ofp = fp;
6176250Sphk	const ctf_type_t *tp;
6276250Sphk	ssize_t size, increment;
6376250Sphk	uint_t kind, n;
6476250Sphk	int rc;
6576250Sphk
6676250Sphk	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
6776250Sphk		return (CTF_ERR); /* errno is set for us */
6876250Sphk
6983450Sru	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
7097736Stjr		return (CTF_ERR); /* errno is set for us */
71157440Sceri
72157440Sceri	(void) ctf_get_ctt_size(fp, tp, &size, &increment);
73176478Simp	kind = LCTF_INFO_KIND(fp, tp->ctt_info);
7476250Sphk
751590Srgrimes	if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
761590Srgrimes		return (ctf_set_errno(ofp, ECTF_NOTSOU));
7776250Sphk
7876250Sphk	if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) {
7976250Sphk		const ctf_member_t *mp = (const ctf_member_t *)
801590Srgrimes		    ((uintptr_t)tp + increment);
8176250Sphk
8276250Sphk		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) {
8376250Sphk			const char *name = ctf_strptr(fp, mp->ctm_name);
8454828Sroberto			if ((rc = func(name, mp->ctm_type, mp->ctm_offset,
8554828Sroberto			    arg)) != 0)
8682972Sru				return (rc);
8754828Sroberto		}
881590Srgrimes
89129812Seik	} else {
901590Srgrimes		const ctf_lmember_t *lmp = (const ctf_lmember_t *)
91248446Sjilles		    ((uintptr_t)tp + increment);
921590Srgrimes
931590Srgrimes		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) {
941590Srgrimes			const char *name = ctf_strptr(fp, lmp->ctlm_name);
951590Srgrimes			if ((rc = func(name, lmp->ctlm_type,
961590Srgrimes			    (ulong_t)CTF_LMEM_OFFSET(lmp), arg)) != 0)
971590Srgrimes				return (rc);
981590Srgrimes		}
9997736Stjr	}
10097736Stjr
10197736Stjr	return (0);
10297736Stjr}
10397736Stjr
10497736Stjr/*
105158572Skrion * Iterate over the members of an ENUM.  We pass the string name and associated
1061590Srgrimes * integer value of each enum element to the specified callback function.
1071590Srgrimes */
1081590Srgrimesint
10972945Sknuctf_enum_iter(ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg)
1101590Srgrimes{
1111590Srgrimes	ctf_file_t *ofp = fp;
1121590Srgrimes	const ctf_type_t *tp;
1131590Srgrimes	const ctf_enum_t *ep;
114129812Seik	ssize_t increment;
11554828Sroberto	uint_t n;
11682972Sru	int rc;
11754828Sroberto
1181590Srgrimes	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
1191590Srgrimes		return (CTF_ERR); /* errno is set for us */
1201590Srgrimes
1211590Srgrimes	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
1221590Srgrimes		return (CTF_ERR); /* errno is set for us */
1231590Srgrimes
1241590Srgrimes	if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM)
1251590Srgrimes		return (ctf_set_errno(ofp, ECTF_NOTENUM));
12672945Sknu
1271590Srgrimes	(void) ctf_get_ctt_size(fp, tp, NULL, &increment);
1281590Srgrimes
1291590Srgrimes	ep = (const ctf_enum_t *)((uintptr_t)tp + increment);
13097736Stjr
13197736Stjr	for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) {
13297736Stjr		const char *name = ctf_strptr(fp, ep->cte_name);
13397736Stjr		if ((rc = func(name, ep->cte_value, arg)) != 0)
13497736Stjr			return (rc);
13597736Stjr	}
136158572Skrion
1371590Srgrimes	return (0);
1381590Srgrimes}
13991400Sdwmalone
14076250Sphk/*
14176250Sphk * Iterate over every root (user-visible) type in the given CTF container.
1421590Srgrimes * We pass the type ID of each type to the specified callback function.
1431590Srgrimes */
1441590Srgrimesint
1451590Srgrimesctf_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