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
ctf_get_ctt_size(const ctf_file_t * fp,const ctf_type_t * tp,ssize_t * sizep,ssize_t * incrementp)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
ctf_member_iter(ctf_file_t * fp,ctf_id_t type,ctf_member_f * func,void * arg)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
ctf_enum_iter(ctf_file_t * fp,ctf_id_t type,ctf_enum_f * func,void * arg)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
ctf_type_iter(ctf_file_t * fp,ctf_type_f * func,void * arg)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
ctf_type_resolve(ctf_file_t * fp,ctf_id_t type)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
ctf_type_lname(ctf_file_t * fp,ctf_id_t type,char * buf,size_t len)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 *
ctf_type_name(ctf_file_t * fp,ctf_id_t type,char * buf,size_t len)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
ctf_type_size(ctf_file_t * fp,ctf_id_t type)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
ctf_type_align(ctf_file_t * fp,ctf_id_t type)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
ctf_type_kind(ctf_file_t * fp,ctf_id_t type)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
ctf_type_reference(ctf_file_t * fp,ctf_id_t type)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
ctf_type_pointer(ctf_file_t * fp,ctf_id_t type)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
ctf_type_encoding(ctf_file_t * fp,ctf_id_t type,ctf_encoding_t * ep)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
ctf_type_cmp(ctf_file_t * lfp,ctf_id_t ltype,ctf_file_t * rfp,ctf_id_t rtype)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
ctf_type_compat(ctf_file_t * lfp,ctf_id_t ltype,ctf_file_t * rfp,ctf_id_t rtype)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
ctf_member_info(ctf_file_t * fp,ctf_id_t type,const char * name,ctf_membinfo_t * mip)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
ctf_array_info(ctf_file_t * fp,ctf_id_t type,ctf_arinfo_t * arp)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 *
ctf_enum_name(ctf_file_t * fp,ctf_id_t type,int value)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
ctf_enum_value(ctf_file_t * fp,ctf_id_t type,const char * name,int * valp)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
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)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
ctf_type_visit(ctf_file_t * fp,ctf_id_t type,ctf_visit_f * func,void * arg)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