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