1178525Sjb/* 2178525Sjb * CDDL HEADER START 3178525Sjb * 4178525Sjb * The contents of this file are subject to the terms of the 5178525Sjb * Common Development and Distribution License, Version 1.0 only 6178525Sjb * (the "License"). You may not use this file except in compliance 7178525Sjb * with the License. 8178525Sjb * 9178525Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10178525Sjb * or http://www.opensolaris.org/os/licensing. 11178525Sjb * See the License for the specific language governing permissions 12178525Sjb * and limitations under the License. 13178525Sjb * 14178525Sjb * When distributing Covered Code, include this CDDL HEADER in each 15178525Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16178525Sjb * If applicable, add the following below this CDDL HEADER, with the 17178525Sjb * fields enclosed by brackets "[]" replaced with your own identifying 18178525Sjb * information: Portions Copyright [yyyy] [name of copyright owner] 19178525Sjb * 20178525Sjb * CDDL HEADER END 21178525Sjb */ 22178525Sjb 23178525Sjb/* 24178525Sjb * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25178525Sjb * Use is subject to license terms. 26178525Sjb */ 27178525Sjb 28178525Sjb#include <ctf_impl.h> 29178525Sjb 30178525Sjbssize_t 31178525Sjbctf_get_ctt_size(const ctf_file_t *fp, const ctf_type_t *tp, ssize_t *sizep, 32178525Sjb ssize_t *incrementp) 33178525Sjb{ 34178525Sjb ssize_t size, increment; 35178525Sjb 36178525Sjb if (fp->ctf_version > CTF_VERSION_1 && 37178525Sjb tp->ctt_size == CTF_LSIZE_SENT) { 38178525Sjb size = CTF_TYPE_LSIZE(tp); 39178525Sjb increment = sizeof (ctf_type_t); 40178525Sjb } else { 41178525Sjb size = tp->ctt_size; 42178525Sjb increment = sizeof (ctf_stype_t); 43178525Sjb } 44178525Sjb 45178525Sjb if (sizep) 46178525Sjb *sizep = size; 47178525Sjb if (incrementp) 48178525Sjb *incrementp = increment; 49178525Sjb 50178525Sjb return (size); 51178525Sjb} 52178525Sjb 53178525Sjb/* 54178525Sjb * Iterate over the members of a STRUCT or UNION. We pass the name, member 55178525Sjb * type, and offset of each member to the specified callback function. 56178525Sjb */ 57178525Sjbint 58178525Sjbctf_member_iter(ctf_file_t *fp, ctf_id_t type, ctf_member_f *func, void *arg) 59178525Sjb{ 60178525Sjb ctf_file_t *ofp = fp; 61178525Sjb const ctf_type_t *tp; 62178525Sjb ssize_t size, increment; 63178525Sjb uint_t kind, n; 64178525Sjb int rc; 65178525Sjb 66178525Sjb if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) 67178525Sjb return (CTF_ERR); /* errno is set for us */ 68178525Sjb 69178525Sjb if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) 70178525Sjb return (CTF_ERR); /* errno is set for us */ 71178525Sjb 72178525Sjb (void) ctf_get_ctt_size(fp, tp, &size, &increment); 73178525Sjb kind = LCTF_INFO_KIND(fp, tp->ctt_info); 74178525Sjb 75178525Sjb if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) 76178525Sjb return (ctf_set_errno(ofp, ECTF_NOTSOU)); 77178525Sjb 78178525Sjb if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) { 79178525Sjb const ctf_member_t *mp = (const ctf_member_t *) 80178525Sjb ((uintptr_t)tp + increment); 81178525Sjb 82178525Sjb for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) { 83178525Sjb const char *name = ctf_strptr(fp, mp->ctm_name); 84178525Sjb if ((rc = func(name, mp->ctm_type, mp->ctm_offset, 85178525Sjb arg)) != 0) 86178525Sjb return (rc); 87178525Sjb } 88178525Sjb 89178525Sjb } else { 90178525Sjb const ctf_lmember_t *lmp = (const ctf_lmember_t *) 91178525Sjb ((uintptr_t)tp + increment); 92178525Sjb 93178525Sjb for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) { 94178525Sjb const char *name = ctf_strptr(fp, lmp->ctlm_name); 95178525Sjb if ((rc = func(name, lmp->ctlm_type, 96178525Sjb (ulong_t)CTF_LMEM_OFFSET(lmp), arg)) != 0) 97178525Sjb return (rc); 98178525Sjb } 99178525Sjb } 100178525Sjb 101178525Sjb return (0); 102178525Sjb} 103178525Sjb 104178525Sjb/* 105178525Sjb * Iterate over the members of an ENUM. We pass the string name and associated 106178525Sjb * integer value of each enum element to the specified callback function. 107178525Sjb */ 108178525Sjbint 109178525Sjbctf_enum_iter(ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg) 110178525Sjb{ 111178525Sjb ctf_file_t *ofp = fp; 112178525Sjb const ctf_type_t *tp; 113178525Sjb const ctf_enum_t *ep; 114178525Sjb ssize_t increment; 115178525Sjb uint_t n; 116178525Sjb int rc; 117178525Sjb 118178525Sjb if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) 119178525Sjb return (CTF_ERR); /* errno is set for us */ 120178525Sjb 121178525Sjb if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) 122178525Sjb return (CTF_ERR); /* errno is set for us */ 123178525Sjb 124178525Sjb if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) 125178525Sjb return (ctf_set_errno(ofp, ECTF_NOTENUM)); 126178525Sjb 127178525Sjb (void) ctf_get_ctt_size(fp, tp, NULL, &increment); 128178525Sjb 129178525Sjb ep = (const ctf_enum_t *)((uintptr_t)tp + increment); 130178525Sjb 131178525Sjb for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) { 132178525Sjb const char *name = ctf_strptr(fp, ep->cte_name); 133178525Sjb if ((rc = func(name, ep->cte_value, arg)) != 0) 134178525Sjb return (rc); 135178525Sjb } 136178525Sjb 137178525Sjb return (0); 138178525Sjb} 139178525Sjb 140178525Sjb/* 141178525Sjb * Iterate over every root (user-visible) type in the given CTF container. 142178525Sjb * We pass the type ID of each type to the specified callback function. 143178525Sjb */ 144178525Sjbint 145178525Sjbctf_type_iter(ctf_file_t *fp, ctf_type_f *func, void *arg) 146178525Sjb{ 147178525Sjb ctf_id_t id, max = fp->ctf_typemax; 148178525Sjb int rc, child = (fp->ctf_flags & LCTF_CHILD); 149178525Sjb 150178525Sjb for (id = 1; id <= max; id++) { 151178525Sjb const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR(fp, id); 152178525Sjb if (CTF_INFO_ISROOT(tp->ctt_info) && 153178525Sjb (rc = func(CTF_INDEX_TO_TYPE(id, child), arg)) != 0) 154178525Sjb return (rc); 155178525Sjb } 156178525Sjb 157178525Sjb return (0); 158178525Sjb} 159178525Sjb 160178525Sjb/* 161178525Sjb * Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and 162178525Sjb * RESTRICT nodes until we reach a "base" type node. This is useful when 163178525Sjb * we want to follow a type ID to a node that has members or a size. To guard 164178525Sjb * against infinite loops, we implement simplified cycle detection and check 165178525Sjb * each link against itself, the previous node, and the topmost node. 166178525Sjb */ 167178525Sjbctf_id_t 168178525Sjbctf_type_resolve(ctf_file_t *fp, ctf_id_t type) 169178525Sjb{ 170178525Sjb ctf_id_t prev = type, otype = type; 171178525Sjb ctf_file_t *ofp = fp; 172178525Sjb const ctf_type_t *tp; 173178525Sjb 174178525Sjb while ((tp = ctf_lookup_by_id(&fp, type)) != NULL) { 175178525Sjb switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { 176178525Sjb case CTF_K_TYPEDEF: 177178525Sjb case CTF_K_VOLATILE: 178178525Sjb case CTF_K_CONST: 179178525Sjb case CTF_K_RESTRICT: 180178525Sjb if (tp->ctt_type == type || tp->ctt_type == otype || 181178525Sjb tp->ctt_type == prev) { 182178525Sjb ctf_dprintf("type %ld cycle detected\n", otype); 183178525Sjb return (ctf_set_errno(ofp, ECTF_CORRUPT)); 184178525Sjb } 185178525Sjb prev = type; 186178525Sjb type = tp->ctt_type; 187178525Sjb break; 188178525Sjb default: 189178525Sjb return (type); 190178525Sjb } 191178525Sjb } 192178525Sjb 193178525Sjb return (CTF_ERR); /* errno is set for us */ 194178525Sjb} 195178525Sjb 196178525Sjb/* 197178525Sjb * Lookup the given type ID and print a string name for it into buf. Return 198178525Sjb * the actual number of bytes (not including \0) needed to format the name. 199178525Sjb */ 200267941Srpaulostatic ssize_t 201267941Srpauloctf_type_qlname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len, 202267941Srpaulo const char *qname) 203178525Sjb{ 204178525Sjb ctf_decl_t cd; 205178525Sjb ctf_decl_node_t *cdp; 206178525Sjb ctf_decl_prec_t prec, lp, rp; 207178525Sjb int ptr, arr; 208178525Sjb uint_t k; 209178525Sjb 210178525Sjb if (fp == NULL && type == CTF_ERR) 211178525Sjb return (-1); /* simplify caller code by permitting CTF_ERR */ 212178525Sjb 213178525Sjb ctf_decl_init(&cd, buf, len); 214178525Sjb ctf_decl_push(&cd, fp, type); 215178525Sjb 216178525Sjb if (cd.cd_err != 0) { 217178525Sjb ctf_decl_fini(&cd); 218178525Sjb return (ctf_set_errno(fp, cd.cd_err)); 219178525Sjb } 220178525Sjb 221178525Sjb /* 222178525Sjb * If the type graph's order conflicts with lexical precedence order 223178525Sjb * for pointers or arrays, then we need to surround the declarations at 224178525Sjb * the corresponding lexical precedence with parentheses. This can 225178525Sjb * result in either a parenthesized pointer (*) as in int (*)() or 226178525Sjb * int (*)[], or in a parenthesized pointer and array as in int (*[])(). 227178525Sjb */ 228178525Sjb ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER; 229178525Sjb arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY; 230178525Sjb 231178525Sjb rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1; 232178525Sjb lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1; 233178525Sjb 234178525Sjb k = CTF_K_POINTER; /* avoid leading whitespace (see below) */ 235178525Sjb 236178525Sjb for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) { 237178525Sjb for (cdp = ctf_list_next(&cd.cd_nodes[prec]); 238178525Sjb cdp != NULL; cdp = ctf_list_next(cdp)) { 239178525Sjb 240178525Sjb ctf_file_t *rfp = fp; 241178525Sjb const ctf_type_t *tp = 242178525Sjb ctf_lookup_by_id(&rfp, cdp->cd_type); 243178525Sjb const char *name = ctf_strptr(rfp, tp->ctt_name); 244178525Sjb 245178525Sjb if (k != CTF_K_POINTER && k != CTF_K_ARRAY) 246178525Sjb ctf_decl_sprintf(&cd, " "); 247178525Sjb 248178525Sjb if (lp == prec) { 249178525Sjb ctf_decl_sprintf(&cd, "("); 250178525Sjb lp = -1; 251178525Sjb } 252178525Sjb 253178525Sjb switch (cdp->cd_kind) { 254178525Sjb case CTF_K_INTEGER: 255178525Sjb case CTF_K_FLOAT: 256178525Sjb case CTF_K_TYPEDEF: 257267941Srpaulo if (qname != NULL) 258267941Srpaulo ctf_decl_sprintf(&cd, "%s`", qname); 259178525Sjb ctf_decl_sprintf(&cd, "%s", name); 260178525Sjb break; 261178525Sjb case CTF_K_POINTER: 262178525Sjb ctf_decl_sprintf(&cd, "*"); 263178525Sjb break; 264178525Sjb case CTF_K_ARRAY: 265178525Sjb ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n); 266178525Sjb break; 267178525Sjb case CTF_K_FUNCTION: 268178525Sjb ctf_decl_sprintf(&cd, "()"); 269178525Sjb break; 270178525Sjb case CTF_K_STRUCT: 271178525Sjb case CTF_K_FORWARD: 272267941Srpaulo ctf_decl_sprintf(&cd, "struct "); 273267941Srpaulo if (qname != NULL) 274267941Srpaulo ctf_decl_sprintf(&cd, "%s`", qname); 275267941Srpaulo ctf_decl_sprintf(&cd, "%s", name); 276178525Sjb break; 277178525Sjb case CTF_K_UNION: 278267941Srpaulo ctf_decl_sprintf(&cd, "union "); 279267941Srpaulo if (qname != NULL) 280267941Srpaulo ctf_decl_sprintf(&cd, "%s`", qname); 281267941Srpaulo ctf_decl_sprintf(&cd, "%s", name); 282178525Sjb break; 283178525Sjb case CTF_K_ENUM: 284267941Srpaulo ctf_decl_sprintf(&cd, "enum "); 285267941Srpaulo if (qname != NULL) 286267941Srpaulo ctf_decl_sprintf(&cd, "%s`", qname); 287267941Srpaulo ctf_decl_sprintf(&cd, "%s", name); 288178525Sjb break; 289178525Sjb case CTF_K_VOLATILE: 290178525Sjb ctf_decl_sprintf(&cd, "volatile"); 291178525Sjb break; 292178525Sjb case CTF_K_CONST: 293178525Sjb ctf_decl_sprintf(&cd, "const"); 294178525Sjb break; 295178525Sjb case CTF_K_RESTRICT: 296178525Sjb ctf_decl_sprintf(&cd, "restrict"); 297178525Sjb break; 298178525Sjb } 299178525Sjb 300178525Sjb k = cdp->cd_kind; 301178525Sjb } 302178525Sjb 303178525Sjb if (rp == prec) 304178525Sjb ctf_decl_sprintf(&cd, ")"); 305178525Sjb } 306178525Sjb 307178525Sjb if (cd.cd_len >= len) 308178525Sjb (void) ctf_set_errno(fp, ECTF_NAMELEN); 309178525Sjb 310178525Sjb ctf_decl_fini(&cd); 311178525Sjb return (cd.cd_len); 312178525Sjb} 313178525Sjb 314267941Srpaulossize_t 315267941Srpauloctf_type_lname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len) 316267941Srpaulo{ 317267941Srpaulo return (ctf_type_qlname(fp, type, buf, len, NULL)); 318267941Srpaulo} 319267941Srpaulo 320178525Sjb/* 321178525Sjb * Lookup the given type ID and print a string name for it into buf. If buf 322178525Sjb * is too small, return NULL: the ECTF_NAMELEN error is set on 'fp' for us. 323178525Sjb */ 324178525Sjbchar * 325178525Sjbctf_type_name(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len) 326178525Sjb{ 327267941Srpaulo ssize_t rv = ctf_type_qlname(fp, type, buf, len, NULL); 328178525Sjb return (rv >= 0 && rv < len ? buf : NULL); 329178525Sjb} 330178525Sjb 331267941Srpaulochar * 332267941Srpauloctf_type_qname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len, 333267941Srpaulo const char *qname) 334267941Srpaulo{ 335267941Srpaulo ssize_t rv = ctf_type_qlname(fp, type, buf, len, qname); 336267941Srpaulo return (rv >= 0 && rv < len ? buf : NULL); 337267941Srpaulo} 338267941Srpaulo 339267941Srpaulo 340178525Sjb/* 341178525Sjb * Resolve the type down to a base type node, and then return the size 342178525Sjb * of the type storage in bytes. 343178525Sjb */ 344178525Sjbssize_t 345178525Sjbctf_type_size(ctf_file_t *fp, ctf_id_t type) 346178525Sjb{ 347178525Sjb const ctf_type_t *tp; 348178525Sjb ssize_t size; 349178525Sjb ctf_arinfo_t ar; 350178525Sjb 351178525Sjb if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) 352178525Sjb return (-1); /* errno is set for us */ 353178525Sjb 354178525Sjb if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) 355178525Sjb return (-1); /* errno is set for us */ 356178525Sjb 357178525Sjb switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { 358178525Sjb case CTF_K_POINTER: 359178525Sjb return (fp->ctf_dmodel->ctd_pointer); 360178525Sjb 361178525Sjb case CTF_K_FUNCTION: 362178525Sjb return (0); /* function size is only known by symtab */ 363178525Sjb 364178525Sjb case CTF_K_ENUM: 365178525Sjb return (fp->ctf_dmodel->ctd_int); 366178525Sjb 367178525Sjb case CTF_K_ARRAY: 368178525Sjb /* 369178525Sjb * Array size is not directly returned by stabs data. Instead, 370178525Sjb * it defines the element type and requires the user to perform 371178525Sjb * the multiplication. If ctf_get_ctt_size() returns zero, the 372178525Sjb * current version of ctfconvert does not compute member sizes 373178525Sjb * and we compute the size here on its behalf. 374178525Sjb */ 375178525Sjb if ((size = ctf_get_ctt_size(fp, tp, NULL, NULL)) > 0) 376178525Sjb return (size); 377178525Sjb 378178525Sjb if (ctf_array_info(fp, type, &ar) == CTF_ERR || 379178525Sjb (size = ctf_type_size(fp, ar.ctr_contents)) == CTF_ERR) 380178525Sjb return (-1); /* errno is set for us */ 381178525Sjb 382178525Sjb return (size * ar.ctr_nelems); 383178525Sjb 384178525Sjb default: 385178525Sjb return (ctf_get_ctt_size(fp, tp, NULL, NULL)); 386178525Sjb } 387178525Sjb} 388178525Sjb 389178525Sjb/* 390178525Sjb * Resolve the type down to a base type node, and then return the alignment 391178525Sjb * needed for the type storage in bytes. 392178525Sjb */ 393178525Sjbssize_t 394178525Sjbctf_type_align(ctf_file_t *fp, ctf_id_t type) 395178525Sjb{ 396178525Sjb const ctf_type_t *tp; 397178525Sjb ctf_arinfo_t r; 398178525Sjb 399178525Sjb if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) 400178525Sjb return (-1); /* errno is set for us */ 401178525Sjb 402178525Sjb if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) 403178525Sjb return (-1); /* errno is set for us */ 404178525Sjb 405178525Sjb switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { 406178525Sjb case CTF_K_POINTER: 407178525Sjb case CTF_K_FUNCTION: 408178525Sjb return (fp->ctf_dmodel->ctd_pointer); 409178525Sjb 410178525Sjb case CTF_K_ARRAY: 411178525Sjb if (ctf_array_info(fp, type, &r) == CTF_ERR) 412178525Sjb return (-1); /* errno is set for us */ 413178525Sjb return (ctf_type_align(fp, r.ctr_contents)); 414178525Sjb 415178525Sjb case CTF_K_STRUCT: 416178525Sjb case CTF_K_UNION: { 417178525Sjb uint_t n = LCTF_INFO_VLEN(fp, tp->ctt_info); 418178525Sjb ssize_t size, increment; 419178525Sjb size_t align = 0; 420178525Sjb const void *vmp; 421178525Sjb 422178525Sjb (void) ctf_get_ctt_size(fp, tp, &size, &increment); 423178525Sjb vmp = (uchar_t *)tp + increment; 424178525Sjb 425178525Sjb if (LCTF_INFO_KIND(fp, tp->ctt_info) == CTF_K_STRUCT) 426178525Sjb n = MIN(n, 1); /* only use first member for structs */ 427178525Sjb 428178525Sjb if (fp->ctf_version == CTF_VERSION_1 || 429178525Sjb size < CTF_LSTRUCT_THRESH) { 430178525Sjb const ctf_member_t *mp = vmp; 431178525Sjb for (; n != 0; n--, mp++) { 432178525Sjb ssize_t am = ctf_type_align(fp, mp->ctm_type); 433178525Sjb align = MAX(align, am); 434178525Sjb } 435178525Sjb } else { 436178525Sjb const ctf_lmember_t *lmp = vmp; 437178525Sjb for (; n != 0; n--, lmp++) { 438178525Sjb ssize_t am = ctf_type_align(fp, lmp->ctlm_type); 439178525Sjb align = MAX(align, am); 440178525Sjb } 441178525Sjb } 442178525Sjb 443178525Sjb return (align); 444178525Sjb } 445178525Sjb 446178525Sjb case CTF_K_ENUM: 447178525Sjb return (fp->ctf_dmodel->ctd_int); 448178525Sjb 449178525Sjb default: 450178525Sjb return (ctf_get_ctt_size(fp, tp, NULL, NULL)); 451178525Sjb } 452178525Sjb} 453178525Sjb 454178525Sjb/* 455178525Sjb * Return the kind (CTF_K_* constant) for the specified type ID. 456178525Sjb */ 457178525Sjbint 458178525Sjbctf_type_kind(ctf_file_t *fp, ctf_id_t type) 459178525Sjb{ 460178525Sjb const ctf_type_t *tp; 461178525Sjb 462178525Sjb if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) 463178525Sjb return (CTF_ERR); /* errno is set for us */ 464178525Sjb 465178525Sjb return (LCTF_INFO_KIND(fp, tp->ctt_info)); 466178525Sjb} 467178525Sjb 468178525Sjb/* 469178525Sjb * If the type is one that directly references another type (such as POINTER), 470178525Sjb * then return the ID of the type to which it refers. 471178525Sjb */ 472178525Sjbctf_id_t 473178525Sjbctf_type_reference(ctf_file_t *fp, ctf_id_t type) 474178525Sjb{ 475178525Sjb ctf_file_t *ofp = fp; 476178525Sjb const ctf_type_t *tp; 477178525Sjb 478178525Sjb if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) 479178525Sjb return (CTF_ERR); /* errno is set for us */ 480178525Sjb 481178525Sjb switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { 482178525Sjb case CTF_K_POINTER: 483178525Sjb case CTF_K_TYPEDEF: 484178525Sjb case CTF_K_VOLATILE: 485178525Sjb case CTF_K_CONST: 486178525Sjb case CTF_K_RESTRICT: 487178525Sjb return (tp->ctt_type); 488178525Sjb default: 489178525Sjb return (ctf_set_errno(ofp, ECTF_NOTREF)); 490178525Sjb } 491178525Sjb} 492178525Sjb 493178525Sjb/* 494178525Sjb * Find a pointer to type by looking in fp->ctf_ptrtab. If we can't find a 495178525Sjb * pointer to the given type, see if we can compute a pointer to the type 496178525Sjb * resulting from resolving the type down to its base type and use that 497178525Sjb * instead. This helps with cases where the CTF data includes "struct foo *" 498178525Sjb * but not "foo_t *" and the user accesses "foo_t *" in the debugger. 499178525Sjb */ 500178525Sjbctf_id_t 501178525Sjbctf_type_pointer(ctf_file_t *fp, ctf_id_t type) 502178525Sjb{ 503178525Sjb ctf_file_t *ofp = fp; 504178525Sjb ctf_id_t ntype; 505178525Sjb 506178525Sjb if (ctf_lookup_by_id(&fp, type) == NULL) 507178525Sjb return (CTF_ERR); /* errno is set for us */ 508178525Sjb 509178525Sjb if ((ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]) != 0) 510178525Sjb return (CTF_INDEX_TO_TYPE(ntype, (fp->ctf_flags & LCTF_CHILD))); 511178525Sjb 512178525Sjb if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) 513178525Sjb return (ctf_set_errno(ofp, ECTF_NOTYPE)); 514178525Sjb 515178525Sjb if (ctf_lookup_by_id(&fp, type) == NULL) 516178525Sjb return (ctf_set_errno(ofp, ECTF_NOTYPE)); 517178525Sjb 518178525Sjb if ((ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]) != 0) 519178525Sjb return (CTF_INDEX_TO_TYPE(ntype, (fp->ctf_flags & LCTF_CHILD))); 520178525Sjb 521178525Sjb return (ctf_set_errno(ofp, ECTF_NOTYPE)); 522178525Sjb} 523178525Sjb 524178525Sjb/* 525178525Sjb * Return the encoding for the specified INTEGER or FLOAT. 526178525Sjb */ 527178525Sjbint 528178525Sjbctf_type_encoding(ctf_file_t *fp, ctf_id_t type, ctf_encoding_t *ep) 529178525Sjb{ 530178525Sjb ctf_file_t *ofp = fp; 531178525Sjb const ctf_type_t *tp; 532178525Sjb ssize_t increment; 533178525Sjb uint_t data; 534178525Sjb 535178525Sjb if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) 536178525Sjb return (CTF_ERR); /* errno is set for us */ 537178525Sjb 538178525Sjb (void) ctf_get_ctt_size(fp, tp, NULL, &increment); 539178525Sjb 540178525Sjb switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { 541178525Sjb case CTF_K_INTEGER: 542178525Sjb data = *(const uint_t *)((uintptr_t)tp + increment); 543178525Sjb ep->cte_format = CTF_INT_ENCODING(data); 544178525Sjb ep->cte_offset = CTF_INT_OFFSET(data); 545178525Sjb ep->cte_bits = CTF_INT_BITS(data); 546178525Sjb break; 547178525Sjb case CTF_K_FLOAT: 548178525Sjb data = *(const uint_t *)((uintptr_t)tp + increment); 549178525Sjb ep->cte_format = CTF_FP_ENCODING(data); 550178525Sjb ep->cte_offset = CTF_FP_OFFSET(data); 551178525Sjb ep->cte_bits = CTF_FP_BITS(data); 552178525Sjb break; 553178525Sjb default: 554178525Sjb return (ctf_set_errno(ofp, ECTF_NOTINTFP)); 555178525Sjb } 556178525Sjb 557178525Sjb return (0); 558178525Sjb} 559178525Sjb 560178525Sjbint 561178525Sjbctf_type_cmp(ctf_file_t *lfp, ctf_id_t ltype, ctf_file_t *rfp, ctf_id_t rtype) 562178525Sjb{ 563178525Sjb int rval; 564178525Sjb 565178525Sjb if (ltype < rtype) 566178525Sjb rval = -1; 567178525Sjb else if (ltype > rtype) 568178525Sjb rval = 1; 569178525Sjb else 570178525Sjb rval = 0; 571178525Sjb 572178525Sjb if (lfp == rfp) 573178525Sjb return (rval); 574178525Sjb 575178525Sjb if (CTF_TYPE_ISPARENT(ltype) && lfp->ctf_parent != NULL) 576178525Sjb lfp = lfp->ctf_parent; 577178525Sjb 578178525Sjb if (CTF_TYPE_ISPARENT(rtype) && rfp->ctf_parent != NULL) 579178525Sjb rfp = rfp->ctf_parent; 580178525Sjb 581178525Sjb if (lfp < rfp) 582178525Sjb return (-1); 583178525Sjb 584178525Sjb if (lfp > rfp) 585178525Sjb return (1); 586178525Sjb 587178525Sjb return (rval); 588178525Sjb} 589178525Sjb 590178525Sjb/* 591178525Sjb * Return a boolean value indicating if two types are compatible integers or 592178525Sjb * floating-pointer values. This function returns true if the two types are 593178525Sjb * the same, or if they have the same ASCII name and encoding properties. 594178525Sjb * This function could be extended to test for compatibility for other kinds. 595178525Sjb */ 596178525Sjbint 597178525Sjbctf_type_compat(ctf_file_t *lfp, ctf_id_t ltype, 598178525Sjb ctf_file_t *rfp, ctf_id_t rtype) 599178525Sjb{ 600178525Sjb const ctf_type_t *ltp, *rtp; 601178525Sjb ctf_encoding_t le, re; 602178525Sjb ctf_arinfo_t la, ra; 603178525Sjb uint_t lkind, rkind; 604178525Sjb 605178525Sjb if (ctf_type_cmp(lfp, ltype, rfp, rtype) == 0) 606178525Sjb return (1); 607178525Sjb 608178525Sjb ltype = ctf_type_resolve(lfp, ltype); 609178525Sjb lkind = ctf_type_kind(lfp, ltype); 610178525Sjb 611178525Sjb rtype = ctf_type_resolve(rfp, rtype); 612178525Sjb rkind = ctf_type_kind(rfp, rtype); 613178525Sjb 614178525Sjb if (lkind != rkind || 615178525Sjb (ltp = ctf_lookup_by_id(&lfp, ltype)) == NULL || 616178525Sjb (rtp = ctf_lookup_by_id(&rfp, rtype)) == NULL || 617178525Sjb strcmp(ctf_strptr(lfp, ltp->ctt_name), 618178525Sjb ctf_strptr(rfp, rtp->ctt_name)) != 0) 619178525Sjb return (0); 620178525Sjb 621178525Sjb switch (lkind) { 622178525Sjb case CTF_K_INTEGER: 623178525Sjb case CTF_K_FLOAT: 624178525Sjb return (ctf_type_encoding(lfp, ltype, &le) == 0 && 625178525Sjb ctf_type_encoding(rfp, rtype, &re) == 0 && 626178525Sjb bcmp(&le, &re, sizeof (ctf_encoding_t)) == 0); 627178525Sjb case CTF_K_POINTER: 628178525Sjb return (ctf_type_compat(lfp, ctf_type_reference(lfp, ltype), 629178525Sjb rfp, ctf_type_reference(rfp, rtype))); 630178525Sjb case CTF_K_ARRAY: 631178525Sjb return (ctf_array_info(lfp, ltype, &la) == 0 && 632178525Sjb ctf_array_info(rfp, rtype, &ra) == 0 && 633178525Sjb la.ctr_nelems == ra.ctr_nelems && ctf_type_compat( 634178525Sjb lfp, la.ctr_contents, rfp, ra.ctr_contents) && 635178525Sjb ctf_type_compat(lfp, la.ctr_index, rfp, ra.ctr_index)); 636178525Sjb case CTF_K_STRUCT: 637178525Sjb case CTF_K_UNION: 638178525Sjb return (ctf_type_size(lfp, ltype) == ctf_type_size(rfp, rtype)); 639178525Sjb case CTF_K_ENUM: 640178525Sjb case CTF_K_FORWARD: 641178525Sjb return (1); /* no other checks required for these type kinds */ 642178525Sjb default: 643178525Sjb return (0); /* should not get here since we did a resolve */ 644178525Sjb } 645178525Sjb} 646178525Sjb 647313129Smarkjstatic int 648313129Smarkj_ctf_member_info(ctf_file_t *fp, ctf_id_t type, const char *name, ulong_t off, 649178525Sjb ctf_membinfo_t *mip) 650178525Sjb{ 651178525Sjb ctf_file_t *ofp = fp; 652178525Sjb const ctf_type_t *tp; 653178525Sjb ssize_t size, increment; 654178525Sjb uint_t kind, n; 655178525Sjb 656178525Sjb if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) 657178525Sjb return (CTF_ERR); /* errno is set for us */ 658178525Sjb 659178525Sjb if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) 660178525Sjb return (CTF_ERR); /* errno is set for us */ 661178525Sjb 662178525Sjb (void) ctf_get_ctt_size(fp, tp, &size, &increment); 663178525Sjb kind = LCTF_INFO_KIND(fp, tp->ctt_info); 664178525Sjb 665178525Sjb if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) 666178525Sjb return (ctf_set_errno(ofp, ECTF_NOTSOU)); 667178525Sjb 668178525Sjb if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) { 669178525Sjb const ctf_member_t *mp = (const ctf_member_t *) 670178525Sjb ((uintptr_t)tp + increment); 671178525Sjb 672178525Sjb for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) { 673313129Smarkj if (mp->ctm_name == 0 && 674313129Smarkj _ctf_member_info(fp, mp->ctm_type, name, 675313129Smarkj mp->ctm_offset + off, mip) == 0) 676313129Smarkj return (0); 677178525Sjb if (strcmp(ctf_strptr(fp, mp->ctm_name), name) == 0) { 678178525Sjb mip->ctm_type = mp->ctm_type; 679313129Smarkj mip->ctm_offset = mp->ctm_offset + off; 680178525Sjb return (0); 681178525Sjb } 682178525Sjb } 683178525Sjb } else { 684178525Sjb const ctf_lmember_t *lmp = (const ctf_lmember_t *) 685178525Sjb ((uintptr_t)tp + increment); 686178525Sjb 687178525Sjb for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) { 688313129Smarkj if (lmp->ctlm_name == 0 && 689313129Smarkj _ctf_member_info(fp, lmp->ctlm_name, name, 690313129Smarkj (ulong_t)CTF_LMEM_OFFSET(lmp) + off, mip) == 0) 691313129Smarkj return (0); 692178525Sjb if (strcmp(ctf_strptr(fp, lmp->ctlm_name), name) == 0) { 693178525Sjb mip->ctm_type = lmp->ctlm_type; 694313129Smarkj mip->ctm_offset = 695313129Smarkj (ulong_t)CTF_LMEM_OFFSET(lmp) + off; 696178525Sjb return (0); 697178525Sjb } 698178525Sjb } 699178525Sjb } 700178525Sjb 701178525Sjb return (ctf_set_errno(ofp, ECTF_NOMEMBNAM)); 702178525Sjb} 703178525Sjb 704178525Sjb/* 705313129Smarkj * Return the type and offset for a given member of a STRUCT or UNION. 706313129Smarkj */ 707313129Smarkjint 708313129Smarkjctf_member_info(ctf_file_t *fp, ctf_id_t type, const char *name, 709313129Smarkj ctf_membinfo_t *mip) 710313129Smarkj{ 711313129Smarkj 712313129Smarkj return (_ctf_member_info(fp, type, name, 0, mip)); 713313129Smarkj} 714313129Smarkj 715313129Smarkj/* 716178525Sjb * Return the array type, index, and size information for the specified ARRAY. 717178525Sjb */ 718178525Sjbint 719178525Sjbctf_array_info(ctf_file_t *fp, ctf_id_t type, ctf_arinfo_t *arp) 720178525Sjb{ 721178525Sjb ctf_file_t *ofp = fp; 722178525Sjb const ctf_type_t *tp; 723178525Sjb const ctf_array_t *ap; 724178525Sjb ssize_t increment; 725178525Sjb 726178525Sjb if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) 727178525Sjb return (CTF_ERR); /* errno is set for us */ 728178525Sjb 729178525Sjb if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ARRAY) 730178525Sjb return (ctf_set_errno(ofp, ECTF_NOTARRAY)); 731178525Sjb 732178525Sjb (void) ctf_get_ctt_size(fp, tp, NULL, &increment); 733178525Sjb 734178525Sjb ap = (const ctf_array_t *)((uintptr_t)tp + increment); 735178525Sjb arp->ctr_contents = ap->cta_contents; 736178525Sjb arp->ctr_index = ap->cta_index; 737178525Sjb arp->ctr_nelems = ap->cta_nelems; 738178525Sjb 739178525Sjb return (0); 740178525Sjb} 741178525Sjb 742178525Sjb/* 743178525Sjb * Convert the specified value to the corresponding enum member name, if a 744178525Sjb * matching name can be found. Otherwise NULL is returned. 745178525Sjb */ 746178525Sjbconst char * 747178525Sjbctf_enum_name(ctf_file_t *fp, ctf_id_t type, int value) 748178525Sjb{ 749178525Sjb ctf_file_t *ofp = fp; 750178525Sjb const ctf_type_t *tp; 751178525Sjb const ctf_enum_t *ep; 752178525Sjb ssize_t increment; 753178525Sjb uint_t n; 754178525Sjb 755178525Sjb if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) 756178525Sjb return (NULL); /* errno is set for us */ 757178525Sjb 758178525Sjb if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) 759178525Sjb return (NULL); /* errno is set for us */ 760178525Sjb 761178525Sjb if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) { 762178525Sjb (void) ctf_set_errno(ofp, ECTF_NOTENUM); 763178525Sjb return (NULL); 764178525Sjb } 765178525Sjb 766178525Sjb (void) ctf_get_ctt_size(fp, tp, NULL, &increment); 767178525Sjb 768178525Sjb ep = (const ctf_enum_t *)((uintptr_t)tp + increment); 769178525Sjb 770178525Sjb for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) { 771178525Sjb if (ep->cte_value == value) 772178525Sjb return (ctf_strptr(fp, ep->cte_name)); 773178525Sjb } 774178525Sjb 775178525Sjb (void) ctf_set_errno(ofp, ECTF_NOENUMNAM); 776178525Sjb return (NULL); 777178525Sjb} 778178525Sjb 779178525Sjb/* 780178525Sjb * Convert the specified enum tag name to the corresponding value, if a 781178525Sjb * matching name can be found. Otherwise CTF_ERR is returned. 782178525Sjb */ 783178525Sjbint 784178525Sjbctf_enum_value(ctf_file_t *fp, ctf_id_t type, const char *name, int *valp) 785178525Sjb{ 786178525Sjb ctf_file_t *ofp = fp; 787178525Sjb const ctf_type_t *tp; 788178525Sjb const ctf_enum_t *ep; 789178525Sjb ssize_t size, increment; 790178525Sjb uint_t n; 791178525Sjb 792178525Sjb if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) 793178525Sjb return (CTF_ERR); /* errno is set for us */ 794178525Sjb 795178525Sjb if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) 796178525Sjb return (CTF_ERR); /* errno is set for us */ 797178525Sjb 798178525Sjb if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) { 799178525Sjb (void) ctf_set_errno(ofp, ECTF_NOTENUM); 800178525Sjb return (CTF_ERR); 801178525Sjb } 802178525Sjb 803178525Sjb (void) ctf_get_ctt_size(fp, tp, &size, &increment); 804178525Sjb 805178525Sjb ep = (const ctf_enum_t *)((uintptr_t)tp + increment); 806178525Sjb 807178525Sjb for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) { 808178525Sjb if (strcmp(ctf_strptr(fp, ep->cte_name), name) == 0) { 809178525Sjb if (valp != NULL) 810178525Sjb *valp = ep->cte_value; 811178525Sjb return (0); 812178525Sjb } 813178525Sjb } 814178525Sjb 815178525Sjb (void) ctf_set_errno(ofp, ECTF_NOENUMNAM); 816178525Sjb return (CTF_ERR); 817178525Sjb} 818178525Sjb 819178525Sjb/* 820178525Sjb * Recursively visit the members of any type. This function is used as the 821178525Sjb * engine for ctf_type_visit, below. We resolve the input type, recursively 822178525Sjb * invoke ourself for each type member if the type is a struct or union, and 823178525Sjb * then invoke the callback function on the current type. If any callback 824178525Sjb * returns non-zero, we abort and percolate the error code back up to the top. 825178525Sjb */ 826178525Sjbstatic int 827178525Sjbctf_type_rvisit(ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg, 828178525Sjb const char *name, ulong_t offset, int depth) 829178525Sjb{ 830178525Sjb ctf_id_t otype = type; 831178525Sjb const ctf_type_t *tp; 832178525Sjb ssize_t size, increment; 833178525Sjb uint_t kind, n; 834178525Sjb int rc; 835178525Sjb 836178525Sjb if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) 837178525Sjb return (CTF_ERR); /* errno is set for us */ 838178525Sjb 839178525Sjb if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) 840178525Sjb return (CTF_ERR); /* errno is set for us */ 841178525Sjb 842178525Sjb if ((rc = func(name, otype, offset, depth, arg)) != 0) 843178525Sjb return (rc); 844178525Sjb 845178525Sjb kind = LCTF_INFO_KIND(fp, tp->ctt_info); 846178525Sjb 847178525Sjb if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) 848178525Sjb return (0); 849178525Sjb 850178525Sjb (void) ctf_get_ctt_size(fp, tp, &size, &increment); 851178525Sjb 852178525Sjb if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) { 853178525Sjb const ctf_member_t *mp = (const ctf_member_t *) 854178525Sjb ((uintptr_t)tp + increment); 855178525Sjb 856178525Sjb for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) { 857178525Sjb if ((rc = ctf_type_rvisit(fp, mp->ctm_type, 858178525Sjb func, arg, ctf_strptr(fp, mp->ctm_name), 859178525Sjb offset + mp->ctm_offset, depth + 1)) != 0) 860178525Sjb return (rc); 861178525Sjb } 862178525Sjb 863178525Sjb } else { 864178525Sjb const ctf_lmember_t *lmp = (const ctf_lmember_t *) 865178525Sjb ((uintptr_t)tp + increment); 866178525Sjb 867178525Sjb for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) { 868178525Sjb if ((rc = ctf_type_rvisit(fp, lmp->ctlm_type, 869178525Sjb func, arg, ctf_strptr(fp, lmp->ctlm_name), 870178525Sjb offset + (ulong_t)CTF_LMEM_OFFSET(lmp), 871178525Sjb depth + 1)) != 0) 872178525Sjb return (rc); 873178525Sjb } 874178525Sjb } 875178525Sjb 876178525Sjb return (0); 877178525Sjb} 878178525Sjb 879178525Sjb/* 880178525Sjb * Recursively visit the members of any type. We pass the name, member 881178525Sjb * type, and offset of each member to the specified callback function. 882178525Sjb */ 883178525Sjbint 884178525Sjbctf_type_visit(ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg) 885178525Sjb{ 886178525Sjb return (ctf_type_rvisit(fp, type, func, arg, "", 0, 0)); 887178525Sjb} 888