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