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); }
/* * 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); }
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)); }