1193323Sed/*
2193323Sed * CDDL HEADER START
3193323Sed *
4193323Sed * The contents of this file are subject to the terms of the
5193323Sed * Common Development and Distribution License, Version 1.0 only
6193323Sed * (the "License").  You may not use this file except in compliance
7193323Sed * with the License.
8193323Sed *
9193323Sed * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10193323Sed * or http://www.opensolaris.org/os/licensing.
11193323Sed * See the License for the specific language governing permissions
12193323Sed * and limitations under the License.
13193323Sed *
14193323Sed * When distributing Covered Code, include this CDDL HEADER in each
15193323Sed * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16218893Sdim * If applicable, add the following below this CDDL HEADER, with the
17226890Sdim * fields enclosed by brackets "[]" replaced with your own identifying
18193323Sed * information: Portions Copyright [yyyy] [name of copyright owner]
19193323Sed *
20193323Sed * CDDL HEADER END
21193323Sed */
22193323Sed
23193323Sed/*
24193323Sed * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25193323Sed * Use is subject to license terms.
26195340Sed */
27193323Sed
28193323Sed#include <ctf_impl.h>
29193323Sed
30193323Sedssize_t
31193323Sedctf_get_ctt_size(const ctf_file_t *fp, const ctf_type_t *tp, ssize_t *sizep,
32193323Sed    ssize_t *incrementp)
33193323Sed{
34208599Srdivacky	ssize_t size, increment;
35208599Srdivacky
36193323Sed	if (fp->ctf_version > CTF_VERSION_1 &&
37193323Sed	    tp->ctt_size == CTF_LSIZE_SENT) {
38193323Sed		size = CTF_TYPE_LSIZE(tp);
39193323Sed		increment = sizeof (ctf_type_t);
40193323Sed	} else {
41193323Sed		size = tp->ctt_size;
42193323Sed		increment = sizeof (ctf_stype_t);
43193323Sed	}
44193323Sed
45193323Sed	if (sizep)
46193323Sed		*sizep = size;
47193323Sed	if (incrementp)
48193323Sed		*incrementp = increment;
49193323Sed
50193323Sed	return (size);
51193323Sed}
52193323Sed
53193323Sed/*
54193323Sed * Iterate over the members of a STRUCT or UNION.  We pass the name, member
55193323Sed * type, and offset of each member to the specified callback function.
56193323Sed */
57193323Sedint
58193323Sedctf_member_iter(ctf_file_t *fp, ctf_id_t type, ctf_member_f *func, void *arg)
59193323Sed{
60193323Sed	ctf_file_t *ofp = fp;
61193323Sed	const ctf_type_t *tp;
62208599Srdivacky	ssize_t size, increment;
63208599Srdivacky	uint_t kind, n;
64193323Sed	int rc;
65193323Sed
66208599Srdivacky	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
67208599Srdivacky		return (CTF_ERR); /* errno is set for us */
68218893Sdim
69218893Sdim	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
70218893Sdim		return (CTF_ERR); /* errno is set for us */
71218893Sdim
72218893Sdim	(void) ctf_get_ctt_size(fp, tp, &size, &increment);
73208599Srdivacky	kind = LCTF_INFO_KIND(fp, tp->ctt_info);
74208599Srdivacky
75208599Srdivacky	if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
76208599Srdivacky		return (ctf_set_errno(ofp, ECTF_NOTSOU));
77218893Sdim
78208599Srdivacky	if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) {
79218893Sdim		const ctf_member_t *mp = (const ctf_member_t *)
80218893Sdim		    ((uintptr_t)tp + increment);
81208599Srdivacky
82208599Srdivacky		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) {
83208599Srdivacky			const char *name = ctf_strptr(fp, mp->ctm_name);
84193323Sed			if ((rc = func(name, mp->ctm_type, mp->ctm_offset,
85195340Sed			    arg)) != 0)
86193323Sed				return (rc);
87193323Sed		}
88193323Sed
89193323Sed	} else {
90193323Sed		const ctf_lmember_t *lmp = (const ctf_lmember_t *)
91193323Sed		    ((uintptr_t)tp + increment);
92193323Sed
93193323Sed		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) {
94193323Sed			const char *name = ctf_strptr(fp, lmp->ctlm_name);
95193323Sed			if ((rc = func(name, lmp->ctlm_type,
96193323Sed			    (ulong_t)CTF_LMEM_OFFSET(lmp), arg)) != 0)
97193323Sed				return (rc);
98193323Sed		}
99195340Sed	}
100218893Sdim
101218893Sdim	return (0);
102193323Sed}
103218893Sdim
104218893Sdim/*
105193323Sed * Iterate over the members of an ENUM.  We pass the string name and associated
106193323Sed * integer value of each enum element to the specified callback function.
107218893Sdim */
108218893Sdimint
109218893Sdimctf_enum_iter(ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg)
110218893Sdim{
111218893Sdim	ctf_file_t *ofp = fp;
112193323Sed	const ctf_type_t *tp;
113218893Sdim	const ctf_enum_t *ep;
114218893Sdim	ssize_t increment;
115218893Sdim	uint_t n;
116218893Sdim	int rc;
117218893Sdim
118218893Sdim	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
119218893Sdim		return (CTF_ERR); /* errno is set for us */
120218893Sdim
121218893Sdim	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
122218893Sdim		return (CTF_ERR); /* errno is set for us */
123218893Sdim
124218893Sdim	if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM)
125218893Sdim		return (ctf_set_errno(ofp, ECTF_NOTENUM));
126218893Sdim
127218893Sdim	(void) ctf_get_ctt_size(fp, tp, NULL, &increment);
128218893Sdim
129218893Sdim	ep = (const ctf_enum_t *)((uintptr_t)tp + increment);
130218893Sdim
131218893Sdim	for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) {
132218893Sdim		const char *name = ctf_strptr(fp, ep->cte_name);
133218893Sdim		if ((rc = func(name, ep->cte_value, arg)) != 0)
134218893Sdim			return (rc);
135193323Sed	}
136193323Sed
137218893Sdim	return (0);
138218893Sdim}
139218893Sdim
140193323Sed/*
141218893Sdim * Iterate over every root (user-visible) type in the given CTF container.
142193323Sed * We pass the type ID of each type to the specified callback function.
143193323Sed */
144193323Sedint
145193323Sedctf_type_iter(ctf_file_t *fp, ctf_type_f *func, void *arg)
146193323Sed{
147193323Sed	ctf_id_t id, max = fp->ctf_typemax;
148195340Sed	int rc, child = (fp->ctf_flags & LCTF_CHILD);
149193323Sed
150193323Sed	for (id = 1; id <= max; id++) {
151193323Sed		const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR(fp, id);
152193323Sed		if (CTF_INFO_ISROOT(tp->ctt_info) &&
153193323Sed		    (rc = func(CTF_INDEX_TO_TYPE(id, child), arg)) != 0)
154193323Sed			return (rc);
155193323Sed	}
156193323Sed
157193323Sed	return (0);
158193323Sed}
159195340Sed
160235633Sdim/*
161193323Sed * Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and
162235633Sdim * RESTRICT nodes until we reach a "base" type node.  This is useful when
163235633Sdim * we want to follow a type ID to a node that has members or a size.  To guard
164193323Sed * against infinite loops, we implement simplified cycle detection and check
165235633Sdim * each link against itself, the previous node, and the topmost node.
166235633Sdim */
167235633Sdimctf_id_t
168193323Sedctf_type_resolve(ctf_file_t *fp, ctf_id_t type)
169235633Sdim{
170193323Sed	ctf_id_t prev = type, otype = type;
171235633Sdim	ctf_file_t *ofp = fp;
172235633Sdim	const ctf_type_t *tp;
173235633Sdim
174193323Sed	while ((tp = ctf_lookup_by_id(&fp, type)) != NULL) {
175193323Sed		switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
176193323Sed		case CTF_K_TYPEDEF:
177195340Sed		case CTF_K_VOLATILE:
178198090Srdivacky		case CTF_K_CONST:
179198090Srdivacky		case CTF_K_RESTRICT:
180198090Srdivacky			if (tp->ctt_type == type || tp->ctt_type == otype ||
181193323Sed			    tp->ctt_type == prev) {
182193323Sed				ctf_dprintf("type %ld cycle detected\n", otype);
183198090Srdivacky				return (ctf_set_errno(ofp, ECTF_CORRUPT));
184235633Sdim			}
185235633Sdim			prev = type;
186193323Sed			type = tp->ctt_type;
187198090Srdivacky			break;
188193323Sed		default:
189198090Srdivacky			return (type);
190193323Sed		}
191198090Srdivacky	}
192193323Sed
193198090Srdivacky	return (CTF_ERR); /* errno is set for us */
194193323Sed}
195198090Srdivacky
196193323Sed/*
197198090Srdivacky * Lookup the given type ID and print a string name for it into buf.  Return
198198090Srdivacky * the actual number of bytes (not including \0) needed to format the name.
199198090Srdivacky */
200218893Sdimstatic ssize_t
201218893Sdimctf_type_qlname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
202193323Sed    const char *qname)
203193323Sed{
204193323Sed	ctf_decl_t cd;
205193323Sed	ctf_decl_node_t *cdp;
206193323Sed	ctf_decl_prec_t prec, lp, rp;
207195340Sed	int ptr, arr;
208193323Sed	uint_t k;
209193323Sed
210195340Sed	if (fp == NULL && type == CTF_ERR)
211193323Sed		return (-1); /* simplify caller code by permitting CTF_ERR */
212193323Sed
213206083Srdivacky	ctf_decl_init(&cd, buf, len);
214206083Srdivacky	ctf_decl_push(&cd, fp, type);
215206083Srdivacky
216206083Srdivacky	if (cd.cd_err != 0) {
217206083Srdivacky		ctf_decl_fini(&cd);
218193323Sed		return (ctf_set_errno(fp, cd.cd_err));
219224145Sdim	}
220193323Sed
221193323Sed	/*
222193323Sed	 * If the type graph's order conflicts with lexical precedence order
223193323Sed	 * for pointers or arrays, then we need to surround the declarations at
224193323Sed	 * the corresponding lexical precedence with parentheses.  This can
225193323Sed	 * result in either a parenthesized pointer (*) as in int (*)() or
226193323Sed	 * int (*)[], or in a parenthesized pointer and array as in int (*[])().
227193323Sed	 */
228193323Sed	ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER;
229193323Sed	arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY;
230195340Sed
231193323Sed	rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1;
232193323Sed	lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1;
233193323Sed
234193323Sed	k = CTF_K_POINTER; /* avoid leading whitespace (see below) */
235193323Sed
236193323Sed	for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) {
237193323Sed		for (cdp = ctf_list_next(&cd.cd_nodes[prec]);
238193323Sed		    cdp != NULL; cdp = ctf_list_next(cdp)) {
239193323Sed
240193323Sed			ctf_file_t *rfp = fp;
241193323Sed			const ctf_type_t *tp =
242193323Sed			    ctf_lookup_by_id(&rfp, cdp->cd_type);
243193323Sed			const char *name = ctf_strptr(rfp, tp->ctt_name);
244193323Sed
245198090Srdivacky			if (k != CTF_K_POINTER && k != CTF_K_ARRAY)
246193323Sed				ctf_decl_sprintf(&cd, " ");
247193323Sed
248193323Sed			if (lp == prec) {
249193323Sed				ctf_decl_sprintf(&cd, "(");
250193323Sed				lp = -1;
251193323Sed			}
252198090Srdivacky
253198090Srdivacky			switch (cdp->cd_kind) {
254193323Sed			case CTF_K_INTEGER:
255198090Srdivacky			case CTF_K_FLOAT:
256193323Sed			case CTF_K_TYPEDEF:
257193323Sed				if (qname != NULL)
258193323Sed					ctf_decl_sprintf(&cd, "%s`", qname);
259193323Sed				ctf_decl_sprintf(&cd, "%s", name);
260193323Sed				break;
261193323Sed			case CTF_K_POINTER:
262193323Sed				ctf_decl_sprintf(&cd, "*");
263193323Sed				break;
264224145Sdim			case CTF_K_ARRAY:
265193323Sed				ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n);
266193323Sed				break;
267193323Sed			case CTF_K_FUNCTION:
268193323Sed				ctf_decl_sprintf(&cd, "()");
269193323Sed				break;
270193323Sed			case CTF_K_STRUCT:
271198090Srdivacky			case CTF_K_FORWARD:
272193323Sed				ctf_decl_sprintf(&cd, "struct ");
273193323Sed				if (qname != NULL)
274193323Sed					ctf_decl_sprintf(&cd, "%s`", qname);
275193323Sed				ctf_decl_sprintf(&cd, "%s", name);
276193323Sed				break;
277193323Sed			case CTF_K_UNION:
278193323Sed				ctf_decl_sprintf(&cd, "union ");
279193323Sed				if (qname != NULL)
280193323Sed					ctf_decl_sprintf(&cd, "%s`", qname);
281193323Sed				ctf_decl_sprintf(&cd, "%s", name);
282193323Sed				break;
283193323Sed			case CTF_K_ENUM:
284193323Sed				ctf_decl_sprintf(&cd, "enum ");
285193323Sed				if (qname != NULL)
286193323Sed					ctf_decl_sprintf(&cd, "%s`", qname);
287193323Sed				ctf_decl_sprintf(&cd, "%s", name);
288193323Sed				break;
289193323Sed			case CTF_K_VOLATILE:
290193323Sed				ctf_decl_sprintf(&cd, "volatile");
291193323Sed				break;
292193323Sed			case CTF_K_CONST:
293206083Srdivacky				ctf_decl_sprintf(&cd, "const");
294193323Sed				break;
295193323Sed			case CTF_K_RESTRICT:
296193323Sed				ctf_decl_sprintf(&cd, "restrict");
297206083Srdivacky				break;
298193323Sed			}
299193323Sed
300193323Sed			k = cdp->cd_kind;
301193323Sed		}
302193323Sed
303193323Sed		if (rp == prec)
304193323Sed			ctf_decl_sprintf(&cd, ")");
305193323Sed	}
306193323Sed
307193323Sed	if (cd.cd_len >= len)
308193323Sed		(void) ctf_set_errno(fp, ECTF_NAMELEN);
309193323Sed
310193323Sed	ctf_decl_fini(&cd);
311193323Sed	return (cd.cd_len);
312193323Sed}
313193323Sed
314193323Sedssize_t
315193323Sedctf_type_lname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
316193323Sed{
317193323Sed	return (ctf_type_qlname(fp, type, buf, len, NULL));
318193323Sed}
319195340Sed
320193323Sed/*
321193323Sed * Lookup the given type ID and print a string name for it into buf.  If buf
322193323Sed * is too small, return NULL: the ECTF_NAMELEN error is set on 'fp' for us.
323235633Sdim */
324193323Sedchar *
325193323Sedctf_type_name(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len)
326193323Sed{
327193323Sed	ssize_t rv = ctf_type_qlname(fp, type, buf, len, NULL);
328193323Sed	return (rv >= 0 && rv < len ? buf : NULL);
329193323Sed}
330193323Sed
331193323Sedchar *
332193323Sedctf_type_qname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len,
333193323Sed    const char *qname)
334193323Sed{
335193323Sed	ssize_t rv = ctf_type_qlname(fp, type, buf, len, qname);
336193323Sed	return (rv >= 0 && rv < len ? buf : NULL);
337193323Sed}
338193323Sed
339193323Sed
340193323Sed/*
341193323Sed * Resolve the type down to a base type node, and then return the size
342193323Sed * of the type storage in bytes.
343193323Sed */
344193323Sedssize_t
345193323Sedctf_type_size(ctf_file_t *fp, ctf_id_t type)
346198090Srdivacky{
347193323Sed	const ctf_type_t *tp;
348193323Sed	ssize_t size;
349193323Sed	ctf_arinfo_t ar;
350193323Sed
351193323Sed	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
352193323Sed		return (-1); /* errno is set for us */
353193323Sed
354193323Sed	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
355193323Sed		return (-1); /* errno is set for us */
356193323Sed
357193323Sed	switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
358198090Srdivacky	case CTF_K_POINTER:
359198090Srdivacky		return (fp->ctf_dmodel->ctd_pointer);
360198090Srdivacky
361193323Sed	case CTF_K_FUNCTION:
362193323Sed		return (0); /* function size is only known by symtab */
363193323Sed
364193323Sed	case CTF_K_ENUM:
365193323Sed		return (fp->ctf_dmodel->ctd_int);
366193323Sed
367193323Sed	case CTF_K_ARRAY:
368193323Sed		/*
369193323Sed		 * Array size is not directly returned by stabs data.  Instead,
370193323Sed		 * it defines the element type and requires the user to perform
371198090Srdivacky		 * the multiplication.  If ctf_get_ctt_size() returns zero, the
372198090Srdivacky		 * current version of ctfconvert does not compute member sizes
373198090Srdivacky		 * and we compute the size here on its behalf.
374193323Sed		 */
375193323Sed		if ((size = ctf_get_ctt_size(fp, tp, NULL, NULL)) > 0)
376193323Sed			return (size);
377193323Sed
378193323Sed		if (ctf_array_info(fp, type, &ar) == CTF_ERR ||
379193323Sed		    (size = ctf_type_size(fp, ar.ctr_contents)) == CTF_ERR)
380193323Sed			return (-1); /* errno is set for us */
381193323Sed
382193323Sed		return (size * ar.ctr_nelems);
383193323Sed
384193323Sed	default:
385193323Sed		return (ctf_get_ctt_size(fp, tp, NULL, NULL));
386198090Srdivacky	}
387198090Srdivacky}
388198090Srdivacky
389193323Sed/*
390193323Sed * Resolve the type down to a base type node, and then return the alignment
391193323Sed * needed for the type storage in bytes.
392193323Sed */
393193323Sedssize_t
394193323Sedctf_type_align(ctf_file_t *fp, ctf_id_t type)
395193323Sed{
396193323Sed	const ctf_type_t *tp;
397193323Sed	ctf_arinfo_t r;
398193323Sed
399198090Srdivacky	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
400198090Srdivacky		return (-1); /* errno is set for us */
401198090Srdivacky
402193323Sed	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
403193323Sed		return (-1); /* errno is set for us */
404193323Sed
405193323Sed	switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
406193323Sed	case CTF_K_POINTER:
407193323Sed	case CTF_K_FUNCTION:
408193323Sed		return (fp->ctf_dmodel->ctd_pointer);
409193323Sed
410193323Sed	case CTF_K_ARRAY:
411193323Sed		if (ctf_array_info(fp, type, &r) == CTF_ERR)
412193323Sed			return (-1); /* errno is set for us */
413193323Sed		return (ctf_type_align(fp, r.ctr_contents));
414193323Sed
415195340Sed	case CTF_K_STRUCT:
416193323Sed	case CTF_K_UNION: {
417193323Sed		uint_t n = LCTF_INFO_VLEN(fp, tp->ctt_info);
418193323Sed		ssize_t size, increment;
419235633Sdim		size_t align = 0;
420193323Sed		const void *vmp;
421193323Sed
422193323Sed		(void) ctf_get_ctt_size(fp, tp, &size, &increment);
423193323Sed		vmp = (uchar_t *)tp + increment;
424193323Sed
425193323Sed		if (LCTF_INFO_KIND(fp, tp->ctt_info) == CTF_K_STRUCT)
426193323Sed			n = MIN(n, 1); /* only use first member for structs */
427193323Sed
428193323Sed		if (fp->ctf_version == CTF_VERSION_1 ||
429193323Sed		    size < CTF_LSTRUCT_THRESH) {
430193323Sed			const ctf_member_t *mp = vmp;
431193323Sed			for (; n != 0; n--, mp++) {
432193323Sed				ssize_t am = ctf_type_align(fp, mp->ctm_type);
433193323Sed				align = MAX(align, am);
434193323Sed			}
435193323Sed		} else {
436193323Sed			const ctf_lmember_t *lmp = vmp;
437193323Sed			for (; n != 0; n--, lmp++) {
438193323Sed				ssize_t am = ctf_type_align(fp, lmp->ctlm_type);
439193323Sed				align = MAX(align, am);
440193323Sed			}
441193323Sed		}
442193323Sed
443193323Sed		return (align);
444193323Sed	}
445193323Sed
446193323Sed	case CTF_K_ENUM:
447193323Sed		return (fp->ctf_dmodel->ctd_int);
448193323Sed
449193323Sed	default:
450193323Sed		return (ctf_get_ctt_size(fp, tp, NULL, NULL));
451193323Sed	}
452193323Sed}
453193323Sed
454193323Sed/*
455193323Sed * Return the kind (CTF_K_* constant) for the specified type ID.
456193323Sed */
457193323Sedint
458193323Sedctf_type_kind(ctf_file_t *fp, ctf_id_t type)
459193323Sed{
460193323Sed	const ctf_type_t *tp;
461193323Sed
462193323Sed	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
463193323Sed		return (CTF_ERR); /* errno is set for us */
464193323Sed
465193323Sed	return (LCTF_INFO_KIND(fp, tp->ctt_info));
466193323Sed}
467193323Sed
468193323Sed/*
469193323Sed * If the type is one that directly references another type (such as POINTER),
470223017Sdim * then return the ID of the type to which it refers.
471223017Sdim */
472223017Sdimctf_id_t
473223017Sdimctf_type_reference(ctf_file_t *fp, ctf_id_t type)
474223017Sdim{
475223017Sdim	ctf_file_t *ofp = fp;
476223017Sdim	const ctf_type_t *tp;
477223017Sdim
478223017Sdim	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
479223017Sdim		return (CTF_ERR); /* errno is set for us */
480223017Sdim
481223017Sdim	switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
482223017Sdim	case CTF_K_POINTER:
483223017Sdim	case CTF_K_TYPEDEF:
484223017Sdim	case CTF_K_VOLATILE:
485223017Sdim	case CTF_K_CONST:
486223017Sdim	case CTF_K_RESTRICT:
487223017Sdim		return (tp->ctt_type);
488235633Sdim	default:
489223017Sdim		return (ctf_set_errno(ofp, ECTF_NOTREF));
490223017Sdim	}
491223017Sdim}
492223017Sdim
493223017Sdim/*
494223017Sdim * Find a pointer to type by looking in fp->ctf_ptrtab.  If we can't find a
495223017Sdim * pointer to the given type, see if we can compute a pointer to the type
496223017Sdim * resulting from resolving the type down to its base type and use that
497223017Sdim * instead.  This helps with cases where the CTF data includes "struct foo *"
498223017Sdim * but not "foo_t *" and the user accesses "foo_t *" in the debugger.
499223017Sdim */
500223017Sdimctf_id_t
501223017Sdimctf_type_pointer(ctf_file_t *fp, ctf_id_t type)
502223017Sdim{
503223017Sdim	ctf_file_t *ofp = fp;
504223017Sdim	ctf_id_t ntype;
505223017Sdim
506223017Sdim	if (ctf_lookup_by_id(&fp, type) == NULL)
507223017Sdim		return (CTF_ERR); /* errno is set for us */
508223017Sdim
509193323Sed	if ((ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]) != 0)
510193323Sed		return (CTF_INDEX_TO_TYPE(ntype, (fp->ctf_flags & LCTF_CHILD)));
511195340Sed
512193323Sed	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
513193323Sed		return (ctf_set_errno(ofp, ECTF_NOTYPE));
514193323Sed
515193323Sed	if (ctf_lookup_by_id(&fp, type) == NULL)
516223017Sdim		return (ctf_set_errno(ofp, ECTF_NOTYPE));
517193323Sed
518223017Sdim	if ((ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]) != 0)
519223017Sdim		return (CTF_INDEX_TO_TYPE(ntype, (fp->ctf_flags & LCTF_CHILD)));
520235633Sdim
521235633Sdim	return (ctf_set_errno(ofp, ECTF_NOTYPE));
522235633Sdim}
523235633Sdim
524223017Sdim/*
525235633Sdim * Return the encoding for the specified INTEGER or FLOAT.
526193323Sed */
527223017Sdimint
528223017Sdimctf_type_encoding(ctf_file_t *fp, ctf_id_t type, ctf_encoding_t *ep)
529223017Sdim{
530235633Sdim	ctf_file_t *ofp = fp;
531235633Sdim	const ctf_type_t *tp;
532235633Sdim	ssize_t increment;
533235633Sdim	uint_t data;
534193323Sed
535223017Sdim	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
536223017Sdim		return (CTF_ERR); /* errno is set for us */
537223017Sdim
538223017Sdim	(void) ctf_get_ctt_size(fp, tp, NULL, &increment);
539235633Sdim
540193323Sed	switch (LCTF_INFO_KIND(fp, tp->ctt_info)) {
541235633Sdim	case CTF_K_INTEGER:
542235633Sdim		data = *(const uint_t *)((uintptr_t)tp + increment);
543193323Sed		ep->cte_format = CTF_INT_ENCODING(data);
544235633Sdim		ep->cte_offset = CTF_INT_OFFSET(data);
545235633Sdim		ep->cte_bits = CTF_INT_BITS(data);
546235633Sdim		break;
547235633Sdim	case CTF_K_FLOAT:
548193323Sed		data = *(const uint_t *)((uintptr_t)tp + increment);
549235633Sdim		ep->cte_format = CTF_FP_ENCODING(data);
550235633Sdim		ep->cte_offset = CTF_FP_OFFSET(data);
551235633Sdim		ep->cte_bits = CTF_FP_BITS(data);
552235633Sdim		break;
553235633Sdim	default:
554235633Sdim		return (ctf_set_errno(ofp, ECTF_NOTINTFP));
555235633Sdim	}
556235633Sdim
557235633Sdim	return (0);
558235633Sdim}
559235633Sdim
560235633Sdimint
561235633Sdimctf_type_cmp(ctf_file_t *lfp, ctf_id_t ltype, ctf_file_t *rfp, ctf_id_t rtype)
562223017Sdim{
563235633Sdim	int rval;
564223017Sdim
565223017Sdim	if (ltype < rtype)
566223017Sdim		rval = -1;
567223017Sdim	else if (ltype > rtype)
568223017Sdim		rval = 1;
569223017Sdim	else
570223017Sdim		rval = 0;
571235633Sdim
572235633Sdim	if (lfp == rfp)
573223017Sdim		return (rval);
574193323Sed
575223017Sdim	if (CTF_TYPE_ISPARENT(ltype) && lfp->ctf_parent != NULL)
576223017Sdim		lfp = lfp->ctf_parent;
577223017Sdim
578223017Sdim	if (CTF_TYPE_ISPARENT(rtype) && rfp->ctf_parent != NULL)
579223017Sdim		rfp = rfp->ctf_parent;
580223017Sdim
581193323Sed	if (lfp < rfp)
582223017Sdim		return (-1);
583193323Sed
584193323Sed	if (lfp > rfp)
585223017Sdim		return (1);
586223017Sdim
587223017Sdim	return (rval);
588223017Sdim}
589223017Sdim
590223017Sdim/*
591223017Sdim * Return a boolean value indicating if two types are compatible integers or
592223017Sdim * floating-pointer values.  This function returns true if the two types are
593223017Sdim * the same, or if they have the same ASCII name and encoding properties.
594223017Sdim * This function could be extended to test for compatibility for other kinds.
595223017Sdim */
596235633Sdimint
597223017Sdimctf_type_compat(ctf_file_t *lfp, ctf_id_t ltype,
598223017Sdim    ctf_file_t *rfp, ctf_id_t rtype)
599223017Sdim{
600193323Sed	const ctf_type_t *ltp, *rtp;
601223017Sdim	ctf_encoding_t le, re;
602223017Sdim	ctf_arinfo_t la, ra;
603223017Sdim	uint_t lkind, rkind;
604223017Sdim
605223017Sdim	if (ctf_type_cmp(lfp, ltype, rfp, rtype) == 0)
606193323Sed		return (1);
607193323Sed
608223017Sdim	ltype = ctf_type_resolve(lfp, ltype);
609223017Sdim	lkind = ctf_type_kind(lfp, ltype);
610235633Sdim
611235633Sdim	rtype = ctf_type_resolve(rfp, rtype);
612223017Sdim	rkind = ctf_type_kind(rfp, rtype);
613235633Sdim
614223017Sdim	if (lkind != rkind ||
615193323Sed	    (ltp = ctf_lookup_by_id(&lfp, ltype)) == NULL ||
616193323Sed	    (rtp = ctf_lookup_by_id(&rfp, rtype)) == NULL ||
617235633Sdim	    strcmp(ctf_strptr(lfp, ltp->ctt_name),
618193323Sed	    ctf_strptr(rfp, rtp->ctt_name)) != 0)
619223017Sdim		return (0);
620193323Sed
621193323Sed	switch (lkind) {
622193323Sed	case CTF_K_INTEGER:
623193323Sed	case CTF_K_FLOAT:
624193323Sed		return (ctf_type_encoding(lfp, ltype, &le) == 0 &&
625193323Sed		    ctf_type_encoding(rfp, rtype, &re) == 0 &&
626195340Sed		    bcmp(&le, &re, sizeof (ctf_encoding_t)) == 0);
627235633Sdim	case CTF_K_POINTER:
628235633Sdim		return (ctf_type_compat(lfp, ctf_type_reference(lfp, ltype),
629235633Sdim		    rfp, ctf_type_reference(rfp, rtype)));
630235633Sdim	case CTF_K_ARRAY:
631235633Sdim		return (ctf_array_info(lfp, ltype, &la) == 0 &&
632235633Sdim		    ctf_array_info(rfp, rtype, &ra) == 0 &&
633235633Sdim		    la.ctr_nelems == ra.ctr_nelems && ctf_type_compat(
634193323Sed		    lfp, la.ctr_contents, rfp, ra.ctr_contents) &&
635235633Sdim		    ctf_type_compat(lfp, la.ctr_index, rfp, ra.ctr_index));
636193323Sed	case CTF_K_STRUCT:
637193323Sed	case CTF_K_UNION:
638235633Sdim		return (ctf_type_size(lfp, ltype) == ctf_type_size(rfp, rtype));
639193323Sed	case CTF_K_ENUM:
640193323Sed	case CTF_K_FORWARD:
641235633Sdim		return (1); /* no other checks required for these type kinds */
642218893Sdim	default:
643193323Sed		return (0); /* should not get here since we did a resolve */
644235633Sdim	}
645193323Sed}
646212904Sdim
647235633Sdim/*
648193323Sed * Return the type and offset for a given member of a STRUCT or UNION.
649235633Sdim */
650235633Sdimint
651235633Sdimctf_member_info(ctf_file_t *fp, ctf_id_t type, const char *name,
652193323Sed    ctf_membinfo_t *mip)
653193323Sed{
654235633Sdim	ctf_file_t *ofp = fp;
655235633Sdim	const ctf_type_t *tp;
656235633Sdim	ssize_t size, increment;
657193323Sed	uint_t kind, n;
658193323Sed
659193323Sed	if ((type = ctf_type_resolve(fp, type)) == CTF_ERR)
660193323Sed		return (CTF_ERR); /* errno is set for us */
661193323Sed
662193323Sed	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
663195340Sed		return (CTF_ERR); /* errno is set for us */
664193323Sed
665218893Sdim	(void) ctf_get_ctt_size(fp, tp, &size, &increment);
666193323Sed	kind = LCTF_INFO_KIND(fp, tp->ctt_info);
667218893Sdim
668218893Sdim	if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
669218893Sdim		return (ctf_set_errno(ofp, ECTF_NOTSOU));
670218893Sdim
671218893Sdim	if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) {
672193323Sed		const ctf_member_t *mp = (const ctf_member_t *)
673218893Sdim		    ((uintptr_t)tp + increment);
674218893Sdim
675193323Sed		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) {
676193323Sed			if (strcmp(ctf_strptr(fp, mp->ctm_name), name) == 0) {
677193323Sed				mip->ctm_type = mp->ctm_type;
678193323Sed				mip->ctm_offset = mp->ctm_offset;
679193323Sed				return (0);
680195340Sed			}
681193323Sed		}
682193323Sed	} else {
683193323Sed		const ctf_lmember_t *lmp = (const ctf_lmember_t *)
684193323Sed		    ((uintptr_t)tp + increment);
685193323Sed
686193323Sed		for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) {
687193323Sed			if (strcmp(ctf_strptr(fp, lmp->ctlm_name), name) == 0) {
688193323Sed				mip->ctm_type = lmp->ctlm_type;
689193323Sed				mip->ctm_offset = (ulong_t)CTF_LMEM_OFFSET(lmp);
690193323Sed				return (0);
691193323Sed			}
692193323Sed		}
693193323Sed	}
694193323Sed
695193323Sed	return (ctf_set_errno(ofp, ECTF_NOMEMBNAM));
696193323Sed}
697193323Sed
698193323Sed/*
699193323Sed * Return the array type, index, and size information for the specified ARRAY.
700193323Sed */
701193323Sedint
702193323Sedctf_array_info(ctf_file_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
703193323Sed{
704218893Sdim	ctf_file_t *ofp = fp;
705193323Sed	const ctf_type_t *tp;
706193323Sed	const ctf_array_t *ap;
707218893Sdim	ssize_t increment;
708193323Sed
709193323Sed	if ((tp = ctf_lookup_by_id(&fp, type)) == NULL)
710218893Sdim		return (CTF_ERR); /* errno is set for us */
711218893Sdim
712193323Sed	if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ARRAY)
713193323Sed		return (ctf_set_errno(ofp, ECTF_NOTARRAY));
714193323Sed
715193323Sed	(void) ctf_get_ctt_size(fp, tp, NULL, &increment);
716193323Sed
717218893Sdim	ap = (const ctf_array_t *)((uintptr_t)tp + increment);
718193323Sed	arp->ctr_contents = ap->cta_contents;
719193323Sed	arp->ctr_index = ap->cta_index;
720193323Sed	arp->ctr_nelems = ap->cta_nelems;
721193323Sed
722193323Sed	return (0);
723193323Sed}
724193323Sed
725193323Sed/*
726218893Sdim * Convert the specified value to the corresponding enum member name, if a
727218893Sdim * matching name can be found.  Otherwise NULL is returned.
728218893Sdim */
729218893Sdimconst char *
730193323Sedctf_enum_name(ctf_file_t *fp, ctf_id_t type, int value)
731193323Sed{
732193323Sed	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