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