static int type_equals(mdb_ctf_id_t a, mdb_ctf_id_t b) { size_t asz, bsz; int akind, bkind; mdb_ctf_arinfo_t aar, bar; /* * Resolve both types down to their fundamental types, and make * sure their sizes and kinds match. */ if (mdb_ctf_type_resolve(a, &a) != 0 || mdb_ctf_type_resolve(b, &b) != 0 || (asz = mdb_ctf_type_size(a)) == -1UL || (bsz = mdb_ctf_type_size(b)) == -1UL || (akind = mdb_ctf_type_kind(a)) == -1 || (bkind = mdb_ctf_type_kind(b)) == -1 || asz != bsz || akind != bkind) { return (0); } switch (akind) { case CTF_K_INTEGER: case CTF_K_FLOAT: case CTF_K_POINTER: /* * For pointers we could be a little stricter and require * both pointers to reference types which look vaguely * similar (for example, we could insist that the two types * have the same name). However, all we really care about * here is that the structure of the two types are the same, * and, in that regard, one pointer is as good as another. */ return (1); case CTF_K_UNION: case CTF_K_STRUCT: /* * The test for the number of members is only strictly * necessary for unions since we'll find other problems with * structs. However, the extra check will do no harm. */ return (mdb_ctf_num_members(a) == mdb_ctf_num_members(b) && mdb_ctf_member_iter(a, type_equals_cb, &b) == 0); case CTF_K_ARRAY: return (mdb_ctf_array_info(a, &aar) == 0 && mdb_ctf_array_info(b, &bar) == 0 && aar.mta_nelems == bar.mta_nelems && type_equals(aar.mta_index, bar.mta_index) && type_equals(aar.mta_contents, bar.mta_contents)); } return (0); }
static int ttrace_ttr_size_check(void) { mdb_ctf_id_t ttrtid; ssize_t ttr_size; if (mdb_ctf_lookup_by_name("trap_trace_rec_t", &ttrtid) != 0 || mdb_ctf_type_resolve(ttrtid, &ttrtid) != 0) { mdb_warn("failed to determine size of trap_trace_rec_t; " "non-TRAPTRACE kernel?\n"); return (0); } if ((ttr_size = mdb_ctf_type_size(ttrtid)) != sizeof (trap_trace_rec_t)) { /* * On Intel machines, this will happen when TTR_STACK_DEPTH * is changed. This code could be smarter, and could * dynamically adapt to different depths, but not until a * need for such adaptation is demonstrated. */ mdb_warn("size of trap_trace_rec_t (%d bytes) doesn't " "match expected %d\n", ttr_size, sizeof (trap_trace_rec_t)); return (0); } return (1); }
int mdb_ctf_enum_iter(mdb_ctf_id_t id, mdb_ctf_enum_f *cb, void *data) { mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id; int ret; /* resolve the type in case there's a forward declaration */ if ((ret = mdb_ctf_type_resolve(id, &id)) != 0) return (ret); return (ctf_enum_iter(idp->mci_fp, idp->mci_id, cb, data)); }
const char * mdb_ctf_enum_name(mdb_ctf_id_t id, int value) { mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id; const char *ret; /* resolve the type in case there's a forward declaration */ if (mdb_ctf_type_resolve(id, &id) != 0) return (NULL); if ((ret = ctf_enum_name(idp->mci_fp, idp->mci_id, value)) == NULL) (void) set_errno(ctf_to_errno(ctf_errno(idp->mci_fp))); return (ret); }
ssize_t mdb_ctf_type_size(mdb_ctf_id_t id) { mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id; ssize_t ret; /* resolve the type in case there's a forward declaration */ if ((ret = mdb_ctf_type_resolve(id, &id)) != 0) return (ret); if ((ret = ctf_type_size(idp->mci_fp, idp->mci_id)) == CTF_ERR) return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp)))); return (ret); }
/* * callback proxy for mdb_ctf_type_visit */ static int type_cb(const char *name, ctf_id_t type, ulong_t off, int depth, void *arg) { type_visit_t *tvp = arg; mdb_ctf_id_t id; mdb_ctf_id_t base; mdb_ctf_impl_t *basep = (mdb_ctf_impl_t *)&base; int ret; if (depth < tvp->tv_min_depth) return (0); off += tvp->tv_base_offset; depth += tvp->tv_base_depth; set_ctf_id(&id, tvp->tv_fp, type); (void) mdb_ctf_type_resolve(id, &base); if ((ret = tvp->tv_cb(name, id, base, off, depth, tvp->tv_arg)) != 0) return (ret); /* * If the type resolves to a type in a different file, we must have * followed a forward declaration. We need to recurse into the * new type. */ if (basep->mci_fp != tvp->tv_fp && mdb_ctf_type_valid(base)) { type_visit_t tv; tv.tv_cb = tvp->tv_cb; tv.tv_arg = tvp->tv_arg; tv.tv_fp = basep->mci_fp; tv.tv_base_offset = off; tv.tv_base_depth = depth; tv.tv_min_depth = 1; /* depth = 0 has already been done */ ret = ctf_type_visit(basep->mci_fp, basep->mci_id, type_cb, &tv); } return (ret); }
/* * This function takes a ctf id and determines whether or not the associated * type should be considered as a potential match for the given tab * completion command. We verify that the type itself is valid * for completion given the current context of the command, resolve * its actual name, and then pass it off to mdb_tab_insert to determine * if it's an actual match. */ static int tab_complete_type(mdb_ctf_id_t id, void *arg) { int rkind; char buf[MDB_SYM_NAMLEN]; mdb_ctf_id_t rid; mdb_tab_cookie_t *mcp = arg; uint_t flags = (uint_t)(uintptr_t)mcp->mtc_cba; /* * CTF data includes types that mdb commands don't understand. Before * we resolve the actual type prune any entry that is a type we * don't care about. */ switch (mdb_ctf_type_kind(id)) { case CTF_K_CONST: case CTF_K_RESTRICT: case CTF_K_VOLATILE: return (0); } if (mdb_ctf_type_resolve(id, &rid) != 0) return (1); rkind = mdb_ctf_type_kind(rid); if ((flags & MDB_TABC_MEMBERS) && rkind != CTF_K_STRUCT && rkind != CTF_K_UNION) return (0); if ((flags & MDB_TABC_NOPOINT) && rkind == CTF_K_POINTER) return (0); if ((flags & MDB_TABC_NOARRAY) && rkind == CTF_K_ARRAY) return (0); (void) mdb_ctf_type_name(id, buf, sizeof (buf)); mdb_tab_insert(mcp, buf); return (0); }
int mdb_ctf_member_iter(mdb_ctf_id_t id, mdb_ctf_member_f *cb, void *data) { mdb_ctf_impl_t *idp = (mdb_ctf_impl_t *)&id; member_iter_t mi; int ret; /* resolve the type in case there's a forward declaration */ if ((ret = mdb_ctf_type_resolve(id, &id)) != 0) return (ret); mi.mi_cb = cb; mi.mi_arg = data; mi.mi_fp = idp->mci_fp; ret = ctf_member_iter(idp->mci_fp, idp->mci_id, member_iter_cb, &mi); if (ret == CTF_ERR) return (set_errno(ctf_to_errno(ctf_errno(idp->mci_fp)))); return (ret); }
ssize_t mdb_ctf_offset_to_name(mdb_ctf_id_t id, ulong_t off, char *buf, size_t len, int dot, mdb_ctf_id_t *midp, ulong_t *moffp) { size_t size; size_t n; mbr_contains_t mbc; if (!mdb_ctf_type_valid(id)) return (set_errno(EINVAL)); /* * Quick sanity check to make sure the given offset is within * this scope of this type. */ if (mdb_ctf_type_size(id) * NBBY <= off) return (set_errno(EINVAL)); mbc.mbc_bufp = &buf; mbc.mbc_lenp = &len; mbc.mbc_offp = &off; mbc.mbc_idp = &id; mbc.mbc_total = 0; *buf = '\0'; for (;;) { /* * Check for an exact match. */ if (off == 0) break; (void) mdb_ctf_type_resolve(id, &id); /* * Find the member that contains this offset. */ switch (mdb_ctf_type_kind(id)) { case CTF_K_ARRAY: { mdb_ctf_arinfo_t ar; uint_t index; (void) mdb_ctf_array_info(id, &ar); size = mdb_ctf_type_size(ar.mta_contents) * NBBY; index = off / size; id = ar.mta_contents; off %= size; n = mdb_snprintf(buf, len, "[%u]", index); mbc.mbc_total += n; if (n > len) n = len; buf += n; len -= n; break; } case CTF_K_STRUCT: { int ret; /* * Find the member that contains this offset * and continue. */ if (dot) { mbc.mbc_total++; if (len != 0) { *buf++ = '.'; *buf = '\0'; len--; } } ret = mdb_ctf_member_iter(id, offset_to_name_cb, &mbc); if (ret == -1) return (-1); /* errno is set for us */ /* * If we did not find a member containing this offset * (due to holes in the structure), return EINVAL. */ if (ret == 0) return (set_errno(EINVAL)); break; } case CTF_K_UNION: /* * Treat unions like atomic entities since we can't * do more than guess which member of the union * might be the intended one. */ goto done; case CTF_K_INTEGER: case CTF_K_FLOAT: case CTF_K_POINTER: case CTF_K_ENUM: goto done; default: return (set_errno(EINVAL)); } dot = 1; } done: if (midp != NULL) *midp = id; if (moffp != NULL) *moffp = off; return (mbc.mbc_total); }
static int vread_helper(mdb_ctf_id_t modid, char *modbuf, mdb_ctf_id_t tgtid, char *tgtbuf, uint_t flags) { size_t modsz, tgtsz; int modkind, tgtkind; member_t mbr; int ret; mdb_ctf_arinfo_t tar, mar; int i; /* * Resolve the types to their canonical form. */ (void) mdb_ctf_type_resolve(modid, &modid); (void) mdb_ctf_type_resolve(tgtid, &tgtid); if ((modkind = mdb_ctf_type_kind(modid)) == -1) return (-1); /* errno is set for us */ if ((tgtkind = mdb_ctf_type_kind(tgtid)) == -1) return (-1); /* errno is set for us */ if (tgtkind != modkind) return (set_errno(EMDB_INCOMPAT)); switch (modkind) { case CTF_K_INTEGER: case CTF_K_FLOAT: case CTF_K_POINTER: if ((modsz = mdb_ctf_type_size(modid)) == -1UL) return (-1); /* errno is set for us */ if ((tgtsz = mdb_ctf_type_size(tgtid)) == -1UL) return (-1); /* errno is set for us */ /* * If the sizes don't match we need to be tricky to make * sure that the caller gets the correct data. */ if (modsz < tgtsz) { if (!(flags & MDB_CTF_VREAD_IGNORE_GROW)) return (set_errno(EMDB_INCOMPAT)); #ifdef _BIG_ENDIAN bcopy(tgtbuf + tgtsz - modsz, modbuf, modsz); #else bcopy(tgtbuf, modbuf, modsz); #endif } else if (modsz > tgtsz) { bzero(modbuf, modsz); #ifdef _BIG_ENDIAN bcopy(tgtbuf, modbuf + modsz - tgtsz, tgtsz); #else bcopy(tgtbuf, modbuf, tgtsz); #endif } else { bcopy(tgtbuf, modbuf, modsz); } return (0); case CTF_K_STRUCT: mbr.m_modbuf = modbuf; mbr.m_tgtbuf = tgtbuf; mbr.m_tgtid = tgtid; mbr.m_flags = flags; return (mdb_ctf_member_iter(modid, member_cb, &mbr)); case CTF_K_UNION: /* * Unions are a little tricky. The only time it's truly * safe to read in a union is if no part of the union or * any of its component types have changed. We allow the * consumer to ignore unions. The correct use of this * feature is to read the containing structure, figure * out which component of the union is valid, compute * the location of that in the target and then read in * that part of the structure. */ if (flags & MDB_CTF_VREAD_IGNORE_UNIONS) return (0); if (!type_equals(modid, tgtid)) return (set_errno(EMDB_INCOMPAT)); modsz = mdb_ctf_type_size(modid); tgtsz = mdb_ctf_type_size(tgtid); ASSERT(modsz == tgtsz); bcopy(tgtbuf, modbuf, modsz); return (0); case CTF_K_ARRAY: if (mdb_ctf_array_info(tgtid, &tar) != 0) return (-1); /* errno is set for us */ if (mdb_ctf_array_info(modid, &mar) != 0) return (-1); /* errno is set for us */ if (tar.mta_nelems != mar.mta_nelems) return (set_errno(EMDB_INCOMPAT)); if ((modsz = mdb_ctf_type_size(mar.mta_contents)) == -1UL) return (-1); /* errno is set for us */ if ((tgtsz = mdb_ctf_type_size(tar.mta_contents)) == -1UL) return (-1); /* errno is set for us */ for (i = 0; i < tar.mta_nelems; i++) { ret = vread_helper(mar.mta_contents, modbuf + i * modsz, tar.mta_contents, tgtbuf + i * tgtsz, flags); if (ret != 0) return (ret); } return (0); } return (set_errno(EMDB_INCOMPAT)); }