📄 ctf_types.c
字号:
/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident "@(#)ctf_types.c 1.6 03/09/02 SMI"#include <sys/sysmacros.h>#include <ctf_impl.h>ssize_tctf_get_ctt_size(const ctf_file_t *fp, const ctf_type_t *tp, ssize_t *sizep, ssize_t *incrementp){ ssize_t size, increment; if (fp->ctf_version > CTF_VERSION_1 && tp->ctt_size == CTF_LSIZE_SENT) { size = CTF_TYPE_LSIZE(tp); increment = sizeof (ctf_type_t); } else { size = tp->ctt_size; increment = sizeof (ctf_stype_t); } if (sizep) *sizep = size; if (incrementp) *incrementp = increment; return (size);}/* * Iterate over the members of a STRUCT or UNION. We pass the name, member * type, and offset of each member to the specified callback function. */intctf_member_iter(ctf_file_t *fp, ctf_id_t type, ctf_member_f *func, void *arg){ ctf_file_t *ofp = fp; const ctf_type_t *tp; ssize_t size, increment; uint_t kind, n; int rc; if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (CTF_ERR); /* errno is set for us */ (void) ctf_get_ctt_size(fp, tp, &size, &increment); kind = LCTF_INFO_KIND(fp, tp->ctt_info); if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) return (ctf_set_errno(ofp, ECTF_NOTSOU)); if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) { const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t)tp + increment); for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) { const char *name = ctf_strptr(fp, mp->ctm_name); if ((rc = func(name, mp->ctm_type, mp->ctm_offset, arg)) != 0) return (rc); } } else { const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t)tp + increment); for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) { const char *name = ctf_strptr(fp, lmp->ctlm_name); if ((rc = func(name, lmp->ctlm_type, (ulong_t)CTF_LMEM_OFFSET(lmp), arg)) != 0) return (rc); } } return (0);}/* * Iterate over the members of an ENUM. We pass the string name and associated * integer value of each enum element to the specified callback function. */intctf_enum_iter(ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg){ ctf_file_t *ofp = fp; const ctf_type_t *tp; const ctf_enum_t *ep; ssize_t increment; uint_t n; int rc; if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (CTF_ERR); /* errno is set for us */ if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) return (ctf_set_errno(ofp, ECTF_NOTENUM)); (void) ctf_get_ctt_size(fp, tp, NULL, &increment); ep = (const ctf_enum_t *)((uintptr_t)tp + increment); for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) { const char *name = ctf_strptr(fp, ep->cte_name); if ((rc = func(name, ep->cte_value, arg)) != 0) return (rc); } return (0);}/* * Iterate over every root (user-visible) type in the given CTF container. * We pass the type ID of each type to the specified callback function. */intctf_type_iter(ctf_file_t *fp, ctf_type_f *func, void *arg){ ctf_id_t id, max = fp->ctf_typemax; int rc, child = (fp->ctf_flags & LCTF_CHILD); for (id = 1; id <= max; id++) { const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR(fp, id); if (CTF_INFO_ISROOT(tp->ctt_info) && (rc = func(CTF_INDEX_TO_TYPE(id, child), arg)) != 0) return (rc); } return (0);}/* * Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and * RESTRICT nodes until we reach a "base" type node. This is useful when * we want to follow a type ID to a node that has members or a size. To guard * against infinite loops, we implement simplified cycle detection and check * each link against itself, the previous node, and the topmost node. */ctf_id_tctf_type_resolve(ctf_file_t *fp, ctf_id_t type){ ctf_id_t prev = type, otype = type; ctf_file_t *ofp = fp; const ctf_type_t *tp; while ((tp = ctf_lookup_by_id(&fp, type)) != NULL) { switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { case CTF_K_TYPEDEF: case CTF_K_VOLATILE: case CTF_K_CONST: case CTF_K_RESTRICT: if (tp->ctt_type == type || tp->ctt_type == otype || tp->ctt_type == prev) { ctf_dprintf("type %ld cycle detected\n", otype); return (ctf_set_errno(ofp, ECTF_CORRUPT)); } prev = type; type = tp->ctt_type; break; default: return (type); } } return (CTF_ERR); /* errno is set for us */}/* * Lookup the given type ID and print a string name for it into buf. If buf * is too small, an appropriate error will be returned to the caller. */char *ctf_type_name(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len){ ctf_file_t *ofp = fp; const ctf_type_t *tp; const ctf_array_t *ap; const char *name; char *p, *q; uint_t kind; ssize_t size, increment; int rlen; if (buf == NULL || len == 0) { (void) ctf_set_errno(ofp, EINVAL); return (NULL); } buf[0] = '\0'; /* start with empty string */ for (p = buf, q = buf + len; p < q; p += strlen(p)) { if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (NULL); /* errno is set for us */ len = (size_t)(q - p); /* bytes remaining in buf */ name = ctf_strptr(fp, tp->ctt_name); kind = LCTF_INFO_KIND(fp, tp->ctt_info); (void) ctf_get_ctt_size(fp, tp, &size, &increment); if (name[0] != '\0' && (kind == CTF_K_FUNCTION || kind == CTF_K_POINTER || kind == CTF_K_VOLATILE || kind == CTF_K_CONST || kind == CTF_K_RESTRICT)) { if (snprintf(p, len, "%s", name) >= len) goto out; return (buf); } switch (kind) { case CTF_K_TYPEDEF: if (name[0] == '\0') { type = tp->ctt_type; break; } /*FALLTHRU*/ case CTF_K_INTEGER: case CTF_K_FLOAT: if (snprintf(p, len, "%s", name) >= len) goto out; return (buf); case CTF_K_ARRAY: ap = (const ctf_array_t *)((uintptr_t)tp + increment); if (ctf_type_name(fp, ap->cta_contents, p, len) == NULL) return (NULL); /* errno is set for us */ p = buf + strlen(buf); len = (size_t)(q - p); if (snprintf(p, len, " [%u]", ap->cta_nelems) >= len) goto out; return (buf); case CTF_K_FUNCTION: case CTF_K_POINTER: if (ctf_type_name(fp, tp->ctt_type, p, len) == NULL) return (NULL); /* errno is set for us */ /* * We assume that all functions are really * pointers to functions. */ if (kind == CTF_K_POINTER && ctf_type_kind(fp, tp->ctt_type) == CTF_K_FUNCTION) return (buf); p = buf + strlen(buf); len = (size_t)(q - p); if (kind == CTF_K_FUNCTION) rlen = snprintf(p, len, " (*)()"); else if (ctf_type_kind(fp, tp->ctt_type) == CTF_K_POINTER) rlen = snprintf(p, len, "*"); else rlen = snprintf(p, len, " *"); if (rlen >= len) goto out; return (buf); case CTF_K_STRUCT: case CTF_K_FORWARD: if (snprintf(p, len, "struct %s", name) >= len) goto out; return (buf); case CTF_K_UNION: if (snprintf(p, len, "union %s", name) >= len) goto out; return (buf); case CTF_K_ENUM: if (snprintf(p, len, "enum %s", name) >= len) goto out; return (buf); case CTF_K_VOLATILE: if (snprintf(p, len, "volatile ") >= len) goto out; type = tp->ctt_type; break; case CTF_K_CONST: if (snprintf(p, len, "const ") >= len) goto out; type = tp->ctt_type; break; case CTF_K_RESTRICT: if (snprintf(p, len, "restrict ") >= len) goto out; type = tp->ctt_type; break; default: (void) ctf_set_errno(ofp, ECTF_CORRUPT); return (NULL); } }out: (void) ctf_set_errno(ofp, ECTF_NAMELEN); buf[0] = '\0'; return (NULL);}/* * Resolve the type down to a base type node, and then return the size * of the type storage in bytes. */ssize_tctf_type_size(ctf_file_t *fp, ctf_id_t type){ const ctf_type_t *tp; ssize_t size; ctf_arinfo_t ar; if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (-1); /* errno is set for us */ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (-1); /* errno is set for us */ switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { case CTF_K_POINTER: return (fp->ctf_dmodel->ctd_pointer); case CTF_K_FUNCTION: return (0); /* function size is only known by symtab */ case CTF_K_ENUM: return (fp->ctf_dmodel->ctd_int); case CTF_K_ARRAY: /* * Array size is not directly returned by stabs data. Instead, * it defines the element type and requires the user to perform * the multiplication. If ctf_get_ctt_size() returns zero, the * current version of ctfconvert does not compute member sizes * and we compute the size here on its behalf. */ if ((size = ctf_get_ctt_size(fp, tp, NULL, NULL)) > 0) return (size); if (ctf_array_info(fp, type, &ar) == CTF_ERR || (size = ctf_type_size(fp, ar.ctr_contents)) == CTF_ERR) return (-1); /* errno is set for us */ return (size * ar.ctr_nelems); default: return (ctf_get_ctt_size(fp, tp, NULL, NULL)); }}/* * Resolve the type down to a base type node, and then return the alignment * needed for the type storage in bytes. */ssize_tctf_type_align(ctf_file_t *fp, ctf_id_t type){ const ctf_type_t *tp; ctf_arinfo_t r; if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (-1); /* errno is set for us */ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (-1); /* errno is set for us */ switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { case CTF_K_POINTER: case CTF_K_FUNCTION: return (fp->ctf_dmodel->ctd_pointer); case CTF_K_ARRAY: if (ctf_array_info(fp, type, &r) == CTF_ERR) return (-1); /* errno is set for us */ return (ctf_type_align(fp, r.ctr_contents)); case CTF_K_STRUCT: case CTF_K_UNION: { uint_t n = LCTF_INFO_VLEN(fp, tp->ctt_info); ssize_t size, increment; size_t align = 0; const void *vmp; (void) ctf_get_ctt_size(fp, tp, &size, &increment); vmp = (uchar_t *)tp + increment; if (LCTF_INFO_KIND(fp, tp->ctt_info) == CTF_K_STRUCT) n = MIN(n, 1); /* only use first member for structs */ if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) { const ctf_member_t *mp = vmp; for (; n != 0; n--, mp++) { ssize_t am = ctf_type_align(fp, mp->ctm_type); align = MAX(align, am); } } else { const ctf_lmember_t *lmp = vmp; for (; n != 0; n--, lmp++) { ssize_t am = ctf_type_align(fp, lmp->ctlm_type); align = MAX(align, am); } } return (align); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -